浏览代码

Handle icon & qrcode upload failure gracefully

Bubka 2 年之前
父节点
当前提交
61d177aecd

+ 6 - 4
app/Api/v1/Controllers/IconController.php

@@ -22,11 +22,13 @@ class IconController extends Controller
         $this->validate($request, [
             'icon' => 'required|image',
         ]);
-        
-        $path = $request->file('icon')->store('', 'icons');
-        $response = array( "filename" => pathinfo($path)['basename']);
 
-        return response()->json($response, 201);
+        $icon = $request->file('icon');
+        $path = $icon instanceof \Illuminate\Http\UploadedFile ? $icon->store('', 'icons') : false;
+
+        return $path
+                ? response()->json(['filename' => pathinfo($path)['basename']], 201)
+                : response()->json(['message' => __('errors.file_upload_failed')], 500);
     }
 
 

+ 3 - 1
app/Api/v1/Controllers/QrCodeController.php

@@ -35,7 +35,9 @@ class QrCodeController extends Controller
     {
         $file = $request->file('qrcode');
 
-        return response()->json(['data' => QrCode::decode($file)], 200);
+        return $file instanceof \Illuminate\Http\UploadedFile
+            ? response()->json(['data' => QrCode::decode($file)], 200)
+            : response()->json(['message' => __('errors.file_upload_failed')], 500);
     }
     
 }

+ 1 - 1
resources/js/components/Form.js

@@ -213,7 +213,7 @@ class Form {
 
         return new Promise((resolve, reject) => {
             // (Form.axios || axios).request({ url: this.route(url), method, data, ...config })
-            Vue.axios.request({ url: this.route(url), method: 'post', data: formData, header: {'Content-Type' : 'multipart/form-data'} })
+            Vue.axios.request({ url: this.route(url), method: 'post', data: formData, header: {'Content-Type' : 'multipart/form-data'}, ...config })
                 .then(response => {
                     this.finishProcessing()
 

+ 10 - 7
resources/js/views/Start.vue

@@ -110,18 +110,21 @@
              * Upload the submitted QR code file to the backend for decoding, then route the user
              * to the Create or Import form with decoded URI to prefill the form
              */
-            async submitQrCode() {
+            submitQrCode() {
 
                 let imgdata = new FormData();
                 imgdata.append('qrcode', this.$refs.qrcodeInput.files[0]);
                 imgdata.append('inputFormat', 'fileUpload');
 
-                const { data } = await this.form.upload('/api/v1/qrcode/decode', imgdata)
-
-                if( data.data.slice(0, 33).toLowerCase() === "otpauth-migration://offline?data=" ) {
-                    this.$router.push({ name: 'importAccounts', params: { migrationUri: data.data } });
-                }
-                else this.$router.push({ name: 'createAccount', params: { decodedUri: data.data } });
+                this.form.upload('/api/v1/qrcode/decode', imgdata, {returnError: true}).then(response => {
+                    if( response.data.data.slice(0, 33).toLowerCase() === "otpauth-migration://offline?data=" ) {
+                        this.$router.push({ name: 'importAccounts', params: { migrationUri: response.data.data } });
+                    }
+                    else this.$router.push({ name: 'createAccount', params: { decodedUri: response.data.data } });
+                })
+                .catch(error => {
+                    this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
+                });
             },
 
             /**

+ 27 - 18
resources/js/views/twofaccounts/Create.vue

@@ -340,32 +340,38 @@
                 this.$router.push({name: 'accounts'});
             },
 
-            async uploadQrcode(event) {
+            uploadQrcode(event) {
 
                 let imgdata = new FormData();
                 imgdata.append('qrcode', this.$refs.qrcodeInput.files[0]);
                 imgdata.append('inputFormat', 'fileUpload');
 
                 // First we get the uri encoded in the qrcode
-                const { data } = await this.form.upload('/api/v1/qrcode/decode', imgdata)
-                this.uri = data.data
-
-                // Then the otp described by the uri
-                this.axios.post('/api/v1/twofaccounts/preview', { uri: data.data }).then(response => {
-                    this.form.fill(response.data)
-                    this.secretIsBase32Encoded = 1
-                    this.tempIcon = response.data.icon ? response.data.icon : null
+                this.form.upload('/api/v1/qrcode/decode', imgdata, {returnError: true}).then(response => {
+                    this.uri = response.data.data
+                    
+                    // Then the otp described by the uri
+                    this.axios.post('/api/v1/twofaccounts/preview', { uri: this.uri }).then(response => {
+                        this.form.fill(response.data)
+                        this.secretIsBase32Encoded = 1
+                        this.tempIcon = response.data.icon ? response.data.icon : null
+                    })
+                    .catch(error => {
+                        if( error.response.status === 422 ) {
+                            if( error.response.data.errors.uri ) {
+                                this.showAlternatives = true
+                            }
+                        }
+                    });
                 })
                 .catch(error => {
-                    if( error.response.status === 422 ) {
-                        if( error.response.data.errors.uri ) {
-                            this.showAlternatives = true
-                        }
-                    }
+                    this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
+                    return false
                 });
+
             },
 
-            async uploadIcon(event) {
+            uploadIcon(event) {
 
                 // clean possible already uploaded temp icon
                 this.deleteIcon()
@@ -373,9 +379,12 @@
                 let imgdata = new FormData();
                 imgdata.append('icon', this.$refs.iconInput.files[0]);
 
-                const { data } = await this.form.upload('/api/v1/icons', imgdata)
-
-                this.tempIcon = data.filename;
+                this.form.upload('/api/v1/icons', imgdata, {returnError: true}).then(response => {
+                    this.tempIcon = response.data.filename;
+                })
+                .catch(error => {
+                    this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
+                });
             },
 
             fetchLogo() {

+ 6 - 4
resources/js/views/twofaccounts/Edit.vue

@@ -265,10 +265,12 @@
                 let imgdata = new FormData();
                 imgdata.append('icon', this.$refs.iconInput.files[0]);
 
-                const { data } = await this.form.upload('/api/v1/icons', imgdata)
-
-                this.tempIcon = data.filename;
-
+                this.form.upload('/api/v1/icons', imgdata, {returnError: true}).then(response => {
+                    this.tempIcon = response.data.filename;
+                })
+                .catch(error => {
+                    this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
+                });
             },
 
             fetchLogo() {

+ 2 - 1
resources/lang/en/errors.php

@@ -41,5 +41,6 @@ return [
     'auth_proxy_failed_legend' => '2Fauth is configured to run behind an authentication proxy but your proxy does not return the expected header. Check your configuration and try again.',
     'invalid_google_auth_migration' => 'Invalid or unreadable Google Authenticator data',
     'unsupported_otp_type' => 'Unsupported OTP type',
-    'no_logo_found_for_x' => 'No logo available for {service}'
+    'no_logo_found_for_x' => 'No logo available for {service}',
+    'file_upload_failed' => 'File upload failed'
 ];