mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
Move API texts to frontend + better status codes
This commit is contained in:
parent
b1a6cf39c8
commit
330941522f
50 changed files with 490 additions and 321 deletions
|
@ -1,64 +1,45 @@
|
|||
const baseURL = "/api/";
|
||||
import axios from "axios";
|
||||
import utils from "@/utils";
|
||||
import { store } from "../store";
|
||||
|
||||
axios.defaults.headers.common[
|
||||
"Authorization"
|
||||
] = `Bearer ${store.getters.getToken}`;
|
||||
|
||||
function processResponse(response) {
|
||||
try {
|
||||
utils.notify.show(response.data.snackbar.text, response.data.snackbar.type);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const apiReq = {
|
||||
post: async function(url, data) {
|
||||
let response = await axios.post(url, data).catch(function(error) {
|
||||
if (error.response) {
|
||||
processResponse(error.response);
|
||||
return error.response;
|
||||
}
|
||||
});
|
||||
processResponse(response);
|
||||
return response;
|
||||
},
|
||||
|
||||
put: async function(url, data) {
|
||||
let response = await axios.put(url, data).catch(function(error) {
|
||||
if (error.response) {
|
||||
processResponse(error.response);
|
||||
return response;
|
||||
return error.response;
|
||||
} else return;
|
||||
});
|
||||
processResponse(response);
|
||||
return response;
|
||||
},
|
||||
|
||||
get: async function(url, data) {
|
||||
let response = await axios.get(url, data).catch(function(error) {
|
||||
if (error.response) {
|
||||
processResponse(error.response);
|
||||
return response;
|
||||
return error.response;
|
||||
} else return;
|
||||
});
|
||||
processResponse(response);
|
||||
return response;
|
||||
},
|
||||
|
||||
delete: async function(url, data) {
|
||||
let response = await axios.delete(url, data).catch(function(error) {
|
||||
if (error.response) {
|
||||
processResponse(error.response);
|
||||
return response;
|
||||
return error.response;
|
||||
}
|
||||
});
|
||||
processResponse(response);
|
||||
return response;
|
||||
},
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ export const backupAPI = {
|
|||
* @param {string} fileName
|
||||
*/
|
||||
async delete(fileName) {
|
||||
await apiReq.delete(backupURLs.deleteBackup(fileName));
|
||||
return await apiReq.delete(backupURLs.deleteBackup(fileName));
|
||||
},
|
||||
/**
|
||||
* Creates a backup on the serve given a set of options
|
||||
|
|
|
@ -27,7 +27,7 @@ export const categoryAPI = {
|
|||
async delete(category) {
|
||||
let response = await apiReq.delete(categoryURLs.deleteCategory(category));
|
||||
store.dispatch("requestCategories");
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ export const groupAPI = {
|
|||
},
|
||||
async create(name) {
|
||||
let response = await apiReq.post(groupsURLs.create, { name: name });
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
async delete(id) {
|
||||
let response = await apiReq.delete(groupsURLs.delete(id));
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
async current() {
|
||||
let response = await apiReq.get(groupsURLs.current);
|
||||
|
@ -29,6 +29,6 @@ export const groupAPI = {
|
|||
},
|
||||
async update(data) {
|
||||
let response = await apiReq.put(groupsURLs.update(data.id), data);
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ export const migrationAPI = {
|
|||
},
|
||||
async delete(folder, file) {
|
||||
let response = await apiReq.delete(migrationURLs.delete(folder, file));
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
async import(folder, file) {
|
||||
let response = await apiReq.post(migrationURLs.import(folder, file));
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { baseURL } from "./api-utils";
|
||||
import { apiReq } from "./api-utils";
|
||||
import { store } from "../store";
|
||||
import { router } from "../main";
|
||||
|
||||
const prefix = baseURL + "recipes/";
|
||||
|
||||
|
@ -72,9 +71,7 @@ export const recipeAPI = {
|
|||
},
|
||||
|
||||
async delete(recipeSlug) {
|
||||
await apiReq.delete(recipeURLs.delete(recipeSlug));
|
||||
store.dispatch("requestRecentRecipes");
|
||||
router.push(`/`);
|
||||
return await apiReq.delete(recipeURLs.delete(recipeSlug));
|
||||
},
|
||||
|
||||
async allSummary(start = 0, limit = 9999) {
|
||||
|
|
|
@ -20,11 +20,9 @@ export const signupAPI = {
|
|||
return response.data;
|
||||
},
|
||||
async deleteToken(token) {
|
||||
let response = await apiReq.delete(signUpURLs.deleteToken(token));
|
||||
return response.data;
|
||||
return await apiReq.delete(signUpURLs.deleteToken(token));
|
||||
},
|
||||
async createUser(token, data) {
|
||||
let response = await apiReq.post(signUpURLs.createUser(token), data);
|
||||
return response.data;
|
||||
return apiReq.post(signUpURLs.createUser(token), data);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ export const siteSettingsAPI = {
|
|||
async update(body) {
|
||||
let response = await apiReq.put(settingsURLs.updateSiteSettings, body);
|
||||
store.dispatch("requestSiteSettings");
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
|
||||
async getPages() {
|
||||
|
@ -35,18 +35,15 @@ export const siteSettingsAPI = {
|
|||
},
|
||||
|
||||
async createPage(body) {
|
||||
let response = await apiReq.post(settingsURLs.customPages, body);
|
||||
return response.data;
|
||||
return await apiReq.post(settingsURLs.customPages, body);
|
||||
},
|
||||
|
||||
async deletePage(id) {
|
||||
let response = await apiReq.delete(settingsURLs.customPage(id));
|
||||
return response.data;
|
||||
return await apiReq.delete(settingsURLs.customPage(id));
|
||||
},
|
||||
|
||||
async updatePage(body) {
|
||||
let response = await apiReq.put(settingsURLs.customPage(body.id), body);
|
||||
return response.data;
|
||||
return await apiReq.put(settingsURLs.customPage(body.id), body);
|
||||
},
|
||||
|
||||
async updateAllPages(allPages) {
|
||||
|
|
|
@ -23,8 +23,7 @@ export const themeAPI = {
|
|||
},
|
||||
|
||||
async create(postBody) {
|
||||
let response = await apiReq.post(settingsURLs.createTheme, postBody);
|
||||
return response.data;
|
||||
return await apiReq.post(settingsURLs.createTheme, postBody);
|
||||
},
|
||||
|
||||
async update(themeName, colors) {
|
||||
|
@ -32,12 +31,10 @@ export const themeAPI = {
|
|||
name: themeName,
|
||||
colors: colors,
|
||||
};
|
||||
let response = await apiReq.put(settingsURLs.updateTheme(themeName), body);
|
||||
return response.data;
|
||||
return await apiReq.put(settingsURLs.updateTheme(themeName), body);
|
||||
},
|
||||
|
||||
async delete(themeName) {
|
||||
let response = await apiReq.delete(settingsURLs.deleteTheme(themeName));
|
||||
return response.data;
|
||||
return await apiReq.delete(settingsURLs.deleteTheme(themeName));
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,6 +10,6 @@ export const utilsAPI = {
|
|||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
return response;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -37,8 +37,7 @@ export const userAPI = {
|
|||
return response.data;
|
||||
},
|
||||
async create(user) {
|
||||
let response = await apiReq.post(usersURLs.users, user);
|
||||
return response.data;
|
||||
return await apiReq.post(usersURLs.users, user);
|
||||
},
|
||||
async self() {
|
||||
let response = await apiReq.get(usersURLs.self);
|
||||
|
@ -49,19 +48,16 @@ export const userAPI = {
|
|||
return response.data;
|
||||
},
|
||||
async update(user) {
|
||||
let response = await apiReq.put(usersURLs.userID(user.id), user);
|
||||
return response.data;
|
||||
return await apiReq.put(usersURLs.userID(user.id), user);
|
||||
},
|
||||
async changePassword(id, password) {
|
||||
let response = await apiReq.put(usersURLs.password(id), password);
|
||||
return response.data;
|
||||
},
|
||||
async delete(id) {
|
||||
let response = await apiReq.delete(usersURLs.userID(id));
|
||||
return response.data;
|
||||
return await apiReq.delete(usersURLs.userID(id));
|
||||
},
|
||||
async resetPassword(id) {
|
||||
let response = await apiReq.put(usersURLs.resetPassword(id));
|
||||
return response.data;
|
||||
return await apiReq.put(usersURLs.resetPassword(id));
|
||||
},
|
||||
};
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
props: {},
|
||||
data() {
|
||||
|
@ -98,9 +99,11 @@ export default {
|
|||
this.error = true;
|
||||
}
|
||||
if (key.status != 200) {
|
||||
utils.notify.error(this.$t('user.incorrect-username-or-password'));
|
||||
this.error = true;
|
||||
this.loading = false;
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-successfully-logged-in'));
|
||||
this.clear();
|
||||
this.$store.commit("setToken", key.data.access_token);
|
||||
this.$emit("logged-in");
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
<script>
|
||||
import { api } from "@/api";
|
||||
import { validators } from "@/mixins/validators";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
mixins: [validators],
|
||||
data() {
|
||||
|
@ -132,18 +133,20 @@ export default {
|
|||
admin: false,
|
||||
};
|
||||
|
||||
let successUser = false;
|
||||
if (this.$refs.signUpForm.validate()) {
|
||||
let response = await api.signUps.createUser(this.token, userData);
|
||||
successUser = response.snackbar.text.includes("Created");
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('user.you-are-not-allowed-to-create-a-user'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-created'));
|
||||
this.$emit("user-created");
|
||||
this.$router.push("/");
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit("user-created");
|
||||
|
||||
this.loading = false;
|
||||
if (successUser) {
|
||||
this.$router.push("/");
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -36,8 +36,13 @@ export default {
|
|||
return utils.getDateAsPythonDate(dateObject);
|
||||
},
|
||||
async update() {
|
||||
await api.mealPlans.update(this.mealPlan.uid, this.mealPlan);
|
||||
this.$emit("updated");
|
||||
const response = await api.mealPlans.update(this.mealPlan.uid, this.mealPlan);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('meal-plan.mealplan-update-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('meal-plan.mealplan-updated'));
|
||||
this.$emit("updated");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -196,7 +196,12 @@ export default {
|
|||
endDate: this.endDate,
|
||||
meals: this.meals,
|
||||
};
|
||||
await api.mealPlans.create(mealBody);
|
||||
const response = await api.mealPlans.create(mealBody);
|
||||
if (response.status != 201) {
|
||||
utils.notify.error(this.$t('meal-plan.mealplan-creation-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('meal-plan.mealplan-created'));
|
||||
}
|
||||
this.$emit(CREATE_EVENT);
|
||||
this.meals = [];
|
||||
this.startDate = null;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<v-menu offset-y top nudge-top="6" :close-on-content-click="false">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn color="accent" dark v-bind="attrs" v-on="on">
|
||||
{{$t('recipe.image')}}
|
||||
{{$t('general.image')}}
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card width="400">
|
||||
|
@ -46,6 +46,7 @@ const REFRESH_EVENT = "refresh";
|
|||
const UPLOAD_EVENT = "upload";
|
||||
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: {
|
||||
TheUploadBtn,
|
||||
|
@ -64,6 +65,11 @@ export default {
|
|||
async getImageFromURL() {
|
||||
this.loading = true;
|
||||
const response = await api.recipes.updateImagebyURL(this.slug, this.url);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('general.image-upload-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('general.image-updated'));
|
||||
}
|
||||
if (response) this.$emit(REFRESH_EVENT);
|
||||
this.loading = false;
|
||||
},
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<script>
|
||||
const UPLOAD_EVENT = "uploaded";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
props: {
|
||||
post: {
|
||||
|
@ -55,8 +56,13 @@ export default {
|
|||
let formData = new FormData();
|
||||
formData.append(this.fileName, this.file);
|
||||
|
||||
await api.utils.uploadFile(this.url, formData);
|
||||
const response = await api.utils.uploadFile(this.url, formData);
|
||||
if(response.status != 200) {
|
||||
utils.notify.error(this.$t('general.failure-uploading-file'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('general.file-uploaded'));
|
||||
|
||||
}
|
||||
this.isSelecting = false;
|
||||
this.$emit(UPLOAD_EVENT);
|
||||
}
|
||||
|
|
|
@ -34,15 +34,22 @@
|
|||
"enabled": "Enabled",
|
||||
"exception": "Exception",
|
||||
"failed-count": "Failed: {count}",
|
||||
"failure-uploading-file": "Failure uploading file",
|
||||
"field-required": "Field Required",
|
||||
"file-folder-not-found": "File/folder not found",
|
||||
"file-uploaded": "File uploaded",
|
||||
"filter": "Filter",
|
||||
"friday": "Friday",
|
||||
"get": "Get",
|
||||
"groups": "Groups",
|
||||
"image": "Image",
|
||||
"image-updated": "Image updated",
|
||||
"image-upload-failed": "Image upload failed",
|
||||
"import": "Import",
|
||||
"monday": "Monday",
|
||||
"name": "Name",
|
||||
"no": "No",
|
||||
"not-authorized": "Not authorized",
|
||||
"ok": "OK",
|
||||
"options": "Options:",
|
||||
"random": "Random",
|
||||
|
@ -79,6 +86,14 @@
|
|||
"group": "Group (Beta)",
|
||||
"meal-planner": "Meal Planner",
|
||||
"meal-plans": "Meal Plans",
|
||||
"mealplan-created": "Mealplan created",
|
||||
"mealplan-creation-failed": "Mealplan creation failed",
|
||||
"mealplan-deleted": "Mealplan Deleted",
|
||||
"mealplan-deletion-failed": "Mealplan deletion failed",
|
||||
"mealplan-update-failed": "Mealplan update failed",
|
||||
"mealplan-updated": "Mealplan Updated",
|
||||
"no-meal-plan-defined-yet": "No meal plan defined yet",
|
||||
"no-meal-planned-for-today": "No meal planned for today",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans",
|
||||
"planner": "Planner",
|
||||
"quick-week": "Quick Week",
|
||||
|
@ -90,6 +105,7 @@
|
|||
"description": "Migrate data from Chowdown",
|
||||
"title": "Chowdown"
|
||||
},
|
||||
"migration-data-removed": "Migration data removed",
|
||||
"nextcloud": {
|
||||
"description": "Migrate data from a Nextcloud Cookbook intance",
|
||||
"title": "Nextcloud Cookbook"
|
||||
|
@ -108,6 +124,12 @@
|
|||
"page": {
|
||||
"all-recipes": "All Recipes",
|
||||
"home-page": "Home Page",
|
||||
"new-page-created": "New page created",
|
||||
"page-creation-failed": "Page creation failed",
|
||||
"page-update-failed": "Page update failed",
|
||||
"page-updated": "Page updated",
|
||||
"pages-update-failed": "Pages update failed",
|
||||
"pages-updated": "Pages updated",
|
||||
"recent": "Recent"
|
||||
},
|
||||
"recipe": {
|
||||
|
@ -122,7 +144,6 @@
|
|||
"fat-content": "Fat Content",
|
||||
"fiber-content": "Fiber Content",
|
||||
"grams": "grams",
|
||||
"image": "Image",
|
||||
"ingredient": "Ingredient",
|
||||
"ingredients": "Ingredients",
|
||||
"instructions": "Instructions",
|
||||
|
@ -139,7 +160,9 @@
|
|||
"perform-time": "Cook Time",
|
||||
"prep-time": "Prep Time",
|
||||
"protein-content": "Protein Content",
|
||||
"recipe-deleted": "Recipe deleted",
|
||||
"recipe-image": "Recipe Image",
|
||||
"recipe-image-updated": "Recipe image updated",
|
||||
"recipe-name": "Recipe Name",
|
||||
"servings": "Servings",
|
||||
"sodium-content": "Sodium Content",
|
||||
|
@ -148,6 +171,7 @@
|
|||
"tags": "Tags",
|
||||
"title": "Title",
|
||||
"total-time": "Total Time",
|
||||
"unable-to-delete-recipe": "Unable to Delete Recipe",
|
||||
"view-recipe": "View Recipe"
|
||||
},
|
||||
"search": {
|
||||
|
@ -166,19 +190,26 @@
|
|||
"admin-settings": "Admin Settings",
|
||||
"available-backups": "Available Backups",
|
||||
"backup": {
|
||||
"backup-created-at-response-export_path": "Backup Created at {path}",
|
||||
"backup-deleted": "Backup deleted",
|
||||
"backup-tag": "Backup Tag",
|
||||
"create-heading": "Create a Backup",
|
||||
"error-creating-backup-see-log-file": "Error Creating Backup. See Log File",
|
||||
"full-backup": "Full Backup",
|
||||
"import-summary": "Import Summary",
|
||||
"partial-backup": "Partial Backup"
|
||||
"partial-backup": "Partial Backup",
|
||||
"unable-to-delete-backup-see-log-file": "Unable to Delete Backup. See Log File"
|
||||
},
|
||||
"backup-and-exports": "Backups",
|
||||
"backup-info": "Backups are exported in standard JSON format along with all the images stored on the file system. In your backup folder you'll find a .zip file that contains all of the recipe JSON and images from the database. Additionally, if you selected a markdown file, those will also be stored in the .zip file. To import a backup, it must be located in your backups folder. Automated backups are done each day at 3:00 AM.",
|
||||
"category-deleted": "Category Deleted",
|
||||
"category-deletion-failed": "Category deletion failed",
|
||||
"change-password": "Change Password",
|
||||
"current": "Version:",
|
||||
"custom-pages": "Custom Pages",
|
||||
"edit-page": "Edit Page",
|
||||
"first-day-of-week": "First day of the week",
|
||||
"group-settings-updated": "Group Settings Updated",
|
||||
"homepage": {
|
||||
"all-categories": "All Categories",
|
||||
"card-per-section": "Card Per Section",
|
||||
|
@ -198,6 +229,8 @@
|
|||
"profile": "Profile",
|
||||
"remove-existing-entries-matching-imported-entries": "Remove existing entries matching imported entries",
|
||||
"set-new-time": "Set New Time",
|
||||
"settings-update-failed": "Settings update failed",
|
||||
"settings-updated": "Settings updated",
|
||||
"site-settings": "Site Settings",
|
||||
"theme": {
|
||||
"accent": "Accent",
|
||||
|
@ -208,6 +241,9 @@
|
|||
"default-to-system": "Default to system",
|
||||
"delete-theme": "Delete Theme",
|
||||
"error": "Error",
|
||||
"error-creating-theme-see-log-file": "Error creating theme. See log file.",
|
||||
"error-deleting-theme": "Error deleting theme",
|
||||
"error-updating-theme": "Error updating theme",
|
||||
"info": "Info",
|
||||
"light": "Light",
|
||||
"primary": "Primary",
|
||||
|
@ -215,9 +251,12 @@
|
|||
"select-a-theme-from-the-dropdown-or-create-a-new-theme-note-that-the-default-theme-will-be-served-to-all-users-who-have-not-set-a-theme-preference": "Select a theme from the dropdown or create a new theme. Note that the default theme will be served to all users who have not set a theme preference.",
|
||||
"success": "Success",
|
||||
"theme": "Theme",
|
||||
"theme-deleted": "Theme deleted",
|
||||
"theme-name": "Theme Name",
|
||||
"theme-name-is-required": "Theme Name is required.",
|
||||
"theme-saved": "Theme Saved",
|
||||
"theme-settings": "Theme Settings",
|
||||
"theme-updated": "Theme updated",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webhooks": {
|
||||
|
@ -227,11 +266,14 @@
|
|||
"webhook-url": "Webhook URL"
|
||||
}
|
||||
},
|
||||
"this": {},
|
||||
"user": {
|
||||
"admin": "Admin",
|
||||
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
|
||||
"are-you-sure-you-want-to-delete-the-link": "Are you sure you want to delete the link <b>{link}<b/>?",
|
||||
"are-you-sure-you-want-to-delete-the-user": "Are you sure you want to delete the user <b>{activeName} ID: {activeId}<b/>?",
|
||||
"cannot-delete-default-group": "Cannot delete default group",
|
||||
"cannot-delete-group-with-users": "Cannot delete group with users",
|
||||
"confirm-group-deletion": "Confirm Group Deletion",
|
||||
"confirm-link-deletion": "Confirm Link Deletion",
|
||||
"confirm-password": "Confirm Password",
|
||||
|
@ -244,12 +286,19 @@
|
|||
"e-mail-must-be-valid": "E-mail must be valid",
|
||||
"edit-user": "Edit User",
|
||||
"email": "Email",
|
||||
"error-cannot-delete-super-user": "Error! Cannot Delete Super User",
|
||||
"error-updating-group": "Error updating group",
|
||||
"existing-password-does-not-match": "Existing password does not match",
|
||||
"full-name": "Full Name",
|
||||
"group": "Group",
|
||||
"group-deleted": "Group deleted",
|
||||
"group-deletion-failed": "Group deletion failed",
|
||||
"group-id-with-value": "Group ID: {groupID}",
|
||||
"group-name": "Group Name",
|
||||
"group-not-found": "Group not found",
|
||||
"groups": "Groups",
|
||||
"groups-can-only-be-set-by-administrators": "Groups can only be set by administrators",
|
||||
"incorrect-username-or-password": "Incorrect username or password",
|
||||
"link-id": "Link ID",
|
||||
"link-name": "Link Name",
|
||||
"login": "Login",
|
||||
|
@ -257,20 +306,34 @@
|
|||
"new-password": "New Password",
|
||||
"new-user": "New User",
|
||||
"password": "Password",
|
||||
"password-has-been-reset-to-the-default-password": "Password has been reset to the default password",
|
||||
"password-must-match": "Password must match",
|
||||
"password-reset-failed": "Password reset failed",
|
||||
"password-updated": "Password updated",
|
||||
"reset-password": "Reset Password",
|
||||
"sign-in": "Sign in",
|
||||
"sign-up-links": "Sign Up Links",
|
||||
"sign-up-token-deleted": "Sign Up Token Deleted",
|
||||
"total-mealplans": "Total MealPlans",
|
||||
"total-users": "Total Users",
|
||||
"upload-photo": "Upload Photo",
|
||||
"use-8-characters-or-more-for-your-password": "Use 8 characters or more for your password",
|
||||
"user-created": "User created",
|
||||
"user-creation-failed": "User creation failed",
|
||||
"user-deleted": "User deleted",
|
||||
"user-group": "User Group",
|
||||
"user-group-created": "User Group Created",
|
||||
"user-group-creation-failed": "User Group Creation Failed",
|
||||
"user-id": "User ID",
|
||||
"user-id-with-value": "User ID: {id}",
|
||||
"user-password": "User Password",
|
||||
"user-successfully-logged-in": "User Successfully Logged In",
|
||||
"user-update-failed": "User update failed",
|
||||
"user-updated": "User updated",
|
||||
"users": "Users",
|
||||
"webhook-time": "Webhook Time",
|
||||
"webhooks-enabled": "Webhooks Enabled"
|
||||
"webhooks-enabled": "Webhooks Enabled",
|
||||
"you-are-not-allowed-to-create-a-user": "You are not allowed to create a user",
|
||||
"you-are-not-allowed-to-delete-this-user": "You are not allowed to delete this user"
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@
|
|||
<script>
|
||||
import ImportDialog from "./ImportDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
props: {
|
||||
backups: Array,
|
||||
|
@ -68,10 +69,15 @@ export default {
|
|||
|
||||
this.$emit("finished", importData);
|
||||
},
|
||||
deleteBackup(data) {
|
||||
async deleteBackup(data) {
|
||||
this.$emit("loading");
|
||||
|
||||
api.backups.delete(data.name);
|
||||
const response = await api.backups.delete(data.name);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('settings.backup.unable-to-delete-backup-see-log-file'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.backup.backup-deleted'));
|
||||
}
|
||||
this.selectedBackup = null;
|
||||
this.backupLoading = false;
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<script>
|
||||
import ImportOptions from "./ImportOptions";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: { ImportOptions },
|
||||
data() {
|
||||
|
@ -97,10 +98,15 @@ export default {
|
|||
templates: this.selectedTemplates,
|
||||
};
|
||||
|
||||
await api.backups.create(data);
|
||||
const response = await api.backups.create(data);
|
||||
this.loading = false;
|
||||
if (response.status != 201) {
|
||||
utils.notify.error(this.$t('settings.backup.error-creating-backup-see-log-file'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.backup.backup-created-at-response-export_path', {path: response.data.export_path}));
|
||||
this.$emit("created");
|
||||
}
|
||||
|
||||
this.$emit("created");
|
||||
},
|
||||
appendTemplate(templateName) {
|
||||
if (this.selectedTemplates.includes(templateName)) {
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
const RENDER_EVENT = "update";
|
||||
import ConfirmationDialog from "@/components/UI/Dialogs/ConfirmationDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: { ConfirmationDialog },
|
||||
props: {
|
||||
|
@ -91,8 +92,28 @@ export default {
|
|||
this.$refs.deleteGroupConfirm.open();
|
||||
},
|
||||
async deleteGroup() {
|
||||
await api.groups.delete(this.group.id);
|
||||
this.$emit(RENDER_EVENT);
|
||||
const response = await api.groups.delete(this.group.id);
|
||||
if (response.status != 200) {
|
||||
switch(response.data.detail) {
|
||||
case 'GROUP_WITH_USERS':
|
||||
utils.notify.error(this.$t('user.cannot-delete-group-with-users'));
|
||||
break;
|
||||
|
||||
case 'GROUP_NOT_FOUND':
|
||||
utils.notify.error(this.$t('user.group-not-found'));
|
||||
break;
|
||||
|
||||
case 'DEFAULT_GROUP':
|
||||
utils.notify.error(this.$t('user.cannot-delete-default-group'));
|
||||
break;
|
||||
|
||||
default:
|
||||
utils.notify.error(this.$t('user.group-deletion-failed'));
|
||||
}
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.group-deleted'));
|
||||
this.$emit(RENDER_EVENT);
|
||||
}
|
||||
},
|
||||
closeGroupDelete() {
|
||||
console.log("Close Delete");
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
import { validators } from "@/mixins/validators";
|
||||
import { api } from "@/api";
|
||||
import GroupCard from "./GroupCard";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: { GroupCard },
|
||||
mixins: [validators],
|
||||
|
@ -104,8 +105,11 @@ export default {
|
|||
methods: {
|
||||
async createGroup() {
|
||||
this.groupLoading = true;
|
||||
let response = await api.groups.create(this.newGroupName);
|
||||
if (response.created) {
|
||||
const response = await api.groups.create(this.newGroupName);
|
||||
if (response.status != 201) {
|
||||
utils.notify.error(this.$t('user.user-group-creation-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-group-created'));
|
||||
this.groupLoading = false;
|
||||
this.groupDialog = false;
|
||||
this.$store.dispatch("requestAllGroups");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<v-card outlined class="mt-n1">
|
||||
<ConfirmationDialog
|
||||
ref="deleteUserDialog"
|
||||
ref="deleteTokenDialog"
|
||||
:title="$t('user.confirm-link-deletion')"
|
||||
:message="
|
||||
$t('user.are-you-sure-you-want-to-delete-the-link', {
|
||||
|
@ -9,7 +9,7 @@
|
|||
})
|
||||
"
|
||||
icon="mdi-alert"
|
||||
@confirm="deleteUser"
|
||||
@confirm="deleteToken"
|
||||
:width="450"
|
||||
@close="closeDelete"
|
||||
/>
|
||||
|
@ -109,6 +109,7 @@
|
|||
<script>
|
||||
import ConfirmationDialog from "@/components/UI/Dialogs/ConfirmationDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
import { validators } from "@/mixins/validators";
|
||||
export default {
|
||||
components: { ConfirmationDialog },
|
||||
|
@ -181,8 +182,13 @@ export default {
|
|||
this.links = await api.signUps.getAll();
|
||||
},
|
||||
|
||||
async deleteUser() {
|
||||
await api.signUps.deleteToken(this.activeId);
|
||||
async deleteToken() {
|
||||
const response = await api.signUps.deleteToken(this.activeId);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('general.not-authorized'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.sign-up-token-deleted'));
|
||||
}
|
||||
this.initialize();
|
||||
},
|
||||
|
||||
|
@ -197,7 +203,7 @@ export default {
|
|||
this.activeName = item.name;
|
||||
this.editedIndex = this.links.indexOf(item);
|
||||
this.editedItem = Object.assign({}, item);
|
||||
this.$refs.deleteUserDialog.open();
|
||||
this.$refs.deleteTokenDialog.open();
|
||||
},
|
||||
|
||||
deleteItemConfirm() {
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
|
||||
<v-card-actions>
|
||||
<v-btn color="info" text @click="resetPassword">
|
||||
Reset Password
|
||||
{{$t('user.reset-password')}}
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" text @click="close">
|
||||
|
@ -146,6 +146,7 @@
|
|||
<script>
|
||||
import ConfirmationDialog from "@/components/UI/Dialogs/ConfirmationDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
import { validators } from "@/mixins/validators";
|
||||
export default {
|
||||
components: { ConfirmationDialog },
|
||||
|
@ -223,8 +224,20 @@ export default {
|
|||
},
|
||||
|
||||
async deleteUser() {
|
||||
await api.users.delete(this.activeId);
|
||||
this.initialize();
|
||||
const response = await api.users.delete(this.activeId);
|
||||
if (response.status != 200) {
|
||||
switch(response.data.detail) {
|
||||
case 'SUPER_USER':
|
||||
utils.notify.error(this.$t('user.error-cannot-delete-super-user'));
|
||||
break;
|
||||
|
||||
default:
|
||||
utils.notify.error(this.$t('user.you-are-not-allowed-to-delete-this-user'));
|
||||
}
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-deleted'));
|
||||
this.initialize();
|
||||
}
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
|
@ -264,17 +277,40 @@ export default {
|
|||
|
||||
async save() {
|
||||
if (this.editedIndex > -1) {
|
||||
await api.users.update(this.editedItem);
|
||||
this.close();
|
||||
this.updateUser();
|
||||
} else if (this.$refs.newUser.validate()) {
|
||||
await api.users.create(this.editedItem);
|
||||
this.close();
|
||||
this.createUser();
|
||||
}
|
||||
await this.initialize();
|
||||
},
|
||||
resetPassword() {
|
||||
api.users.resetPassword(this.editedItem.id);
|
||||
async resetPassword() {
|
||||
const response = await api.users.resetPassword(this.editedItem.id);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('user.password-reset-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.password-has-been-reset-to-the-default-password'));
|
||||
}
|
||||
},
|
||||
|
||||
async createUser() {
|
||||
const response = await api.users.create(this.editedItem);
|
||||
if(response.status!=201) {
|
||||
utils.notify.error(this.$t('user.user-creation-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-created'));
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
|
||||
async updateUser() {
|
||||
const response = await api.users.update(this.editedItem);
|
||||
if(response.status!=200) {
|
||||
utils.notify.error(this.$t('user.user-update-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-updated'));
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
import { api } from "@/api";
|
||||
import TimePickerDialog from "@/components/FormHelpers/TimePickerDialog";
|
||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: {
|
||||
TimePickerDialog,
|
||||
|
@ -135,9 +136,14 @@ export default {
|
|||
this.groupSettings.webhookUrls.splice(index, 1);
|
||||
},
|
||||
async saveGroupSettings() {
|
||||
await api.groups.update(this.groupSettings);
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
this.getSiteSettings();
|
||||
const response = await api.groups.update(this.groupSettings);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('user.error-updating-group'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.group-settings-updated'));
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
this.getSiteSettings();
|
||||
}
|
||||
},
|
||||
testWebhooks() {
|
||||
api.settings.testWebhooks();
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
|
||||
import { api } from "@/api";
|
||||
import MigrationDialog from "./MigrationDialog";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
props: {
|
||||
folder: String,
|
||||
|
@ -86,9 +87,14 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
deleteMigration(file_name) {
|
||||
api.migrations.delete(this.folder, file_name);
|
||||
this.$emit("refresh");
|
||||
async deleteMigration(file_name) {
|
||||
const response = await api.migrations.delete(this.folder, file_name);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('general.file-folder-not-found'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('migration.migration-data-removed'));
|
||||
this.$emit("refresh");
|
||||
}
|
||||
},
|
||||
async importMigration(file_name) {
|
||||
this.loading = true;
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
// import AvatarPicker from '@/components/AvatarPicker'
|
||||
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
import { validators } from "@/mixins/validators";
|
||||
import { initials } from "@/mixins/initials";
|
||||
export default {
|
||||
|
@ -201,11 +202,16 @@ export default {
|
|||
},
|
||||
async updateUser() {
|
||||
this.loading = true;
|
||||
let newKey = await api.users.update(this.user);
|
||||
this.$store.commit("setToken", newKey.access_token);
|
||||
this.refreshProfile();
|
||||
this.loading = false;
|
||||
this.$store.dispatch("requestUserData");
|
||||
const response = await api.users.update(this.user);
|
||||
if(response.status != 200) {
|
||||
utils.notify.error(this.$t('user.user-update-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.user-updated'));
|
||||
this.$store.commit("setToken", response.data.access_token);
|
||||
this.refreshProfile();
|
||||
this.loading = false;
|
||||
this.$store.dispatch("requestUserData");
|
||||
}
|
||||
},
|
||||
async changePassword() {
|
||||
this.paswordLoading = true;
|
||||
|
@ -215,7 +221,13 @@ export default {
|
|||
};
|
||||
|
||||
if (this.$refs.passChange.validate()) {
|
||||
await api.users.changePassword(this.user.id, data);
|
||||
const response = await api.users.changePassword(this.user.id, data);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('user.existing-password-does-not-match'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('user.password-updated'));
|
||||
this.$emit("refresh");
|
||||
}
|
||||
}
|
||||
this.paswordLoading = false;
|
||||
},
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<script>
|
||||
const NEW_PAGE_EVENT = "refresh-page";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||
export default {
|
||||
components: {
|
||||
|
@ -82,14 +83,25 @@ export default {
|
|||
this.$refs.categoryFormSelector.setInit(this.page.categories);
|
||||
},
|
||||
async submitForm() {
|
||||
let response, sucessMessage, errorMessage;
|
||||
if (this.create) {
|
||||
await api.siteSettings.createPage(this.page);
|
||||
response = await api.siteSettings.createPage(this.page);
|
||||
sucessMessage = this.$t('page.new-page-created');
|
||||
errorMessage = this.$t('page.page-creation-failed');
|
||||
} else {
|
||||
await api.siteSettings.updatePage(this.page);
|
||||
response = await api.siteSettings.updatePage(this.page);
|
||||
sucessMessage = this.$t('page.page-updated');
|
||||
errorMessage = this.$t('page.page-update-failed');
|
||||
}
|
||||
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(errorMessage);
|
||||
} else {
|
||||
utils.notify.success(sucessMessage);
|
||||
this.pageDialog = false;
|
||||
this.page.categories = [];
|
||||
this.$emit(NEW_PAGE_EVENT);
|
||||
}
|
||||
this.pageDialog = false;
|
||||
this.page.categories = [];
|
||||
this.$emit(NEW_PAGE_EVENT);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
import draggable from "vuedraggable";
|
||||
import CreatePageDialog from "./CreatePageDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
|
@ -109,9 +110,14 @@ export default {
|
|||
element.position = index;
|
||||
});
|
||||
|
||||
await api.siteSettings.updateAllPages(this.customPages);
|
||||
const response = await api.siteSettings.updateAllPages(this.customPages);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('page.pages-update-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('page.pages-updated'));
|
||||
this.getPages();
|
||||
}
|
||||
|
||||
this.getPages();
|
||||
},
|
||||
editPage(index) {
|
||||
this.editPageData.data = this.customPages[index];
|
||||
|
|
|
@ -150,6 +150,7 @@ import { api } from "@/api";
|
|||
import LanguageSelector from "@/components/FormHelpers/LanguageSelector";
|
||||
import draggable from "vuedraggable";
|
||||
import NewCategoryTagDialog from "@/components/UI/Dialogs/NewCategoryTagDialog.vue";
|
||||
import utils from "@/utils";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -213,8 +214,13 @@ export default {
|
|||
writeLang(val) {
|
||||
this.settings.language = val;
|
||||
},
|
||||
deleteCategoryfromDatabase(category) {
|
||||
api.categories.delete(category);
|
||||
async deleteCategoryfromDatabase(category) {
|
||||
const response = await api.categories.delete(category);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('settings.category-deletion-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.category-deleted'));
|
||||
}
|
||||
},
|
||||
async getOptions() {
|
||||
this.settings = await api.siteSettings.get();
|
||||
|
@ -223,7 +229,12 @@ export default {
|
|||
this.settings.categories.splice(index, 1);
|
||||
},
|
||||
async saveSettings() {
|
||||
await api.siteSettings.update(this.settings);
|
||||
const response = await api.siteSettings.update(this.settings);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('settings.settings-update-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.settings-updated'));
|
||||
}
|
||||
this.getOptions();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<script>
|
||||
import ConfirmationDialog from "@/components/UI/Dialogs/ConfirmationDialog";
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
|
||||
const DELETE_EVENT = "delete";
|
||||
const APPLY_EVENT = "apply";
|
||||
|
@ -70,11 +71,15 @@ export default {
|
|||
},
|
||||
async deleteSelectedTheme() {
|
||||
//Delete Theme from DB
|
||||
await api.themes.delete(this.theme.name);
|
||||
|
||||
//Get the new list of available from DB
|
||||
this.availableThemes = await api.themes.requestAll();
|
||||
this.$emit(DELETE_EVENT);
|
||||
const response = await api.themes.delete(this.theme.name);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('settings.theme.error-deleting-theme'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.theme.theme-deleted'));
|
||||
//Get the new list of available from DB
|
||||
this.availableThemes = await api.themes.requestAll();
|
||||
this.$emit(DELETE_EVENT);
|
||||
}
|
||||
},
|
||||
async saveThemes() {
|
||||
this.$store.commit("setTheme", this.theme);
|
||||
|
|
|
@ -138,6 +138,7 @@ import { api } from "@/api";
|
|||
import ColorPickerDialog from "@/components/FormHelpers/ColorPickerDialog";
|
||||
import NewThemeDialog from "./NewThemeDialog";
|
||||
import ThemeCard from "./ThemeCard";
|
||||
import utils from "@/utils";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -171,9 +172,14 @@ export default {
|
|||
* Create the new Theme and select it.
|
||||
*/
|
||||
async appendTheme(NewThemeDialog) {
|
||||
await api.themes.create(NewThemeDialog);
|
||||
this.availableThemes.push(NewThemeDialog);
|
||||
this.$store.commit("setTheme", NewThemeDialog);
|
||||
const response = await api.themes.create(NewThemeDialog);
|
||||
if (response.status != 201) {
|
||||
utils.notify.error(this.$t('settings.theme.error-creating-theme-see-log-file'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.theme.theme-saved'));
|
||||
this.availableThemes.push(NewThemeDialog);
|
||||
this.$store.commit("setTheme", NewThemeDialog);
|
||||
}
|
||||
},
|
||||
setStoresDarkMode() {
|
||||
this.$store.commit("setDarkMode", this.selectedDarkMode);
|
||||
|
@ -182,10 +188,15 @@ export default {
|
|||
* This will save the current colors and make the selected theme live.
|
||||
*/
|
||||
async saveThemes() {
|
||||
await api.themes.update(
|
||||
const response = await api.themes.update(
|
||||
this.selectedTheme.name,
|
||||
this.selectedTheme.colors
|
||||
);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('settings.theme.error-updating-theme'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('settings.theme.theme-updated'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -128,8 +128,13 @@ export default {
|
|||
this.requestMeals();
|
||||
},
|
||||
async deletePlan(id) {
|
||||
await api.mealPlans.delete(id);
|
||||
this.requestMeals();
|
||||
const response = await api.mealPlans.delete(id);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('meal-plan.mealplan-deletion-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('meal-plan.mealplan-deleted'));
|
||||
this.requestMeals();
|
||||
}
|
||||
},
|
||||
openShoppingList(id) {
|
||||
this.$refs.shoppingList.openDialog(id);
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
|
||||
import RecipeEditor from "@/components/Recipe/RecipeEditor";
|
||||
import VJsoneditor from "v-jsoneditor";
|
||||
|
@ -101,7 +102,12 @@ export default {
|
|||
let slug = await api.recipes.create(this.recipeDetails);
|
||||
|
||||
if (this.fileObject) {
|
||||
await api.recipes.updateImage(slug, this.fileObject);
|
||||
const response = await api.recipes.updateImage(slug, this.fileObject);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('general.image-upload-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('recipe.recipe-image-updated'));
|
||||
}
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
|
|
|
@ -78,6 +78,9 @@ import RecipeEditor from "@/components/Recipe/RecipeEditor";
|
|||
import RecipeTimeCard from "@/components/Recipe/RecipeTimeCard.vue";
|
||||
import EditorButtonRow from "@/components/Recipe/EditorButtonRow";
|
||||
import { user } from "@/mixins/user";
|
||||
import utils from "@/utils";
|
||||
import store from "@/store";
|
||||
import { router } from "@/routes";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -164,8 +167,15 @@ export default {
|
|||
return api.recipes.recipeImage(image) + "&rnd=" + this.imageKey;
|
||||
}
|
||||
},
|
||||
deleteRecipe() {
|
||||
api.recipes.delete(this.recipeDetails.slug);
|
||||
async deleteRecipe() {
|
||||
let response = await api.recipes.delete(this.recipeDetails.slug);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('recipe.unable-to-delete-recipe'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('recipe.recipe-deleted'));
|
||||
store.dispatch("requestRecentRecipes");
|
||||
router.push(`/`);
|
||||
}
|
||||
},
|
||||
validateRecipe() {
|
||||
if (this.jsonEditor) {
|
||||
|
@ -176,7 +186,12 @@ export default {
|
|||
},
|
||||
async saveImage() {
|
||||
if (this.fileObject) {
|
||||
await api.recipes.updateImage(this.recipeDetails.slug, this.fileObject);
|
||||
const response = await api.recipes.updateImage(this.recipeDetails.slug, this.fileObject);
|
||||
if (response.status != 200) {
|
||||
utils.notify.error(this.$t('general.image-upload-failed'));
|
||||
} else {
|
||||
utils.notify.success(this.$t('recipe.recipe-image-updated'));
|
||||
}
|
||||
}
|
||||
this.imageKey += 1;
|
||||
},
|
||||
|
|
|
@ -2,13 +2,12 @@ import operator
|
|||
import shutil
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
|
||||
from mealie.core.config import app_dirs
|
||||
from mealie.core.security import create_file_token
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user, validate_file_token
|
||||
from mealie.schema.backup import BackupJob, ImportJob, Imports, LocalBackup
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.services.backups import imports
|
||||
from mealie.services.backups.exports import backup_all
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
@ -31,30 +30,27 @@ def available_imports():
|
|||
return Imports(imports=imports, templates=templates)
|
||||
|
||||
|
||||
@router.post("/export/database", status_code=201)
|
||||
@router.post("/export/database", status_code=status.HTTP_201_CREATED)
|
||||
def export_database(data: BackupJob, session: Session = Depends(generate_session)):
|
||||
"""Generates a backup of the recipe database in json format."""
|
||||
export_path = backup_all(
|
||||
session=session,
|
||||
tag=data.tag,
|
||||
templates=data.templates,
|
||||
export_recipes=data.options.recipes,
|
||||
export_settings=data.options.settings,
|
||||
export_pages=data.options.pages,
|
||||
export_themes=data.options.themes,
|
||||
export_users=data.options.users,
|
||||
export_groups=data.options.groups,
|
||||
)
|
||||
try:
|
||||
return SnackResponse.success("Backup Created at " + export_path)
|
||||
except:
|
||||
HTTPException(
|
||||
status_code=400,
|
||||
detail=SnackResponse.error("Error Creating Backup. See Log File"),
|
||||
export_path = backup_all(
|
||||
session=session,
|
||||
tag=data.tag,
|
||||
templates=data.templates,
|
||||
export_recipes=data.options.recipes,
|
||||
export_settings=data.options.settings,
|
||||
export_pages=data.options.pages,
|
||||
export_themes=data.options.themes,
|
||||
export_users=data.options.users,
|
||||
export_groups=data.options.groups,
|
||||
)
|
||||
return {"export_path": export_path}
|
||||
except:
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
||||
|
||||
@router.post("/upload")
|
||||
@router.post("/upload", status_code=status.HTTP_200_OK)
|
||||
def upload_backup_file(archive: UploadFile = File(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dest = app_dirs.BACKUP_DIR.joinpath(archive.filename)
|
||||
|
@ -62,10 +58,9 @@ def upload_backup_file(archive: UploadFile = File(...)):
|
|||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(archive.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("Backup uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
|
||||
@router.get("/{file_name}/download")
|
||||
|
@ -76,7 +71,7 @@ async def download_backup_file(file_name: str):
|
|||
return {"fileToken": create_file_token(file)}
|
||||
|
||||
|
||||
@router.post("/{file_name}/import", status_code=200)
|
||||
@router.post("/{file_name}/import", status_code=status.HTTP_200_OK)
|
||||
def import_database(file_name: str, import_data: ImportJob, session: Session = Depends(generate_session)):
|
||||
""" Import a database backup file generated from Mealie. """
|
||||
|
||||
|
@ -94,16 +89,14 @@ def import_database(file_name: str, import_data: ImportJob, session: Session = D
|
|||
)
|
||||
|
||||
|
||||
@router.delete("/{file_name}/delete", status_code=200)
|
||||
@router.delete("/{file_name}/delete", status_code=status.HTTP_200_OK)
|
||||
def delete_backup(file_name: str):
|
||||
""" Removes a database backup from the file system """
|
||||
file_path = app_dirs.BACKUP_DIR.joinpath(file_name)
|
||||
|
||||
if not file_path.is_file():
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
try:
|
||||
app_dirs.BACKUP_DIR.joinpath(file_name).unlink()
|
||||
file_path.unlink()
|
||||
except:
|
||||
HTTPException(
|
||||
status_code=400,
|
||||
detail=SnackResponse.error("Unable to Delete Backup. See Log File"),
|
||||
)
|
||||
|
||||
return SnackResponse.error(f"{file_name} Deleted")
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, status, HTTPException
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import GroupBase, GroupInDB, UpdateGroup, UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -30,7 +29,7 @@ async def get_current_user_group(
|
|||
return db.groups.get(session, current_user.group, "name")
|
||||
|
||||
|
||||
@router.post("")
|
||||
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||
async def create_group(
|
||||
group_data: GroupBase,
|
||||
current_user=Depends(get_current_user),
|
||||
|
@ -40,9 +39,8 @@ async def create_group(
|
|||
|
||||
try:
|
||||
db.groups.create(session, group_data.dict())
|
||||
return SnackResponse.success("User Group Created", {"created": True})
|
||||
except:
|
||||
return SnackResponse.error("User Group Creation Failed")
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.put("/{id}")
|
||||
|
@ -55,8 +53,6 @@ async def update_group_data(
|
|||
""" Updates a User Group """
|
||||
db.groups.update(session, id, group_data.dict())
|
||||
|
||||
return SnackResponse.success("Group Settings Updated")
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
async def delete_user_group(
|
||||
|
@ -65,16 +61,23 @@ async def delete_user_group(
|
|||
""" Removes a user group from the database """
|
||||
|
||||
if id == 1:
|
||||
return SnackResponse.error("Cannot delete default group")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='DEFAULT_GROUP'
|
||||
)
|
||||
|
||||
group: GroupInDB = db.groups.get(session, id)
|
||||
|
||||
if not group:
|
||||
return SnackResponse.error("Group not found")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='GROUP_NOT_FOUND'
|
||||
)
|
||||
|
||||
if not group.users == []:
|
||||
return SnackResponse.error("Cannot delete group with users")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='GROUP_WITH_USERS'
|
||||
)
|
||||
|
||||
db.groups.delete(session, id)
|
||||
|
||||
return
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.meal import MealPlanIn, MealPlanInDB
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import GroupInDB, UserInDB
|
||||
from mealie.services.image import image
|
||||
from mealie.services.meal_services import get_todays_meal, process_meals
|
||||
|
@ -23,7 +22,7 @@ def get_all_meals(
|
|||
return db.groups.get_meals(session, current_user.group)
|
||||
|
||||
|
||||
@router.post("/create")
|
||||
@router.post("/create", status_code=status.HTTP_201_CREATED)
|
||||
def create_meal_plan(
|
||||
data: MealPlanIn, session: Session = Depends(generate_session), current_user=Depends(get_current_user)
|
||||
):
|
||||
|
@ -31,8 +30,6 @@ def create_meal_plan(
|
|||
processed_plan = process_meals(session, data)
|
||||
db.meals.create(session, processed_plan.dict())
|
||||
|
||||
return SnackResponse.success("Mealplan Created")
|
||||
|
||||
|
||||
@router.put("/{plan_id}")
|
||||
def update_meal_plan(
|
||||
|
@ -44,25 +41,28 @@ def update_meal_plan(
|
|||
""" Updates a meal plan based off ID """
|
||||
processed_plan = process_meals(session, meal_plan)
|
||||
processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict())
|
||||
db.meals.update(session, plan_id, processed_plan.dict())
|
||||
|
||||
return SnackResponse.info("Mealplan Updated")
|
||||
try:
|
||||
db.meals.update(session, plan_id, processed_plan.dict())
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.delete("/{plan_id}")
|
||||
def delete_meal_plan(plan_id, session: Session = Depends(generate_session), current_user=Depends(get_current_user)):
|
||||
""" Removes a meal plan from the database """
|
||||
|
||||
db.meals.delete(session, plan_id)
|
||||
|
||||
return SnackResponse.error("Mealplan Deleted")
|
||||
try:
|
||||
db.meals.delete(session, plan_id)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.get("/this-week", response_model=MealPlanInDB)
|
||||
def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
|
||||
""" Returns the meal plan data for this week """
|
||||
|
||||
return db.groups.get_meals(session, current_user.group)[0]
|
||||
plans = db.groups.get_meals(session, current_user.group)
|
||||
if plans:
|
||||
return plans[0]
|
||||
|
||||
|
||||
@router.get("/today", tags=["Meal Plan"])
|
||||
|
@ -74,8 +74,8 @@ def get_today(session: Session = Depends(generate_session), current_user: UserIn
|
|||
|
||||
group_in_db: GroupInDB = db.groups.get(session, current_user.group, "name")
|
||||
recipe = get_todays_meal(session, group_in_db)
|
||||
|
||||
return recipe.slug
|
||||
if recipe:
|
||||
return recipe.slug
|
||||
|
||||
|
||||
@router.get("/today/image", tags=["Meal Plan"])
|
||||
|
@ -90,8 +90,8 @@ def get_todays_image(session: Session = Depends(generate_session), group_name: s
|
|||
if recipe:
|
||||
recipe_image = image.read_image(recipe.slug, image_type=image.IMG_OPTIONS.ORIGINAL_IMAGE)
|
||||
else:
|
||||
raise HTTPException(404, "no meal for today")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
if recipe_image:
|
||||
return FileResponse(recipe_image)
|
||||
else:
|
||||
raise HTTPException(404, "file not found")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
|
|
|
@ -2,12 +2,11 @@ import operator
|
|||
import shutil
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, File, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, UploadFile, status
|
||||
from mealie.core.config import app_dirs
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.migration import MigrationFile, Migrations
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.services.migrations import migration
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -42,7 +41,7 @@ def import_migration(import_type: migration.Migration, file_name: str, session:
|
|||
return migration.migrate(import_type, file_path, session)
|
||||
|
||||
|
||||
@router.delete("/{import_type}/{file_name}/delete")
|
||||
@router.delete("/{import_type}/{file_name}/delete", status_code=status.HTTP_200_OK)
|
||||
def delete_migration_data(import_type: migration.Migration, file_name: str):
|
||||
""" Removes migration data from the file system """
|
||||
|
||||
|
@ -53,12 +52,11 @@ def delete_migration_data(import_type: migration.Migration, file_name: str):
|
|||
elif remove_path.is_dir():
|
||||
shutil.rmtree(remove_path)
|
||||
else:
|
||||
SnackResponse.error("File/Folder not found.")
|
||||
|
||||
return SnackResponse.error(f"Migration Data Remove: {remove_path.absolute()}")
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.post("/{import_type}/upload")
|
||||
|
||||
@router.post("/{import_type}/upload", status_code=status.HTTP_200_OK)
|
||||
def upload_nextcloud_zipfile(import_type: migration.Migration, archive: UploadFile = File(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dir = app_dirs.MIGRATION_DIR.joinpath(import_type.value)
|
||||
|
@ -68,7 +66,5 @@ def upload_nextcloud_zipfile(import_type: migration.Migration, archive: UploadFi
|
|||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(archive.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("Migration data uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
|
@ -1,9 +1,8 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.category import CategoryIn, RecipeCategoryResponse
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(
|
||||
|
@ -41,6 +40,7 @@ async def delete_recipe_category(
|
|||
category does not impact a recipe. The category will be removed
|
||||
from any recipes that contain it"""
|
||||
|
||||
db.categories.delete(session, category)
|
||||
|
||||
return SnackResponse.error(f"Category Deleted: {category}")
|
||||
try:
|
||||
db.categories.delete(session, category)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
|
|
@ -2,13 +2,12 @@ import shutil
|
|||
from enum import Enum
|
||||
|
||||
import requests
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, status
|
||||
from fastapi.responses import FileResponse
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.recipe import Recipe, RecipeURLIn
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.services.image.image import IMG_OPTIONS, delete_image, read_image, rename_image, scrape_image, write_image
|
||||
from mealie.services.scraper.scraper import create_from_url
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
@ -81,9 +80,8 @@ def delete_recipe(
|
|||
db.recipes.delete(session, recipe_slug)
|
||||
delete_image(recipe_slug)
|
||||
except:
|
||||
raise HTTPException(status_code=404, detail=SnackResponse.error("Unable to Delete Recipe"))
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
return SnackResponse.error(f"Recipe {recipe_slug} Deleted")
|
||||
|
||||
|
||||
class ImageType(str, Enum):
|
||||
|
@ -106,7 +104,7 @@ async def get_recipe_img(recipe_slug: str, image_type: ImageType = ImageType.ori
|
|||
if recipe_image:
|
||||
return FileResponse(recipe_image)
|
||||
else:
|
||||
raise HTTPException(404, "file not found")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
|
||||
|
||||
@router.put("/{recipe_slug}/image")
|
||||
|
@ -133,5 +131,3 @@ def scrape_image_url(
|
|||
""" Removes an existing image and replaces it with the incoming file. """
|
||||
|
||||
scrape_image(url.url, recipe_slug)
|
||||
|
||||
return SnackResponse.success("Recipe Image Updated")
|
||||
|
|
|
@ -3,7 +3,6 @@ from mealie.db.database import db
|
|||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.category import RecipeTagResponse, TagIn
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(tags=["Recipes"])
|
||||
|
@ -43,6 +42,7 @@ async def delete_recipe_tag(
|
|||
tag does not impact a recipe. The tag will be removed
|
||||
from any recipes that contain it"""
|
||||
|
||||
db.tags.delete(session, tag)
|
||||
|
||||
return SnackResponse.error(f"Tag Deleted: {tag}")
|
||||
try:
|
||||
db.tags.delete(session, tag)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
|
|
@ -5,7 +5,6 @@ from mealie.db.database import db
|
|||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.settings import CustomPageBase, CustomPageOut
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -29,8 +28,6 @@ async def create_new_page(
|
|||
|
||||
db.custom_pages.create(session, new_page.dict())
|
||||
|
||||
return SnackResponse.success("New Page Created")
|
||||
|
||||
|
||||
@router.put("")
|
||||
async def update_multiple_pages(
|
||||
|
@ -41,7 +38,6 @@ async def update_multiple_pages(
|
|||
""" Update multiple custom pages """
|
||||
for page in pages:
|
||||
db.custom_pages.update(session, page.id, page.dict())
|
||||
return SnackResponse.success("Pages Updated")
|
||||
|
||||
|
||||
@router.get("/{id}")
|
||||
|
@ -57,7 +53,7 @@ async def get_single_page(
|
|||
|
||||
|
||||
@router.put("/{id}")
|
||||
async def update_single_age(
|
||||
async def update_single_page(
|
||||
data: CustomPageOut,
|
||||
id: int,
|
||||
session: Session = Depends(generate_session),
|
||||
|
|
|
@ -3,7 +3,6 @@ from mealie.db.database import db
|
|||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.settings import SiteSettings
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import GroupInDB, UserInDB
|
||||
from mealie.utils.post_webhooks import post_webhooks
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
@ -27,8 +26,6 @@ def update_settings(
|
|||
""" Returns Site Settings """
|
||||
db.settings.update(session, 1, data.dict())
|
||||
|
||||
return SnackResponse.success("Settings Updated")
|
||||
|
||||
|
||||
@router.post("/webhooks/test")
|
||||
def test_webhooks(
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, status, HTTPException
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.theme import SiteTheme
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -16,12 +15,11 @@ def get_all_themes(session: Session = Depends(generate_session)):
|
|||
return db.themes.get_all(session)
|
||||
|
||||
|
||||
@router.post("/themes/create")
|
||||
@router.post("/themes/create", status_code=status.HTTP_201_CREATED)
|
||||
def create_theme(data: SiteTheme, session: Session = Depends(generate_session), current_user=Depends(get_current_user)):
|
||||
""" Creates a site color theme database entry """
|
||||
db.themes.create(session, data.dict())
|
||||
|
||||
return SnackResponse.success("Theme Saved")
|
||||
|
||||
|
||||
@router.get("/themes/{theme_name}")
|
||||
|
@ -30,7 +28,7 @@ def get_single_theme(theme_name: str, session: Session = Depends(generate_sessio
|
|||
return db.themes.get(session, theme_name)
|
||||
|
||||
|
||||
@router.put("/themes/{theme_name}")
|
||||
@router.put("/themes/{theme_name}", status_code=status.HTTP_200_OK)
|
||||
def update_theme(
|
||||
theme_name: str,
|
||||
data: SiteTheme,
|
||||
|
@ -40,12 +38,11 @@ def update_theme(
|
|||
""" Update a theme database entry """
|
||||
db.themes.update(session, theme_name, data.dict())
|
||||
|
||||
return SnackResponse.info(f"Theme Updated: {theme_name}")
|
||||
|
||||
|
||||
@router.delete("/themes/{theme_name}")
|
||||
@router.delete("/themes/{theme_name}", status_code=status.HTTP_200_OK)
|
||||
def delete_theme(theme_name: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user)):
|
||||
""" Deletes theme from the database """
|
||||
db.themes.delete(session, theme_name)
|
||||
|
||||
return SnackResponse.error(f"Theme Deleted: {theme_name}")
|
||||
try:
|
||||
db.themes.delete(session, theme_name)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
|
|
@ -7,7 +7,6 @@ from mealie.core import security
|
|||
from mealie.core.security import authenticate_user
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -28,15 +27,11 @@ def get_token(
|
|||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
access_token = security.create_access_token(dict(sub=email))
|
||||
return SnackResponse.success(
|
||||
"User Successfully Logged In",
|
||||
{"access_token": access_token, "token_type": "bearer"},
|
||||
)
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
|
||||
@router.get("/refresh")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import shutil
|
||||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, File, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, UploadFile, status, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from mealie.core import security
|
||||
from mealie.core.config import app_dirs, settings
|
||||
|
@ -9,7 +9,6 @@ from mealie.core.security import get_password_hash, verify_password
|
|||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import ChangePassword, UserBase, UserIn, UserInDB, UserOut
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -26,7 +25,6 @@ async def create_user(
|
|||
new_user.password = get_password_hash(new_user.password)
|
||||
|
||||
data = db.users.create(session, new_user.dict())
|
||||
return SnackResponse.success(f"User Created: {new_user.full_name}", data)
|
||||
|
||||
|
||||
@router.get("", response_model=list[UserOut])
|
||||
|
@ -35,10 +33,10 @@ async def get_all_users(
|
|||
session: Session = Depends(generate_session),
|
||||
):
|
||||
|
||||
if current_user.admin:
|
||||
return db.users.get_all(session)
|
||||
else:
|
||||
return {"details": "user not authorized"}
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
return db.users.get_all(session)
|
||||
|
||||
|
||||
@router.get("/self", response_model=UserOut)
|
||||
|
@ -68,7 +66,6 @@ async def reset_user_password(
|
|||
new_password = get_password_hash(settings.DEFAULT_PASSWORD)
|
||||
db.users.update_password(session, id, new_password)
|
||||
|
||||
return SnackResponse.success("Users Password Reset")
|
||||
|
||||
|
||||
@router.put("/{id}")
|
||||
|
@ -85,8 +82,7 @@ async def update_user(
|
|||
if current_user.id == id:
|
||||
access_token = security.create_access_token(data=dict(sub=new_data.email))
|
||||
token = {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
return SnackResponse.success("User Updated", token)
|
||||
return token
|
||||
|
||||
|
||||
@router.get("/{id}/image")
|
||||
|
@ -121,10 +117,8 @@ async def update_user_image(
|
|||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(profile_image.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("File uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
||||
|
||||
@router.put("/{id}/password")
|
||||
|
@ -139,12 +133,12 @@ async def update_password(
|
|||
match_passwords = verify_password(password_change.current_password, current_user.password)
|
||||
match_id = current_user.id == id
|
||||
|
||||
if match_passwords and match_id:
|
||||
new_password = get_password_hash(password_change.new_password)
|
||||
db.users.update_password(session, id, new_password)
|
||||
return SnackResponse.success("Password Updated")
|
||||
else:
|
||||
return SnackResponse.error("Existing password does not match")
|
||||
if not ( match_passwords and match_id ):
|
||||
raise HTTPException( status.HTTP_401_UNAUTHORIZED )
|
||||
|
||||
new_password = get_password_hash(password_change.new_password)
|
||||
db.users.update_password(session, id, new_password)
|
||||
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
|
@ -156,8 +150,13 @@ async def delete_user(
|
|||
""" Removes a user from the database. Must be the current user or a super user"""
|
||||
|
||||
if id == 1:
|
||||
return SnackResponse.error("Error! Cannot Delete Super User")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail='SUPER_USER'
|
||||
)
|
||||
|
||||
if current_user.id == id or current_user.admin:
|
||||
db.users.delete(session, id)
|
||||
return SnackResponse.error("User Deleted")
|
||||
try:
|
||||
db.users.delete(session, id)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
|
@ -6,7 +6,6 @@ from mealie.db.db_setup import generate_session
|
|||
from fastapi import APIRouter, Depends
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.sign_up import SignUpIn, SignUpOut, SignUpToken
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserIn, UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
@ -33,18 +32,16 @@ async def create_user_sign_up_key(
|
|||
):
|
||||
""" Generates a Random Token that a new user can sign up with """
|
||||
|
||||
if current_user.admin:
|
||||
sign_up = {
|
||||
"token": str(uuid.uuid1().hex),
|
||||
"name": key_data.name,
|
||||
"admin": key_data.admin,
|
||||
}
|
||||
db_entry = db.sign_ups.create(session, sign_up)
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
return db_entry
|
||||
sign_up = {
|
||||
"token": str(uuid.uuid1().hex),
|
||||
"name": key_data.name,
|
||||
"admin": key_data.admin,
|
||||
}
|
||||
return db.sign_ups.create(session, sign_up)
|
||||
|
||||
else:
|
||||
return {"details": "not authorized"}
|
||||
|
||||
|
||||
@router.post("/{token}")
|
||||
|
@ -58,7 +55,7 @@ async def create_user_with_token(
|
|||
# Validate Token
|
||||
db_entry: SignUpOut = db.sign_ups.get(session, token, limit=1)
|
||||
if not db_entry:
|
||||
return SnackResponse.error("Invalid Token")
|
||||
raise HTTPException( status.HTTP_401_UNAUTHORIZED )
|
||||
|
||||
# Create User
|
||||
new_user.admin = db_entry.admin
|
||||
|
@ -68,9 +65,6 @@ async def create_user_with_token(
|
|||
# DeleteToken
|
||||
db.sign_ups.delete(session, token)
|
||||
|
||||
# Respond
|
||||
return SnackResponse.success(f"User Created: {new_user.full_name}", data)
|
||||
|
||||
|
||||
@router.delete("/{token}")
|
||||
async def delete_token(
|
||||
|
@ -79,8 +73,7 @@ async def delete_token(
|
|||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Removed a token from the database """
|
||||
if current_user.admin:
|
||||
db.sign_ups.delete(session, token)
|
||||
return SnackResponse.error("Sign Up Token Deleted")
|
||||
else:
|
||||
return {"details", "not authorized"}
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
db.sign_ups.delete(session, token)
|
||||
|
|
|
@ -3,7 +3,6 @@ from typing import Optional
|
|||
|
||||
from fastapi import APIRouter, Depends
|
||||
from mealie.routes.deps import validate_file_token
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from starlette.responses import FileResponse
|
||||
|
||||
router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True)
|
||||
|
@ -14,7 +13,7 @@ async def download_file(file_path: Optional[Path] = Depends(validate_file_token)
|
|||
""" Uses a file token obtained by an active user to retrieve a file from the operating
|
||||
system. """
|
||||
print("File Name:", file_path)
|
||||
if file_path.is_file():
|
||||
return FileResponse(file_path, media_type="application/octet-stream", filename=file_path.name)
|
||||
else:
|
||||
return SnackResponse.error("No File Found")
|
||||
if not file_path.is_file():
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
return FileResponse(file_path, media_type="application/octet-stream", filename=file_path.name)
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
class SnackResponse:
|
||||
@staticmethod
|
||||
def _create_response(message: str, type: str, additional_data: dict = None) -> dict:
|
||||
|
||||
snackbar = {"snackbar": {"text": message, "type": type}}
|
||||
|
||||
if additional_data:
|
||||
snackbar.update(additional_data)
|
||||
|
||||
return snackbar
|
||||
|
||||
@staticmethod
|
||||
def success(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "success", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def info(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "info", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def warning(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "warning", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def error(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "error", additional_data)
|
Loading…
Add table
Add a link
Reference in a new issue