Rework the Delete feature to support batch-delete

This commit is contained in:
Bubka 2020-01-31 23:05:06 +01:00
parent dec0831f14
commit 7eac209724
4 changed files with 77 additions and 29 deletions

View File

@ -147,18 +147,27 @@ public function update(Request $request, $id)
* @param \App\TwoFAccount $twofaccount * @param \App\TwoFAccount $twofaccount
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy($id) public function destroy(TwoFAccount $twofaccount)
{ {
$twofaccount = TwoFAccount::FindOrFail($id);
// delete icon
Storage::delete('public/icons/' . $twofaccount->icon);
// delete account
$twofaccount->delete(); $twofaccount->delete();
return response()->json(null, 204); return response()->json(null, 204);
} }
/**
* Remove the specified resources from storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function batchDestroy(Request $request)
{
$ids = $request->all();
TwoFAccount::destroy($ids);
return response()->json(null, 204);
}
} }

View File

@ -34,6 +34,21 @@ class TwoFAccount extends Model
protected $appends = ['type', 'counter']; protected $appends = ['type', 'counter'];
/**
* Override The "booting" method of the model
*
* @return void
*/
protected static function boot()
{
parent::boot();
static::deleted(function ($model) {
Storage::delete('public/icons/' . $model->icon);
});
}
/** /**
* Null empty icon resource has gone * Null empty icon resource has gone
* *

View File

@ -6,7 +6,7 @@
<div class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd"> <div class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
<!-- toolbar --> <!-- toolbar -->
<div class="toolbar has-text-centered" v-if="editMode"> <div class="toolbar has-text-centered" v-if="editMode">
<a class="button is-text has-text-grey"> <a class="button" :class="{ 'is-dark': selectedAccounts.length === 0, 'is-danger': selectedAccounts.length > 0 }" :disabled="selectedAccounts.length == 0" @click="destroyAccounts">
<span class="icon is-small"> <span class="icon is-small">
<font-awesome-icon :icon="['fas', 'trash']" /> <font-awesome-icon :icon="['fas', 'trash']" />
</span> </span>
@ -31,7 +31,7 @@
<div class="tfa-container"> <div class="tfa-container">
<div class="tfa-checkbox" v-if="editMode"> <div class="tfa-checkbox" v-if="editMode">
<div class="field"> <div class="field">
<input class="is-checkradio is-small is-white" :id="'ckb_' + account.id" type="checkbox" :name="'ckb_' + account.id"> <input class="is-checkradio is-small is-white" :id="'ckb_' + account.id" :value="account" type="checkbox" :name="'ckb_' + account.id" v-model="selectedAccounts">
<label :for="'ckb_' + account.id"></label> <label :for="'ckb_' + account.id"></label>
</div> </div>
</div> </div>
@ -103,12 +103,13 @@
data(){ data(){
return { return {
accounts : [], accounts : [],
selectedAccounts: [],
ShowTwofaccountInModal : false, ShowTwofaccountInModal : false,
search: '', search: '',
username : null, username : null,
editMode: this.InitialEditMode, editMode: this.InitialEditMode,
showAccounts: null, showAccounts: null,
showNoAccount: null showNoAccount: null,
} }
}, },
@ -119,7 +120,7 @@
return item.service.toLowerCase().includes(this.search.toLowerCase()) || item.account.toLowerCase().includes(this.search.toLowerCase()); return item.service.toLowerCase().includes(this.search.toLowerCase()) || item.account.toLowerCase().includes(this.search.toLowerCase());
} }
); );
} },
}, },
@ -128,20 +129,7 @@
created() { created() {
this.username = localStorage.getItem('user') this.username = localStorage.getItem('user')
this.fetchAccounts()
this.axios.get('api/twofaccounts').then(response => {
response.data.forEach((data) => {
this.accounts.push({
id : data.id,
service : data.service,
account : data.account ? data.account : '-',
icon : data.icon
})
})
this.showAccounts = this.accounts.length > 0 ? true : false
this.showNoAccount = !this.showAccounts
})
// stop OTP generation on modal close // stop OTP generation on modal close
this.$on('modalClose', function() { this.$on('modalClose', function() {
@ -157,8 +145,27 @@
}, },
methods: { methods: {
showAccount(id) {
fetchAccounts() {
this.accounts = []
this.selectedAccounts = []
this.axios.get('api/twofaccounts').then(response => {
response.data.forEach((data) => {
this.accounts.push({
id : data.id,
service : data.service,
account : data.account ? data.account : '-',
icon : data.icon
})
})
this.showAccounts = this.accounts.length > 0 ? true : false
this.showNoAccount = !this.showAccounts
})
},
showAccount(id) {
if( id ) { if( id ) {
this.$refs.TwofaccountShow.getAccount(id) this.$refs.TwofaccountShow.getAccount(id)
} }
@ -170,15 +177,31 @@
deleteAccount: function (id) { deleteAccount: function (id) {
if(confirm(this.$t('twofaccounts.confirm.delete'))) { if(confirm(this.$t('twofaccounts.confirm.delete'))) {
this.axios.delete('/api/twofaccounts/' + id) this.axios.delete('/api/twofaccounts/' + id)
this.accounts.splice(this.accounts.findIndex(x => x.id === id), 1); // Remove the deleted account from the collection
this.accounts = this.accounts.filter(a => a.id !== id)
this.showAccounts = this.accounts.length > 0 ? true : false this.showAccounts = this.accounts.length > 0 ? true : false
this.showNoAccount = !this.showAccounts this.showNoAccount = !this.showAccounts
} }
}, },
async destroyAccounts() {
if(confirm(this.$t('twofaccounts.confirm.delete'))) {
let ids = []
this.selectedAccounts.forEach(account => ids.push(account.id))
// Backend will delete all accounts at the same time
await this.axios.delete('/api/twofaccounts/batch', {data: ids} )
// we fetch the accounts again to prevent the js collection being
// desynchronize from the backend php collection
this.fetchAccounts()
}
},
async logout(evt) { async logout(evt) {
if(confirm(this.$t('auth.confirm.logout'))) { if(confirm(this.$t('auth.confirm.logout'))) {

View File

@ -31,6 +31,7 @@
Route::patch('user', 'UserController@update'); Route::patch('user', 'UserController@update');
Route::get('user', 'UserController@getDetails'); Route::get('user', 'UserController@getDetails');
Route::delete('twofaccounts/batch', 'TwoFAccountController@batchDestroy');
Route::apiResource('twofaccounts', 'TwoFAccountController'); Route::apiResource('twofaccounts', 'TwoFAccountController');
Route::get('twofaccounts/{twofaccount}/otp', 'TwoFAccountController@generateOTP')->name('twofaccounts.generateOTP'); Route::get('twofaccounts/{twofaccount}/otp', 'TwoFAccountController@generateOTP')->name('twofaccounts.generateOTP');
Route::post('qrcode/decode', 'QrCodeController@decode'); Route::post('qrcode/decode', 'QrCodeController@decode');