mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-03-27 06:46:45 +01:00
Add export feature to the Edit mode - Complete #100
This commit is contained in:
parent
2d706e61b7
commit
88195a6afb
@ -10,6 +10,7 @@
|
||||
use App\Api\v1\Requests\TwoFAccountUpdateRequest;
|
||||
use App\Api\v1\Requests\TwoFAccountUriRequest;
|
||||
use App\Api\v1\Resources\TwoFAccountCollection;
|
||||
use App\Api\v1\Resources\TwoFAccountExportCollection;
|
||||
use App\Api\v1\Resources\TwoFAccountReadResource;
|
||||
use App\Api\v1\Resources\TwoFAccountStoreResource;
|
||||
use App\Facades\Groups;
|
||||
@ -70,8 +71,8 @@ public function store(TwoFAccountDynamicRequest $request)
|
||||
Groups::assign($twofaccount->id);
|
||||
|
||||
return (new TwoFAccountReadResource($twofaccount->refresh()))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,8 +90,8 @@ public function update(TwoFAccountUpdateRequest $request, TwoFAccount $twofaccou
|
||||
$twofaccount->save();
|
||||
|
||||
return (new TwoFAccountReadResource($twofaccount))
|
||||
->response()
|
||||
->setStatusCode(200);
|
||||
->response()
|
||||
->setStatusCode(200);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,6 +144,26 @@ public function preview(TwoFAccountUriRequest $request)
|
||||
return new TwoFAccountStoreResource($twofaccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export accounts
|
||||
*
|
||||
* @param \App\Api\v1\Requests\TwoFAccountBatchRequest $request
|
||||
* @return TwoFAccountExportCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function export(TwoFAccountBatchRequest $request)
|
||||
{
|
||||
$validated = $request->validated();
|
||||
|
||||
if ($this->tooManyIds($validated['ids'])) {
|
||||
return response()->json([
|
||||
'message' => 'bad request',
|
||||
'reason' => [__('errors.too_many_ids')],
|
||||
], 400);
|
||||
}
|
||||
|
||||
return new TwoFAccountExportCollection(TwoFAccounts::export($validated['ids']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a One-Time Password
|
||||
*
|
||||
|
26
app/Api/v1/Resources/TwoFAccountExportCollection.php
Normal file
26
app/Api/v1/Resources/TwoFAccountExportCollection.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\v1\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class TwoFAccountExportCollection extends ResourceCollection
|
||||
{
|
||||
/**
|
||||
* The resource that this resource collects.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $collects = TwoFAccountExportResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Support\Collection<int|string, TwoFAccountExportResource>
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return $this->collection;
|
||||
}
|
||||
}
|
46
app/Api/v1/Resources/TwoFAccountExportResource.php
Normal file
46
app/Api/v1/Resources/TwoFAccountExportResource.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\v1\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* @property mixed $otp_type
|
||||
* @property string $account
|
||||
* @property string $service
|
||||
* @property string|null $icon
|
||||
* @property string|null $icon_file
|
||||
* @property string $secret
|
||||
* @property int $digits
|
||||
* @property string $algorithm
|
||||
* @property int|null $period
|
||||
* @property int|null $counter
|
||||
* @property string $legacy_uri
|
||||
*/
|
||||
class TwoFAccountExportResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'otp_type' => $this->otp_type,
|
||||
'account' => $this->account,
|
||||
'service' => $this->service,
|
||||
'icon' => $this->icon,
|
||||
'icon_mime' => $this->icon ? Storage::disk('icons')->mimeType((string) $this->icon) : null,
|
||||
'icon_file' => $this->icon ? base64_encode(Storage::disk('icons')->get((string) $this->icon)) : null,
|
||||
'secret' => $this->secret,
|
||||
'digits' => (int) $this->digits,
|
||||
'algorithm' => $this->algorithm,
|
||||
'period' => is_null($this->period) ? null : (int) $this->period,
|
||||
'counter' => is_null($this->counter) ? null : (int) $this->counter,
|
||||
'legacy_uri' => $this->legacy_uri,
|
||||
];
|
||||
}
|
||||
}
|
@ -58,6 +58,20 @@ public function migrate(string $migrationPayload) : Collection
|
||||
return self::markAsDuplicate($twofaccounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export one or more twofaccounts
|
||||
*
|
||||
* @param int|array|string $ids twofaccount ids to delete
|
||||
* @return \Illuminate\Support\Collection<int, TwoFAccount> The converted accounts
|
||||
*/
|
||||
public static function export($ids) : Collection
|
||||
{
|
||||
$ids = self::commaSeparatedToArray($ids);
|
||||
$twofaccounts = TwoFAccount::whereIn('id', $ids)->get();
|
||||
|
||||
return $twofaccounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one or more twofaccounts
|
||||
*
|
||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"bulma": "^0.9.3",
|
||||
"bulma-checkradio": "^2.1.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"object-equals": "^0.3.0",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.14",
|
||||
@ -4696,6 +4697,11 @@
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"node_modules/file-type": {
|
||||
"version": "12.4.2",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
|
||||
@ -13330,6 +13336,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"file-type": {
|
||||
"version": "12.4.2",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"bulma": "^0.9.3",
|
||||
"bulma-checkradio": "^2.1.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"object-equals": "^0.3.0",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.14",
|
||||
|
8
resources/js/packages/fontawesome.js
vendored
8
resources/js/packages/fontawesome.js
vendored
@ -1,4 +1,4 @@
|
||||
import Vue from 'vue'
|
||||
import Vue from 'vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
@ -37,7 +37,8 @@ import {
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faExternalLinkAlt,
|
||||
faCamera
|
||||
faCamera,
|
||||
faFileDownload
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import {
|
||||
@ -79,7 +80,8 @@ library.add(
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faExternalLinkAlt,
|
||||
faCamera
|
||||
faCamera,
|
||||
faFileDownload
|
||||
);
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
@ -99,20 +99,23 @@
|
||||
<div v-if="selectedAccounts.length > 0" class="control">
|
||||
<div tabindex="0" role="button" class="tag-button tag-button-link tags are-medium has-addons is-clickable" @click="showGroupSelector = true" @keyup.enter="showGroupSelector = true">
|
||||
<span class="tag is-dark mb-0">
|
||||
{{ $t('groups.change_group') }}
|
||||
</span>
|
||||
<span class="tag is-link mb-0">
|
||||
{{ $t('groups.change_group') }}
|
||||
<font-awesome-icon :icon="['fas', 'layer-group']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- export selected button -->
|
||||
<div v-if="selectedAccounts.length > 0" class="control">
|
||||
<div tabindex="0" role="button" class="tag-button tags are-medium has-addons is-clickable" @click="exportAccounts" @keyup.enter="exportAccounts">
|
||||
<span class="tag is-dark mb-0">
|
||||
<font-awesome-icon :icon="['fas', 'file-download']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- delete selected button -->
|
||||
<div v-if="selectedAccounts.length > 0" class="control">
|
||||
<div tabindex="0" role="button" class="tag-button tag-button-danger tags are-medium has-addons is-clickable" @click="destroyAccounts" @keyup.enter="destroyAccounts">
|
||||
<span class="tag is-dark mb-0">
|
||||
{{ $t('commons.delete') }}
|
||||
</span>
|
||||
<span class="tag is-danger mb-0">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" />
|
||||
</span>
|
||||
</div>
|
||||
@ -272,6 +275,7 @@
|
||||
import draggable from 'vuedraggable'
|
||||
import Form from './../components/Form'
|
||||
import objectEquals from 'object-equals'
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
export default {
|
||||
data(){
|
||||
@ -485,6 +489,20 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Export selected accounts
|
||||
*/
|
||||
exportAccounts() {
|
||||
let ids = []
|
||||
this.selectedAccounts.forEach(id => ids.push(id))
|
||||
|
||||
this.axios.get('/api/v1/twofaccounts/export?ids=' + ids.join(), {responseType: 'blob'})
|
||||
.then((response) => {
|
||||
var blob = new Blob([response.data], {type: "application/json;charset=utf-8"});
|
||||
saveAs.saveAs(blob, "2fauth_export.json");
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Move accounts selected from the Edit mode to another group or withdraw them
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@
|
||||
Route::post('twofaccounts/reorder', [TwoFAccountController::class, 'reorder'])->name('twofaccounts.reorder');
|
||||
Route::post('twofaccounts/migration', [TwoFAccountController::class, 'migrate'])->name('twofaccounts.migrate');
|
||||
Route::post('twofaccounts/preview', [TwoFAccountController::class, 'preview'])->name('twofaccounts.preview');
|
||||
Route::get('twofaccounts/export', [TwoFAccountController::class, 'export'])->name('twofaccounts.export');
|
||||
Route::get('twofaccounts/{twofaccount}/qrcode', [QrCodeController::class, 'show'])->name('twofaccounts.show.qrcode');
|
||||
Route::get('twofaccounts/count', [TwoFAccountController::class, 'count'])->name('twofaccounts.count');
|
||||
Route::get('twofaccounts/{id}/otp', [TwoFAccountController::class, 'otp'])->where('id', '[0-9]+')->name('twofaccounts.show.otp');
|
||||
|
Loading…
Reference in New Issue
Block a user