From f5f3b5d9b36af6d649197cd564beeb27d88704eb Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Wed, 28 Apr 2021 19:42:57 +0200 Subject: [PATCH] Refactor API texts handling --- frontend/src/api/api-utils.js | 79 +++++++++---------- frontend/src/api/backup.js | 16 +++- frontend/src/api/category.js | 36 ++++++--- frontend/src/api/groups.js | 48 ++++++++--- frontend/src/api/mealplan.js | 30 ++++--- frontend/src/api/migration.js | 8 +- frontend/src/api/recipe.js | 58 ++++++++++---- frontend/src/api/signUps.js | 12 ++- frontend/src/api/siteSettings.js | 43 ++++++++-- frontend/src/api/themes.js | 24 ++++-- frontend/src/api/upload.js | 15 ++-- frontend/src/api/users.js | 58 +++++++++++--- frontend/src/components/Login/SignUpForm.vue | 7 +- .../components/MealPlan/MealPlanEditor.vue | 6 +- .../src/components/MealPlan/MealPlanNew.vue | 14 ++-- .../Recipe/RecipeEditor/ImageUploadBtn.vue | 9 +-- .../components/UI/Buttons/TheUploadBtn.vue | 10 +-- frontend/src/components/UI/TheRecipeFab.vue | 18 ++--- frontend/src/locales/messages/en-US.json | 16 +++- .../Admin/Backup/AvailableBackupCard.vue | 20 +++-- .../src/pages/Admin/Backup/NewBackupCard.vue | 9 +-- .../src/pages/Admin/ManageUsers/GroupCard.vue | 22 +----- .../Admin/ManageUsers/GroupDashboard.vue | 9 +-- .../Admin/ManageUsers/TheSignUpTable.vue | 9 +-- .../pages/Admin/ManageUsers/TheUserTable.vue | 35 ++------ .../src/pages/Admin/MealPlanner/index.vue | 7 +- .../pages/Admin/Migration/MigrationCard.vue | 7 +- frontend/src/pages/Admin/Profile/index.vue | 12 +-- .../pages/Admin/Settings/CreatePageDialog.vue | 12 +-- .../Admin/Settings/CustomPageCreator.vue | 7 +- 30 files changed, 366 insertions(+), 290 deletions(-) diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js index c8aff9f09..bcecda36f 100644 --- a/frontend/src/api/api-utils.js +++ b/frontend/src/api/api-utils.js @@ -1,56 +1,55 @@ const baseURL = "/api/"; import axios from "axios"; import { store } from "../store"; +import utils from "@/utils"; axios.defaults.headers.common[ "Authorization" ] = `Bearer ${store.getters.getToken}`; +function handleError(error, getText) { + utils.notify.error(getText(error.response)); + return false; +} +function handleResponse(response, getText) { + if(response && getText) { + const successText = getText(response); + utils.notify.success(successText); + } + return response; +} + +function defaultErrorText(response) { + return response.statusText; +} + +function defaultSuccessText(response) { + return response.statusText; +} + const apiReq = { - post: async function(url, data) { - let response = await axios.post(url, data).catch(function(error) { - if (error.response) { - return error.response; - } - }); - return response; + post: async function(url, data, getErrorText = defaultErrorText, getSuccessText) { + const response = await axios.post(url, data).catch(function(error) { handleError(error, getErrorText) }); + return handleResponse(response, getSuccessText); + }, + + put: async function(url, data, getErrorText = defaultErrorText, getSuccessText) { + const response = await axios.put(url, data).catch(function(error) { handleError(error, getErrorText) }); + return handleResponse(response, getSuccessText); + }, + + patch: async function(url, data, getErrorText = defaultErrorText, getSuccessText) { + const response = await axios.patch(url, data).catch(function(error) { handleError(error, getErrorText) }); + return handleResponse(response, getSuccessText); }, - put: async function(url, data) { - let response = await axios.put(url, data).catch(function(error) { - if (error.response) { - return error.response; - } else return; - }); - return response; - }, - patch: async function(url, data) { - let response = await axios.patch(url, data).catch(function(error) { - if (error.response) { - processResponse(error.response); - return response; - } else return; - }); - processResponse(response); - return response; + get: function(url, data, getErrorText = defaultErrorText) { + return axios.get(url, data).catch(function(error) { handleError(error, getErrorText) }); }, - get: async function(url, data) { - let response = await axios.get(url, data).catch(function(error) { - if (error.response) { - return error.response; - } else return; - }); - return response; - }, - - delete: async function(url, data) { - let response = await axios.delete(url, data).catch(function(error) { - if (error.response) { - return error.response; - } - }); - return response; + delete: async function(url, data, getErrorText = defaultErrorText, getSuccessText = defaultSuccessText ) { + const response = await axios.delete(url, data).catch( function(error) { handleError(error, getErrorText) } ); + return handleResponse(response, getSuccessText); }, async download(url) { diff --git a/frontend/src/api/backup.js b/frontend/src/api/backup.js index f7932bcac..d95dd6d27 100644 --- a/frontend/src/api/backup.js +++ b/frontend/src/api/backup.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import { store } from "@/store"; +import i18n from '@/i18n.js'; const backupBase = baseURL + "backups/"; @@ -40,7 +41,12 @@ export const backupAPI = { * @param {string} fileName */ async delete(fileName) { - return await apiReq.delete(backupURLs.deleteBackup(fileName)); + return apiReq.delete( + backupURLs.deleteBackup(fileName), + null, + function() { return i18n.t('settings.backup.unable-to-delete-backup'); }, + function() { return i18n.t('settings.backup.backup-deleted'); } + ); }, /** * Creates a backup on the serve given a set of options @@ -48,8 +54,12 @@ export const backupAPI = { * @returns */ async create(options) { - let response = apiReq.post(backupURLs.createBackup, options); - return response; + return apiReq.post( + backupURLs.createBackup, + options, + function() { return i18n.t('settings.backup.error-creating-backup-see-log-file'); }, + function(response) { return i18n.t('settings.backup.backup-created-at-response-export_path', {path: response.data.export_path}); } + ); }, /** * Downloads a file from the server. I don't actually think this is used? diff --git a/frontend/src/api/category.js b/frontend/src/api/category.js index 676a4488a..e82ad5303 100644 --- a/frontend/src/api/category.js +++ b/frontend/src/api/category.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import { store } from "@/store"; +import i18n from '@/i18n.js'; const prefix = baseURL + "categories"; @@ -22,26 +23,41 @@ export const categoryAPI = { return response.data; }, async create(name) { - let response = await apiReq.post(categoryURLs.getAll, { name: name }); - store.dispatch("requestCategories"); - return response.data; + const response = await apiReq.post( + categoryURLs.getAll, + { name: name }, + function() { return i18n.t('settings.category-creation-failed'); }, + function() { return i18n.t('settings.category-created'); } + ); + if(response) { + store.dispatch("requestCategories"); + return response.data; + } }, async getRecipesInCategory(category) { let response = await apiReq.get(categoryURLs.getCategory(category)); return response.data; }, async update(name, newName, overrideRequest = false) { - let response = await apiReq.put(categoryURLs.updateCategory(name), { - name: newName, - }); - if (!overrideRequest) { + const response = await apiReq.put( + categoryURLs.updateCategory(name), + { name: newName }, + function() { return i18n.t('settings.category-update-failed'); }, + function() { return i18n.t('settings.category-updated'); } + ); + if (response && !overrideRequest) { store.dispatch("requestCategories"); + return response.data; } - return response.data; }, async delete(category, overrideRequest = false) { - let response = await apiReq.delete(categoryURLs.deleteCategory(category)); - if (!overrideRequest) { + const response = await apiReq.delete( + categoryURLs.deleteCategory(category), + null, + function() { return i18n.t('settings.category-deletion-failed'); }, + function() { return i18n.t('settings.category-deleted'); } + ); + if (response && !overrideRequest) { store.dispatch("requestCategories"); } return response; diff --git a/frontend/src/api/groups.js b/frontend/src/api/groups.js index bbb7fe8dc..c26e8021a 100644 --- a/frontend/src/api/groups.js +++ b/frontend/src/api/groups.js @@ -1,5 +1,6 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; +import i18n from '@/i18n.js'; const groupPrefix = baseURL + "groups"; const groupsURLs = { @@ -10,25 +11,54 @@ const groupsURLs = { update: id => `${groupPrefix}/${id}`, }; +function deleteErrorText(response) { + console.log(response.data); + switch(response.data.detail) { + case 'GROUP_WITH_USERS': + return i18n.t('user.cannot-delete-group-with-users'); + + case 'GROUP_NOT_FOUND': + return i18n.t('user.group-not-found'); + + case 'DEFAULT_GROUP': + return i18n.t('user.cannot-delete-default-group'); + + default: + return i18n.t('user.group-deletion-failed'); + } +} + export const groupAPI = { async allGroups() { let response = await apiReq.get(groupsURLs.groups); return response.data; }, - async create(name) { - let response = await apiReq.post(groupsURLs.create, { name: name }); - return response; + create(name) { + return apiReq.post( + groupsURLs.create, + { name: name }, + function() { return i18n.t('user.user-group-creation-failed'); }, + function() { return i18n.t('user.user-group-created'); } + ); }, - async delete(id) { - let response = await apiReq.delete(groupsURLs.delete(id)); - return response; + delete(id) { + return apiReq.delete( + groupsURLs.delete(id), + null, + deleteErrorText, + function() { return i18n.t('user.group-deleted'); } + ); }, async current() { let response = await apiReq.get(groupsURLs.current); return response.data; }, - async update(data) { - let response = await apiReq.put(groupsURLs.update(data.id), data); - return response; + update(data) { + return apiReq.put( + groupsURLs.update(data.id), + data, + function() { return i18n.t('user.error-updating-group'); }, + function() { return i18n.t('settings.group-settings-updated'); } + ); }, }; diff --git a/frontend/src/api/mealplan.js b/frontend/src/api/mealplan.js index 172fc9339..ff51da61e 100644 --- a/frontend/src/api/mealplan.js +++ b/frontend/src/api/mealplan.js @@ -1,5 +1,6 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; +import i18n from '@/i18n.js'; const prefix = baseURL + "meal-plans/"; @@ -15,9 +16,13 @@ const mealPlanURLs = { }; export const mealplanAPI = { - async create(postBody) { - let response = await apiReq.post(mealPlanURLs.create, postBody); - return response; + create(postBody) { + return apiReq.post( + mealPlanURLs.create, + postBody, + function() { return i18n.t('meal-plan.mealplan-creation-failed')}, + function() { return i18n.t('meal-plan.mealplan-created'); } + ); }, async all() { @@ -35,14 +40,21 @@ export const mealplanAPI = { return response; }, - async delete(id) { - let response = await apiReq.delete(mealPlanURLs.delete(id)); - return response; + delete(id) { + return apiReq.delete(mealPlanURLs.delete(id), + null, + function() { return i18n.t('meal-plan.mealplan-deletion-failed'); }, + function() { return i18n.t('meal-plan.mealplan-deleted'); } + ); }, - async update(id, body) { - let response = await apiReq.put(mealPlanURLs.update(id), body); - return response; + update(id, body) { + return apiReq.put( + mealPlanURLs.update(id), + body, + function() { return i18n.t('meal-plan.mealplan-update-failed'); }, + function() { return i18n.t('meal-plan.mealplan-updated'); } + ); }, async shoppingList(id) { diff --git a/frontend/src/api/migration.js b/frontend/src/api/migration.js index f69c6e116..5d967c56c 100644 --- a/frontend/src/api/migration.js +++ b/frontend/src/api/migration.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import { store } from "../store"; +import i18n from '@/i18n.js'; const migrationBase = baseURL + "migrations"; @@ -17,7 +18,12 @@ export const migrationAPI = { return response.data; }, async delete(folder, file) { - let response = await apiReq.delete(migrationURLs.delete(folder, file)); + const response = await apiReq.delete( + migrationURLs.delete(folder, file), + null, + function() { return i18n.t('general.file-folder-not-found'); }, + function() { return i18n.t('migration.migration-data-removed'); } + ); return response; }, async import(folder, file) { diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js index 80385ae6d..52cc212f7 100644 --- a/frontend/src/api/recipe.js +++ b/frontend/src/api/recipe.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import { store } from "../store"; +import i18n from '@/i18n.js'; const prefix = baseURL + "recipes/"; @@ -24,9 +25,12 @@ export const recipeAPI = { * @returns {string} Recipe Slug */ async createByURL(recipeURL) { - let response = await apiReq.post(recipeURLs.createByURL, { - url: recipeURL, - }); + const response = await apiReq.post( + recipeURLs.createByURL, + { url: recipeURL }, + function() { return i18n.t('recipe.recipe-creation-failed'); }, + function() { return i18n.t('recipe.recipe-created'); } + ); store.dispatch("requestRecentRecipes"); return response; @@ -41,7 +45,12 @@ export const recipeAPI = { }, async create(recipeData) { - let response = await apiReq.post(recipeURLs.create, recipeData); + const response = await apiReq.post( + recipeURLs.create, + recipeData, + function() { return i18n.t('recipe.recipe-creation-failed'); }, + function() { return i18n.t('recipe.recipe-created'); } + ); store.dispatch("requestRecentRecipes"); return response.data; }, @@ -51,17 +60,31 @@ export const recipeAPI = { return response.data; }, - async updateImage(recipeSlug, fileObject) { - const fd = new FormData(); - fd.append("image", fileObject); - fd.append("extension", fileObject.name.split(".").pop()); - let response = apiReq.put(recipeURLs.updateImage(recipeSlug), fd); - return response; + updateImage(recipeSlug, fileObject, overrideSuccessMsg = false) { + const formData = new FormData(); + formData.append("image", fileObject); + formData.append("extension", fileObject.name.split(".").pop()); + + let successMessage = null; + if(!overrideSuccessMsg) { + successMessage = function() { return overrideSuccessMsg ? null : i18n.t('recipe.recipe-image-updated'); }; + } + + return apiReq.put( + recipeURLs.updateImage(recipeSlug), + formData, + function() { return i18n.t('general.image-upload-failed'); }, + successMessage + ); }, - async updateImagebyURL(slug, url) { - const response = apiReq.post(recipeURLs.updateImage(slug), { url: url }); - return response; + updateImagebyURL(slug, url) { + return apiReq.post( + recipeURLs.updateImage(slug), + { url: url }, + function() { return i18n.t('general.image-upload-failed'); }, + function() { return i18n.t('recipe.recipe-image-updated'); } + ); }, async update(data) { @@ -76,8 +99,13 @@ export const recipeAPI = { return response.data; }, - async delete(recipeSlug) { - return await apiReq.delete(recipeURLs.delete(recipeSlug)); + delete(recipeSlug) { + return apiReq.delete( + recipeURLs.delete(recipeSlug), + null, + function() { return i18n.t('recipe.unable-to-delete-recipe'); }, + function() { return i18n.t('recipe.recipe-deleted'); } + ); }, async allSummary(start = 0, limit = 9999) { diff --git a/frontend/src/api/signUps.js b/frontend/src/api/signUps.js index b1cdad9d1..ec4963087 100644 --- a/frontend/src/api/signUps.js +++ b/frontend/src/api/signUps.js @@ -1,5 +1,6 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; +import i18n from '@/i18n.js'; const signUpPrefix = baseURL + "users/sign-ups"; @@ -20,9 +21,16 @@ export const signupAPI = { return response.data; }, async deleteToken(token) { - return await apiReq.delete(signUpURLs.deleteToken(token)); + return await apiReq.delete(signUpURLs.deleteToken(token), + null, + null, + function() { return i18n.t('user.sign-up-token-deleted'); } + ); }, async createUser(token, data) { - return apiReq.post(signUpURLs.createUser(token), data); + return apiReq.post(signUpURLs.createUser(token), data, + function() { return i18n.t('user.you-are-not-allowed-to-create-a-user'); }, + function() { return i18n.t('user.user-created'); } + ); }, }; diff --git a/frontend/src/api/siteSettings.js b/frontend/src/api/siteSettings.js index fd0f413c3..f5c234af7 100644 --- a/frontend/src/api/siteSettings.js +++ b/frontend/src/api/siteSettings.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import { store } from "@/store"; +import i18n from '@/i18n.js'; const settingsBase = baseURL + "site-settings"; @@ -19,8 +20,15 @@ export const siteSettingsAPI = { }, async update(body) { - let response = await apiReq.put(settingsURLs.updateSiteSettings, body); - store.dispatch("requestSiteSettings"); + const response = await apiReq.put( + settingsURLs.updateSiteSettings, + body, + function() { return i18n.t('settings.settings-update-failed'); }, + function() { return i18n.t('settings.settings-updated'); } + ); + if(response) { + store.dispatch("requestSiteSettings"); + } return response; }, @@ -34,20 +42,39 @@ export const siteSettingsAPI = { return response.data; }, - async createPage(body) { - return await apiReq.post(settingsURLs.customPages, body); + createPage(body) { + return apiReq.post( + settingsURLs.customPages, + body, + function() { return i18n.t('page.page-creation-failed'); }, + function() { return i18n.t('page.new-page-created'); } + ); }, async deletePage(id) { - return await apiReq.delete(settingsURLs.customPage(id)); + return await apiReq.delete( + settingsURLs.customPage(id), + null, + function() { return i18n.t('page.page-deletion-failed'); }, + function() { return i18n.t('page.page-deleted'); }); }, - async updatePage(body) { - return await apiReq.put(settingsURLs.customPage(body.id), body); + updatePage(body) { + return apiReq.put( + settingsURLs.customPage(body.id), + body, + function() { return i18n.t('page.page-update-failed'); }, + function() { return i18n.t('page.page-updated'); } + ); }, async updateAllPages(allPages) { - let response = await apiReq.put(settingsURLs.customPages, allPages); + let response = await apiReq.put( + settingsURLs.customPages, + allPages, + function() { return i18n.t('page.pages-update-failed'); }, + function() { return i18n.t('page.pages-updated'); } + ); return response; }, }; diff --git a/frontend/src/api/themes.js b/frontend/src/api/themes.js index 04eb90646..321091754 100644 --- a/frontend/src/api/themes.js +++ b/frontend/src/api/themes.js @@ -1,5 +1,6 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; +import i18n from '@/i18n.js'; const prefix = baseURL + "themes"; @@ -23,18 +24,31 @@ export const themeAPI = { }, async create(postBody) { - return await apiReq.post(settingsURLs.createTheme, postBody); + return await apiReq.post( + settingsURLs.createTheme, + postBody, + function() { return i18n.t('settings.theme.error-creating-theme-see-log-file'); }, + function() { return i18n.t('settings.theme.theme-saved'); }); }, - async update(themeName, colors) { + update(themeName, colors) { const body = { name: themeName, colors: colors, }; - return await apiReq.put(settingsURLs.updateTheme(themeName), body); + return apiReq.put( + settingsURLs.updateTheme(themeName), + body, + function() { return i18n.t('settings.theme.error-updating-theme'); }, + function() { return i18n.t('settings.theme.theme-updated'); }); }, - async delete(themeName) { - return await apiReq.delete(settingsURLs.deleteTheme(themeName)); + delete(themeName) { + return apiReq.delete( + settingsURLs.deleteTheme(themeName), + null, + function() { return i18n.t('settings.theme.error-deleting-theme'); }, + function() { return i18n.t('settings.theme.theme-deleted'); } + ); }, }; diff --git a/frontend/src/api/upload.js b/frontend/src/api/upload.js index 206062b44..14ac790f8 100644 --- a/frontend/src/api/upload.js +++ b/frontend/src/api/upload.js @@ -1,15 +1,16 @@ import { apiReq } from "./api-utils"; +import i18n from '@/i18n.js'; export const utilsAPI = { // import { api } from "@/api"; - async uploadFile(url, fileObject) { + uploadFile(url, fileObject) { console.log("API Called"); - let response = await apiReq.post(url, fileObject, { - headers: { - "Content-Type": "multipart/form-data", - }, - }); - return response; + return apiReq.post( + url, + fileObject, + function() { return i18n.t('general.failure-uploading-file'); }, + function() { return i18n.t('general.file-uploaded'); } + ); }, }; diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js index 3e7a5e06a..9081398cd 100644 --- a/frontend/src/api/users.js +++ b/frontend/src/api/users.js @@ -1,6 +1,7 @@ import { baseURL } from "./api-utils"; import { apiReq } from "./api-utils"; import axios from "axios"; +import i18n from '@/i18n.js'; const authPrefix = baseURL + "auth"; const userPrefix = baseURL + "users"; @@ -17,6 +18,16 @@ const usersURLs = { resetPassword: id => `${userPrefix}/${id}/reset-password`, }; +function deleteErrorText(response) { + console.log(response.data); + switch(response.data.detail) { + case 'SUPER_USER': + return i18n.t('user.error-cannot-delete-super-user'); + + default: + return i18n.t('user.you-are-not-allowed-to-delete-this-user'); + } +} export const userAPI = { async login(formData) { let response = await apiReq.post(authURLs.token, formData, { @@ -36,8 +47,13 @@ export const userAPI = { let response = await apiReq.get(usersURLs.users); return response.data; }, - async create(user) { - return await apiReq.post(usersURLs.users, user); + create(user) { + return apiReq.post( + usersURLs.users, + user, + function() { return i18n.t('user.user-creation-failed'); }, + function() { return i18n.t('user.user-created'); } + ); }, async self() { let response = await apiReq.get(usersURLs.self); @@ -47,17 +63,37 @@ export const userAPI = { let response = await apiReq.get(usersURLs.userID(id)); return response.data; }, - async update(user) { - return await apiReq.put(usersURLs.userID(user.id), user); + update(user) { + return apiReq.put( + usersURLs.userID(user.id), + user, + function() { return i18n.t('user.user-update-failed'); }, + function() { return i18n.t('user.user-updated'); } + ); }, - async changePassword(id, password) { - let response = await apiReq.put(usersURLs.password(id), password); - return response.data; + changePassword(id, password) { + return apiReq.put( + usersURLs.password(id), + password, + function() { return i18n.t('user.existing-password-does-not-match'); }, + function() { return i18n.t('user.password-updated'); } + ); }, - async delete(id) { - return await apiReq.delete(usersURLs.userID(id)); + + delete(id) { + return apiReq.delete( + usersURLs.userID(id), + null, + deleteErrorText, + function() { return i18n.t('user.user-deleted'); } + ); }, - async resetPassword(id) { - return await apiReq.put(usersURLs.resetPassword(id)); + resetPassword(id) { + return apiReq.put( + usersURLs.resetPassword(id), + null, + function() { return i18n.t('user.password-reset-failed'); }, + function() { return i18n.t('user.password-has-been-reset-to-the-default-password'); } + ); }, }; diff --git a/frontend/src/components/Login/SignUpForm.vue b/frontend/src/components/Login/SignUpForm.vue index 268bb3ed4..a2530f987 100644 --- a/frontend/src/components/Login/SignUpForm.vue +++ b/frontend/src/components/Login/SignUpForm.vue @@ -85,7 +85,6 @@