From 479900e9126a106ebe12d4a8f970da97e201b554 Mon Sep 17 00:00:00 2001 From: Philipp Fischbeck Date: Sat, 21 May 2022 21:22:02 +0200 Subject: [PATCH] Consolidate frontend types (#1245) --- docs/docs/overrides/api.html | 2 +- frontend/api/_base.ts | 20 ++--- frontend/api/admin/admin-groups.ts | 48 ++---------- frontend/api/admin/admin-tasks.ts | 2 +- frontend/api/admin/admin-users.ts | 2 +- frontend/api/class-interfaces/backups.ts | 34 +-------- frontend/api/class-interfaces/email.ts | 29 +++----- .../api/class-interfaces/group-cookbooks.ts | 2 +- .../class-interfaces/group-event-notifier.ts | 4 +- .../class-interfaces/group-mealplan-rules.ts | 2 +- .../api/class-interfaces/group-mealplan.ts | 27 +------ .../api/class-interfaces/group-migrations.ts | 8 +- .../group-multiple-purpose-labels.ts | 4 +- .../api/class-interfaces/group-reports.ts | 29 +------- .../class-interfaces/group-shopping-lists.ts | 6 +- frontend/api/class-interfaces/group-tasks.ts | 2 +- .../api/class-interfaces/group-webhooks.ts | 15 +--- frontend/api/class-interfaces/groups.ts | 74 ++++--------------- .../class-interfaces/organizer-categories.ts | 2 +- .../api/class-interfaces/organizer-tags.ts | 2 +- .../api/class-interfaces/organizer-tools.ts | 2 +- .../class-interfaces/recipe-bulk-actions.ts | 51 ++----------- frontend/api/class-interfaces/recipe-foods.ts | 2 +- frontend/api/class-interfaces/recipe-units.ts | 2 +- .../recipes/recipe-comments.ts | 6 +- .../class-interfaces/recipes/recipe-share.ts | 16 +--- .../api/class-interfaces/recipes/recipe.ts | 26 ++++--- .../api/class-interfaces/recipes/types.ts | 72 ------------------ frontend/api/class-interfaces/users.ts | 38 ++-------- frontend/api/class-interfaces/utils.ts | 7 +- frontend/api/public/validators.ts | 13 ++-- frontend/api/types/server-task.ts | 8 -- .../Domain/Group/GroupExportData.vue | 3 +- .../Domain/Recipe/RecipeComments.vue | 4 +- .../Domain/Recipe/RecipeContextMenu.vue | 5 +- .../Domain/Recipe/RecipeDialogShare.vue | 4 +- frontend/components/global/ReportTable.vue | 2 +- frontend/composables/use-backups.ts | 8 +- frontend/composables/use-group-cookbooks.ts | 4 +- frontend/composables/use-group-mealplan.ts | 13 ++-- frontend/composables/use-group-webhooks.ts | 4 +- frontend/composables/use-groups.ts | 6 +- frontend/composables/use-validators.ts | 4 +- frontend/pages/admin/background-tasks.vue | 6 +- frontend/pages/admin/manage/groups/_id.vue | 4 +- frontend/pages/admin/manage/groups/index.vue | 4 +- frontend/pages/admin/parser.vue | 14 ++-- frontend/pages/admin/site-settings.vue | 4 +- frontend/pages/group/data/recipes.vue | 2 +- frontend/pages/group/mealplan/planner.vue | 2 +- frontend/pages/group/migrations.vue | 6 +- frontend/pages/recipe/_slug/index.vue | 4 +- .../pages/recipe/_slug/ingredient-parser.vue | 4 +- frontend/pages/user/profile/api-tokens.vue | 3 +- frontend/types/api-types/admin.ts | 18 ++++- frontend/types/api-types/group.ts | 2 +- frontend/types/api-types/meal-plan.ts | 8 +- frontend/types/api-types/recipe.ts | 15 ++-- frontend/types/api-types/response.ts | 2 +- frontend/types/api-types/user.ts | 9 ++- mealie/routes/admin/admin_email.py | 15 +--- mealie/routes/groups/controller_mealplan.py | 4 +- mealie/routes/recipe/bulk_actions.py | 15 ++-- mealie/routes/recipe/recipe_crud_routes.py | 9 +-- mealie/routes/users/api_tokens.py | 12 +-- mealie/schema/admin/__init__.py | 1 + mealie/schema/admin/about.py | 8 +- mealie/schema/admin/email.py | 14 ++++ mealie/schema/group/group.py | 4 +- mealie/schema/meal_plan/new_meal.py | 2 +- mealie/schema/recipe/recipe_bulk_actions.py | 11 --- mealie/schema/recipe/request_helpers.py | 8 ++ mealie/schema/response/validation.py | 2 +- mealie/schema/user/user.py | 17 +++-- 74 files changed, 261 insertions(+), 582 deletions(-) delete mode 100644 frontend/api/class-interfaces/recipes/types.ts delete mode 100644 frontend/api/types/server-task.ts create mode 100644 mealie/schema/admin/email.py diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index c018ff466521..407b674c4516 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/frontend/api/_base.ts b/frontend/api/_base.ts index 660bf041be24..3b3e40c81cca 100644 --- a/frontend/api/_base.ts +++ b/frontend/api/_base.ts @@ -18,33 +18,33 @@ export abstract class BaseAPI { } } -export abstract class BaseCRUDAPI extends BaseAPI implements CrudAPIInterface { +export abstract class BaseCRUDAPI extends BaseAPI implements CrudAPIInterface { abstract baseRoute: string; abstract itemRoute(itemId: string | number): string; async getAll(start = 0, limit = 9999, params = {} as any) { - return await this.requests.get(this.baseRoute, { + return await this.requests.get(this.baseRoute, { params: { start, limit, ...params }, }); } - async createOne(payload: U) { - return await this.requests.post(this.baseRoute, payload); + async createOne(payload: CreateType) { + return await this.requests.post(this.baseRoute, payload); } async getOne(itemId: string | number) { - return await this.requests.get(this.itemRoute(itemId)); + return await this.requests.get(this.itemRoute(itemId)); } - async updateOne(itemId: string | number, payload: T) { - return await this.requests.put(this.itemRoute(itemId), payload); + async updateOne(itemId: string | number, payload: UpdateType) { + return await this.requests.put(this.itemRoute(itemId), payload); } - async patchOne(itemId: string, payload: Partial) { - return await this.requests.patch(this.itemRoute(itemId), payload); + async patchOne(itemId: string, payload: Partial) { + return await this.requests.patch>(this.itemRoute(itemId), payload); } async deleteOne(itemId: string | number) { - return await this.requests.delete(this.itemRoute(itemId)); + return await this.requests.delete(this.itemRoute(itemId)); } } diff --git a/frontend/api/admin/admin-groups.ts b/frontend/api/admin/admin-groups.ts index d8781fc86790..2f87b3c2a98f 100644 --- a/frontend/api/admin/admin-groups.ts +++ b/frontend/api/admin/admin-groups.ts @@ -1,55 +1,19 @@ import { BaseCRUDAPI } from "../_base"; -import { UserOut } from "~/types/api-types/user"; +import { GroupBase, GroupInDB } from "~/types/api-types/user"; +import { GroupAdminUpdate } from "~/types/api-types/group"; const prefix = "/api"; -export interface Token { - name: string; - id: number; - createdAt: Date; -} - -export interface Preferences { - privateGroup: boolean; - firstDayOfWeek: number; - recipePublic: boolean; - recipeShowNutrition: boolean; - recipeShowAssets: boolean; - recipeLandscapeView: boolean; - recipeDisableComments: boolean; - recipeDisableAmount: boolean; - groupId: number; - id: number; -} - -export interface GroupCreate { - name: string; -} - -export interface GroupRead extends GroupCreate { - id: number; - categories: any[]; - webhooks: any[]; - users: UserOut[]; - preferences: Preferences; -} - -export interface AdminGroupUpdate { - name: string; - id: number; - preferences: Preferences; -} - const routes = { adminUsers: `${prefix}/admin/groups`, - adminUsersId: (id: number) => `${prefix}/admin/groups/${id}`, + adminUsersId: (id: string) => `${prefix}/admin/groups/${id}`, }; -export class AdminGroupsApi extends BaseCRUDAPI { +export class AdminGroupsApi extends BaseCRUDAPI { baseRoute: string = routes.adminUsers; itemRoute = routes.adminUsersId; - async updateOne(id: number, payload: AdminGroupUpdate) { + async updateOne(id: string, payload: GroupAdminUpdate) { // TODO: This should probably be a patch request, which isn't offered by the API currently - return await this.requests.put(this.itemRoute(id), payload); + return await this.requests.put(this.itemRoute(id), payload); } } diff --git a/frontend/api/admin/admin-tasks.ts b/frontend/api/admin/admin-tasks.ts index 09e8f0afffd1..6fdd7448867b 100644 --- a/frontend/api/admin/admin-tasks.ts +++ b/frontend/api/admin/admin-tasks.ts @@ -1,5 +1,5 @@ import { BaseAPI } from "../_base"; -import { ServerTask } from "~/api/types/server-task"; +import { ServerTask } from "~/types/api-types/server"; const prefix = "/api"; diff --git a/frontend/api/admin/admin-users.ts b/frontend/api/admin/admin-users.ts index f93eac79a09f..5df7a8287320 100644 --- a/frontend/api/admin/admin-users.ts +++ b/frontend/api/admin/admin-users.ts @@ -8,7 +8,7 @@ const routes = { adminUsersId: (tag: string) => `${prefix}/admin/users/${tag}`, }; -export class AdminUsersApi extends BaseCRUDAPI { +export class AdminUsersApi extends BaseCRUDAPI { baseRoute: string = routes.adminUsers; itemRoute = routes.adminUsersId; } diff --git a/frontend/api/class-interfaces/backups.ts b/frontend/api/class-interfaces/backups.ts index 9f3f08938a89..ab8ddfae47fd 100644 --- a/frontend/api/class-interfaces/backups.ts +++ b/frontend/api/class-interfaces/backups.ts @@ -1,35 +1,5 @@ import { BaseAPI } from "../_base"; - -export interface BackupOptions { - recipes?: boolean; - settings?: boolean; - pages?: boolean; - themes?: boolean; - groups?: boolean; - users?: boolean; - notifications?: boolean; -} - -export interface ImportBackup { - name: string; - options: BackupOptions; -} - -export interface BackupJob { - tag?: string; - options: BackupOptions; - templates?: string[]; -} - -export interface BackupFile { - name: string; - date: string; -} - -export interface AllBackups { - imports: BackupFile[]; - templates: string[]; -} +import { AllBackups, BackupOptions, CreateBackup } from "~/types/api-types/admin"; const prefix = "/api"; @@ -52,7 +22,7 @@ export class BackupAPI extends BaseAPI { /** Generates a backup of the recipe database in json format. */ - async createOne(payload: BackupJob) { + async createOne(payload: CreateBackup) { return await this.requests.post(routes.backupsExportDatabase, payload); } diff --git a/frontend/api/class-interfaces/email.ts b/frontend/api/class-interfaces/email.ts index c6faa96f216d..91607cf93eb7 100644 --- a/frontend/api/class-interfaces/email.ts +++ b/frontend/api/class-interfaces/email.ts @@ -1,4 +1,7 @@ import { BaseAPI } from "../_base"; +import { EmailInitationResponse, EmailInvitation } from "~/types/api-types/group"; +import { ForgotPassword } from "~/types/api-types/user"; +import { EmailTest } from "~/types/api-types/admin"; const routes = { base: "/api/admin/email", @@ -7,30 +10,16 @@ const routes = { invitation: "/api/groups/invitations/email", }; -export interface EmailResponse { - success: boolean; - error: string; -} - -export interface EmailPayload { - email: string; -} - -export interface InvitationEmail { - email: string; - token: string; -} - export class EmailAPI extends BaseAPI { - test(payload: EmailPayload) { - return this.requests.post(routes.base, payload); + test(payload: EmailTest) { + return this.requests.post(routes.base, payload); } - sendInvitation(payload: InvitationEmail) { - return this.requests.post(routes.invitation, payload); + sendInvitation(payload: EmailInvitation) { + return this.requests.post(routes.invitation, payload); } - sendForgotPassword(payload: EmailPayload) { - return this.requests.post(routes.forgotPassword, payload); + sendForgotPassword(payload: ForgotPassword) { + return this.requests.post(routes.forgotPassword, payload); } } diff --git a/frontend/api/class-interfaces/group-cookbooks.ts b/frontend/api/class-interfaces/group-cookbooks.ts index 853c14cff7a9..533a134a6631 100644 --- a/frontend/api/class-interfaces/group-cookbooks.ts +++ b/frontend/api/class-interfaces/group-cookbooks.ts @@ -8,7 +8,7 @@ const routes = { cookbooksId: (id: number) => `${prefix}/groups/cookbooks/${id}`, }; -export class CookbookAPI extends BaseCRUDAPI { +export class CookbookAPI extends BaseCRUDAPI { baseRoute: string = routes.cookbooks; itemRoute = routes.cookbooksId; diff --git a/frontend/api/class-interfaces/group-event-notifier.ts b/frontend/api/class-interfaces/group-event-notifier.ts index 8d0ffa646eab..501baf8648b3 100644 --- a/frontend/api/class-interfaces/group-event-notifier.ts +++ b/frontend/api/class-interfaces/group-event-notifier.ts @@ -1,5 +1,5 @@ import { BaseCRUDAPI } from "../_base"; -import { GroupEventNotifierCreate, GroupEventNotifierOut } from "~/types/api-types/group"; +import { GroupEventNotifierCreate, GroupEventNotifierOut, GroupEventNotifierUpdate } from "~/types/api-types/group"; const prefix = "/api"; @@ -8,7 +8,7 @@ const routes = { eventNotifierId: (id: string | number) => `${prefix}/groups/events/notifications/${id}`, }; -export class GroupEventNotifierApi extends BaseCRUDAPI { +export class GroupEventNotifierApi extends BaseCRUDAPI { baseRoute = routes.eventNotifier; itemRoute = routes.eventNotifierId; diff --git a/frontend/api/class-interfaces/group-mealplan-rules.ts b/frontend/api/class-interfaces/group-mealplan-rules.ts index f4ac4e940ef8..58c13814b36d 100644 --- a/frontend/api/class-interfaces/group-mealplan-rules.ts +++ b/frontend/api/class-interfaces/group-mealplan-rules.ts @@ -8,7 +8,7 @@ const routes = { ruleId: (id: string | number) => `${prefix}/groups/mealplans/rules/${id}`, }; -export class MealPlanRulesApi extends BaseCRUDAPI { +export class MealPlanRulesApi extends BaseCRUDAPI { baseRoute = routes.rule; itemRoute = routes.ruleId; } diff --git a/frontend/api/class-interfaces/group-mealplan.ts b/frontend/api/class-interfaces/group-mealplan.ts index e1543605f62b..02214ba52325 100644 --- a/frontend/api/class-interfaces/group-mealplan.ts +++ b/frontend/api/class-interfaces/group-mealplan.ts @@ -1,5 +1,5 @@ import { BaseCRUDAPI } from "../_base"; -import { CreatRandomEntry } from "~/types/api-types/meal-plan"; +import { CreatePlanEntry, CreateRandomEntry, ReadPlanEntry, UpdatePlanEntry } from "~/types/api-types/meal-plan"; const prefix = "/api"; @@ -9,31 +9,12 @@ const routes = { mealplanId: (id: string | number) => `${prefix}/groups/mealplans/${id}`, }; -type PlanEntryType = "breakfast" | "lunch" | "dinner" | "side"; - -export interface CreateMealPlan { - date: string; - entryType: PlanEntryType; - title: string; - text: string; - recipeId?: string; -} - -export interface UpdateMealPlan extends CreateMealPlan { - id: number; - groupId: number; -} - -export interface MealPlan extends UpdateMealPlan { - recipe: any; -} - -export class MealPlanAPI extends BaseCRUDAPI { +export class MealPlanAPI extends BaseCRUDAPI { baseRoute = routes.mealplan; itemRoute = routes.mealplanId; - async setRandom(payload: CreatRandomEntry) { + async setRandom(payload: CreateRandomEntry) { console.log(payload); - return await this.requests.post(routes.random, payload); + return await this.requests.post(routes.random, payload); } } diff --git a/frontend/api/class-interfaces/group-migrations.ts b/frontend/api/class-interfaces/group-migrations.ts index 58e74d439e71..9f2c1b57f663 100644 --- a/frontend/api/class-interfaces/group-migrations.ts +++ b/frontend/api/class-interfaces/group-migrations.ts @@ -1,13 +1,11 @@ import { BaseAPI } from "../_base"; -import { ReportSummary } from "./group-reports"; +import { ReportSummary } from "~/types/api-types/reports"; +import { SupportedMigrations } from "~/types/api-types/group"; const prefix = "/api"; - -export type SupportedMigration = "nextcloud" | "chowdown" | "mealie_alpha" | "paprika"; - export interface MigrationPayload { addMigrationTag: boolean; - migrationType: SupportedMigration; + migrationType: SupportedMigrations; archive: File; } diff --git a/frontend/api/class-interfaces/group-multiple-purpose-labels.ts b/frontend/api/class-interfaces/group-multiple-purpose-labels.ts index 98623a62153f..5f4299230b10 100644 --- a/frontend/api/class-interfaces/group-multiple-purpose-labels.ts +++ b/frontend/api/class-interfaces/group-multiple-purpose-labels.ts @@ -1,5 +1,5 @@ import { BaseCRUDAPI } from "../_base"; -import { MultiPurposeLabelCreate, MultiPurposeLabelOut } from "~/types/api-types/labels"; +import { MultiPurposeLabelCreate, MultiPurposeLabelOut, MultiPurposeLabelUpdate } from "~/types/api-types/labels"; const prefix = "/api"; @@ -8,7 +8,7 @@ const routes = { labelsId: (id: string | number) => `${prefix}/groups/labels/${id}`, }; -export class MultiPurposeLabelsApi extends BaseCRUDAPI { +export class MultiPurposeLabelsApi extends BaseCRUDAPI { baseRoute = routes.labels; itemRoute = routes.labelsId; } diff --git a/frontend/api/class-interfaces/group-reports.ts b/frontend/api/class-interfaces/group-reports.ts index daf8b3909401..ca6323cc8769 100644 --- a/frontend/api/class-interfaces/group-reports.ts +++ b/frontend/api/class-interfaces/group-reports.ts @@ -1,33 +1,8 @@ import { BaseAPI } from "../_base"; +import { ReportCategory, ReportOut, ReportSummary } from "~/types/api-types/reports"; const prefix = "/api"; -export type ReportCategory = "backup" | "restore" | "migration"; - -export type SummaryStatus = "success" | "failure" | "partial" | "in-progress"; - -export interface ReportEntry { - id: string; - reportId: string; - timestamp: Date; - success: boolean; - message: string; - exception: string; -} - -export interface ReportSummary { - id: string; - timestamp: Date; - category: ReportCategory; - groupId: number; - name: string; - status: SummaryStatus; -} - -export interface Report extends ReportSummary { - entries: ReportEntry[]; -} - const routes = { base: `${prefix}/groups/reports`, getOne: (id: string) => `${prefix}/groups/reports/${id}`, @@ -40,7 +15,7 @@ export class GroupReportsApi extends BaseAPI { } async getOne(id: string) { - return await this.requests.get(routes.getOne(id)); + return await this.requests.get(routes.getOne(id)); } async deleteOne(id: string) { diff --git a/frontend/api/class-interfaces/group-shopping-lists.ts b/frontend/api/class-interfaces/group-shopping-lists.ts index 96be394bbb76..33430de63de0 100644 --- a/frontend/api/class-interfaces/group-shopping-lists.ts +++ b/frontend/api/class-interfaces/group-shopping-lists.ts @@ -4,7 +4,9 @@ import { ShoppingListCreate, ShoppingListItemCreate, ShoppingListItemOut, + ShoppingListItemUpdate, ShoppingListOut, + ShoppingListUpdate, } from "~/types/api-types/group"; const prefix = "/api"; @@ -18,7 +20,7 @@ const routes = { shoppingListItemsId: (id: string) => `${prefix}/groups/shopping/items/${id}`, }; -export class ShoppingListsApi extends BaseCRUDAPI { +export class ShoppingListsApi extends BaseCRUDAPI { baseRoute = routes.shoppingLists; itemRoute = routes.shoppingListsId; @@ -31,7 +33,7 @@ export class ShoppingListsApi extends BaseCRUDAPI { +export class ShoppingListItemsApi extends BaseCRUDAPI { baseRoute = routes.shoppingListItems; itemRoute = routes.shoppingListItemsId; diff --git a/frontend/api/class-interfaces/group-tasks.ts b/frontend/api/class-interfaces/group-tasks.ts index efd070afc130..4c9c8c5b6cdc 100644 --- a/frontend/api/class-interfaces/group-tasks.ts +++ b/frontend/api/class-interfaces/group-tasks.ts @@ -1,5 +1,5 @@ import { BaseAPI } from "../_base"; -import { ServerTask } from "~/api/types/server-task"; +import { ServerTask } from "~/types/api-types/server"; const prefix = "/api"; const routes = { diff --git a/frontend/api/class-interfaces/group-webhooks.ts b/frontend/api/class-interfaces/group-webhooks.ts index 7ba72ded0fcc..c6a472c337bc 100644 --- a/frontend/api/class-interfaces/group-webhooks.ts +++ b/frontend/api/class-interfaces/group-webhooks.ts @@ -1,4 +1,5 @@ import { BaseCRUDAPI } from "../_base"; +import { CreateWebhook, ReadWebhook } from "~/types/api-types/group"; const prefix = "/api"; @@ -7,19 +8,7 @@ const routes = { webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`, }; -export interface CreateGroupWebhook { - enabled: boolean; - name: string; - url: string; - time: string; -} - -export interface GroupWebhook extends CreateGroupWebhook { - id: string; - groupId: string; -} - -export class WebhooksAPI extends BaseCRUDAPI { +export class WebhooksAPI extends BaseCRUDAPI { baseRoute = routes.webhooks; itemRoute = routes.webhooksId; } diff --git a/frontend/api/class-interfaces/groups.ts b/frontend/api/class-interfaces/groups.ts index 1bd4d872f184..d50990045f0f 100644 --- a/frontend/api/class-interfaces/groups.ts +++ b/frontend/api/class-interfaces/groups.ts @@ -1,6 +1,6 @@ import { BaseCRUDAPI } from "../_base"; -import { GroupInDB, UserOut } from "~/types/api-types/user"; -import { GroupStatistics, GroupStorage } from "~/types/api-types/group"; +import { CategoryBase, GroupBase, GroupInDB, UserOut } from "~/types/api-types/user"; +import { CreateInviteToken, GroupAdminUpdate, GroupStatistics, GroupStorage, ReadGroupPreferences, ReadInviteToken, SetPermissions, UpdateGroupPreferences } from "~/types/api-types/group"; const prefix = "/api"; @@ -20,82 +20,34 @@ const routes = { groupsId: (id: string | number) => `${prefix}/admin/groups/${id}`, }; -interface Category { - id: number; - name: string; - slug: string; -} - -export interface CreateGroup { - name: string; -} - -export interface UpdatePreferences { - privateGroup: boolean; - firstDayOfWeek: number; - recipePublic: boolean; - recipeShowNutrition: boolean; - recipeShowAssets: boolean; - recipeLandscapeView: boolean; - recipeDisableComments: boolean; - recipeDisableAmount: boolean; -} - -export interface Preferences extends UpdatePreferences { - id: number; - group_id: number; -} - -export interface Group extends CreateGroup { - id: number; - preferences: Preferences; -} - -export interface CreateInvitation { - uses: number; -} - -export interface Invitation { - group_id: number; - token: string; - uses_left: number; -} - -export interface SetPermissions { - userId: string; - canInvite?: boolean; - canManage?: boolean; - canOrganize?: boolean; -} - -export class GroupAPI extends BaseCRUDAPI { +export class GroupAPI extends BaseCRUDAPI { baseRoute = routes.groups; itemRoute = routes.groupsId; /** Returns the Group Data for the Current User */ async getCurrentUserGroup() { - return await this.requests.get(routes.groupsSelf); + return await this.requests.get(routes.groupsSelf); } async getCategories() { - return await this.requests.get(routes.categories); + return await this.requests.get(routes.categories); } - async setCategories(payload: Category[]) { - return await this.requests.put(routes.categories, payload); + async setCategories(payload: CategoryBase[]) { + return await this.requests.put(routes.categories, payload); } async getPreferences() { - return await this.requests.get(routes.preferences); + return await this.requests.get(routes.preferences); } - async setPreferences(payload: UpdatePreferences) { + async setPreferences(payload: UpdateGroupPreferences) { // TODO: This should probably be a patch request, which isn't offered by the API currently - return await this.requests.put(routes.preferences, payload); + return await this.requests.put(routes.preferences, payload); } - async createInvitation(payload: CreateInvitation) { - return await this.requests.post(routes.invitation, payload); + async createInvitation(payload: CreateInviteToken) { + return await this.requests.post(routes.invitation, payload); } async fetchMembers() { @@ -104,7 +56,7 @@ export class GroupAPI extends BaseCRUDAPI { async setMemberPermissions(payload: SetPermissions) { // TODO: This should probably be a patch request, which isn't offered by the API currently - return await this.requests.put(routes.permissions, payload); + return await this.requests.put(routes.permissions, payload); } async statistics() { diff --git a/frontend/api/class-interfaces/organizer-categories.ts b/frontend/api/class-interfaces/organizer-categories.ts index dba4c6337c9b..be049750a6eb 100644 --- a/frontend/api/class-interfaces/organizer-categories.ts +++ b/frontend/api/class-interfaces/organizer-categories.ts @@ -10,7 +10,7 @@ const routes = { categoriesSlug: (category: string) => `${prefix}/categories/slug/${category}`, }; -export class CategoriesAPI extends BaseCRUDAPI { +export class CategoriesAPI extends BaseCRUDAPI { baseRoute: string = routes.categories; itemRoute = routes.categoriesId; diff --git a/frontend/api/class-interfaces/organizer-tags.ts b/frontend/api/class-interfaces/organizer-tags.ts index 0433a194983b..9d7366ea0540 100644 --- a/frontend/api/class-interfaces/organizer-tags.ts +++ b/frontend/api/class-interfaces/organizer-tags.ts @@ -10,7 +10,7 @@ const routes = { tagsSlug: (tag: string) => `${prefix}/tags/slug/${tag}`, }; -export class TagsAPI extends BaseCRUDAPI { +export class TagsAPI extends BaseCRUDAPI { baseRoute: string = routes.tags; itemRoute = routes.tagsId; diff --git a/frontend/api/class-interfaces/organizer-tools.ts b/frontend/api/class-interfaces/organizer-tools.ts index fbf29fca9836..6dddcb9d63b3 100644 --- a/frontend/api/class-interfaces/organizer-tools.ts +++ b/frontend/api/class-interfaces/organizer-tools.ts @@ -11,7 +11,7 @@ const routes = { toolsSlug: (id: string) => `${prefix}/tools/slug/${id}`, }; -export class ToolsApi extends BaseCRUDAPI { +export class ToolsApi extends BaseCRUDAPI { baseRoute: string = routes.tools; itemRoute = routes.toolsId; diff --git a/frontend/api/class-interfaces/recipe-bulk-actions.ts b/frontend/api/class-interfaces/recipe-bulk-actions.ts index 9c81fd362e68..838ea82564cf 100644 --- a/frontend/api/class-interfaces/recipe-bulk-actions.ts +++ b/frontend/api/class-interfaces/recipe-bulk-actions.ts @@ -1,45 +1,10 @@ import { BaseAPI } from "../_base"; +import { AssignCategories, AssignTags, DeleteRecipes, ExportRecipes } from "~/types/api-types/recipe"; +import { GroupDataExport } from "~/types/api-types/group"; -interface BasePayload { - recipes: string[]; -} - -type exportType = "json"; - +// Many bulk actions return nothing // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface RecipeBulkDelete extends BasePayload {} - -interface RecipeBulkExport extends BasePayload { - exportType: exportType; -} - -interface RecipeBulkCategorize extends BasePayload { - categories: string[]; -} - -interface RecipeBulkTag extends BasePayload { - tags: string[]; -} - -interface BulkActionError { - recipe: string; - error: string; -} - interface BulkActionResponse { - success: boolean; - message: string; - errors: BulkActionError[]; -} - -export interface GroupDataExport { - id: string; - groupId: string; - name: string; - filename: string; - path: string; - size: string; - expires: Date; } const prefix = "/api"; @@ -53,19 +18,19 @@ const routes = { }; export class BulkActionsAPI extends BaseAPI { - async bulkExport(payload: RecipeBulkExport) { + async bulkExport(payload: ExportRecipes) { return await this.requests.post(routes.bulkExport, payload); } - async bulkCategorize(payload: RecipeBulkCategorize) { + async bulkCategorize(payload: AssignCategories) { return await this.requests.post(routes.bulkCategorize, payload); } - async bulkTag(payload: RecipeBulkTag) { + async bulkTag(payload: AssignTags) { return await this.requests.post(routes.bulkTag, payload); } - async bulkDelete(payload: RecipeBulkDelete) { + async bulkDelete(payload: DeleteRecipes) { return await this.requests.post(routes.bulkDelete, payload); } @@ -74,6 +39,6 @@ export class BulkActionsAPI extends BaseAPI { } async purgeExports() { - return await this.requests.delete(routes.purgeExports); + return await this.requests.delete(routes.purgeExports); } } diff --git a/frontend/api/class-interfaces/recipe-foods.ts b/frontend/api/class-interfaces/recipe-foods.ts index 12b4b91169e4..e7c15b5fcb33 100644 --- a/frontend/api/class-interfaces/recipe-foods.ts +++ b/frontend/api/class-interfaces/recipe-foods.ts @@ -9,7 +9,7 @@ const routes = { merge: `${prefix}/foods/merge`, }; -export class FoodAPI extends BaseCRUDAPI { +export class FoodAPI extends BaseCRUDAPI { baseRoute: string = routes.food; itemRoute = routes.foodsFood; diff --git a/frontend/api/class-interfaces/recipe-units.ts b/frontend/api/class-interfaces/recipe-units.ts index 0650f14e60d0..e43cc4042e5f 100644 --- a/frontend/api/class-interfaces/recipe-units.ts +++ b/frontend/api/class-interfaces/recipe-units.ts @@ -9,7 +9,7 @@ const routes = { merge: `${prefix}/units/merge`, }; -export class UnitAPI extends BaseCRUDAPI { +export class UnitAPI extends BaseCRUDAPI { baseRoute: string = routes.unit; itemRoute = routes.unitsUnit; diff --git a/frontend/api/class-interfaces/recipes/recipe-comments.ts b/frontend/api/class-interfaces/recipes/recipe-comments.ts index c942b6c53215..8c9a86a80524 100644 --- a/frontend/api/class-interfaces/recipes/recipe-comments.ts +++ b/frontend/api/class-interfaces/recipes/recipe-comments.ts @@ -1,5 +1,5 @@ -import { RecipeComment, RecipeCommentCreate } from "./types"; import { BaseCRUDAPI } from "~/api/_base"; +import { RecipeCommentCreate, RecipeCommentOut, RecipeCommentUpdate } from "~/types/api-types/recipe"; const prefix = "/api"; @@ -9,11 +9,11 @@ const routes = { commentsId: (id: string) => `${prefix}/comments/${id}`, }; -export class CommentsApi extends BaseCRUDAPI { +export class CommentsApi extends BaseCRUDAPI { baseRoute: string = routes.comment; itemRoute = routes.commentsId; async byRecipe(slug: string) { - return await this.requests.get(routes.byRecipe(slug)); + return await this.requests.get(routes.byRecipe(slug)); } } diff --git a/frontend/api/class-interfaces/recipes/recipe-share.ts b/frontend/api/class-interfaces/recipes/recipe-share.ts index 9ec0f166bf96..01f68654e059 100644 --- a/frontend/api/class-interfaces/recipes/recipe-share.ts +++ b/frontend/api/class-interfaces/recipes/recipe-share.ts @@ -1,4 +1,5 @@ import { BaseCRUDAPI } from "~/api/_base"; +import { RecipeShareToken, RecipeShareTokenCreate } from "~/types/api-types/recipe"; const prefix = "/api"; @@ -7,20 +8,7 @@ const routes = { shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`, }; -export interface RecipeShareTokenCreate { - recipeId: string; - expiresAt?: Date; -} - -export interface RecipeShareToken { - recipeId: string; - id: string; - groupId: number; - expiresAt: string; - createdAt: string; -} - -export class RecipeShareApi extends BaseCRUDAPI { +export class RecipeShareApi extends BaseCRUDAPI { baseRoute: string = routes.shareToken; itemRoute = routes.shareTokenId; } diff --git a/frontend/api/class-interfaces/recipes/recipe.ts b/frontend/api/class-interfaces/recipes/recipe.ts index ebd831db3412..957f37675983 100644 --- a/frontend/api/class-interfaces/recipes/recipe.ts +++ b/frontend/api/class-interfaces/recipes/recipe.ts @@ -1,11 +1,19 @@ -import { CreateAsset, ParsedIngredient, Parser, RecipeZipToken, BulkCreatePayload } from "./types"; import { CommentsApi } from "./recipe-comments"; import { RecipeShareApi } from "./recipe-share"; import { BaseCRUDAPI } from "~/api/_base"; -import { Recipe, CreateRecipe } from "~/types/api-types/recipe"; +import { Recipe, CreateRecipe, RecipeAsset, CreateRecipeByUrlBulk, ParsedIngredient, UpdateImageResponse, RecipeZipTokenResponse } from "~/types/api-types/recipe"; import { ApiRequestInstance } from "~/types/api"; +export type Parser = "nlp" | "brute"; + +export interface CreateAsset { + name: string; + icon: string; + extension: string; + file: File; +} + const prefix = "/api"; const routes = { @@ -31,7 +39,7 @@ const routes = { recipeShareToken: (token: string) => `${prefix}/recipes/shared/${token}`, }; -export class RecipeAPI extends BaseCRUDAPI { +export class RecipeAPI extends BaseCRUDAPI { baseRoute: string = routes.recipesBase; itemRoute = routes.recipesRecipeSlug; @@ -58,7 +66,7 @@ export class RecipeAPI extends BaseCRUDAPI { formData.append("extension", payload.extension); formData.append("icon", payload.icon); - return await this.requests.post(routes.recipesRecipeSlugAssets(recipeSlug), formData); + return await this.requests.post(routes.recipesRecipeSlugAssets(recipeSlug), formData); } updateImage(slug: string, fileObject: File) { @@ -66,11 +74,11 @@ export class RecipeAPI extends BaseCRUDAPI { formData.append("image", fileObject); formData.append("extension", fileObject.name.split(".").pop() ?? ""); - return this.requests.put(routes.recipesRecipeSlugImage(slug), formData); + return this.requests.put(routes.recipesRecipeSlugImage(slug), formData); } updateImagebyURL(slug: string, url: string) { - return this.requests.post(routes.recipesRecipeSlugImage(slug), { url }); + return this.requests.post(routes.recipesRecipeSlugImage(slug), { url }); } async testCreateOneUrl(url: string) { @@ -81,8 +89,8 @@ export class RecipeAPI extends BaseCRUDAPI { return await this.requests.post(routes.recipesCreateUrl, { url, includeTags }); } - async createManyByUrl(payload: BulkCreatePayload) { - return await this.requests.post(routes.recipesCreateUrlBulk, payload); + async createManyByUrl(payload: CreateRecipeByUrlBulk) { + return await this.requests.post(routes.recipesCreateUrlBulk, payload); } async parseIngredients(parser: Parser, ingredients: Array) { @@ -96,7 +104,7 @@ export class RecipeAPI extends BaseCRUDAPI { } async getZipToken(recipeSlug: string) { - return await this.requests.post(routes.recipesRecipeSlugExport(recipeSlug), {}); + return await this.requests.post(routes.recipesRecipeSlugExport(recipeSlug), {}); } getZipRedirectUrl(recipeSlug: string, token: string) { diff --git a/frontend/api/class-interfaces/recipes/types.ts b/frontend/api/class-interfaces/recipes/types.ts deleted file mode 100644 index 29d83a227bae..000000000000 --- a/frontend/api/class-interfaces/recipes/types.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { CreateIngredientFood, CreateIngredientUnit, IngredientFood, IngredientUnit } from "~/types/api-types/recipe"; -import { RecipeCategory, RecipeTag } from "~/types/api-types/user"; - -export type Parser = "nlp" | "brute"; - -export interface Confidence { - average?: number; - comment?: number; - name?: number; - unit?: number; - quantity?: number; - food?: number; -} - -export interface Ingredient { - title?: string; - note?: string; - unit?: IngredientUnit | CreateIngredientUnit; - food?: IngredientFood | CreateIngredientFood; - disableAmount?: boolean; - quantity?: number; - referenceId?: string; -} - -export interface ParsedIngredient { - input: string - confidence: Confidence; - ingredient: Ingredient; -} - -export interface BulkCreateRecipe { - url: string; - categories: RecipeCategory[]; - tags: RecipeTag[]; -} - -export interface BulkCreatePayload { - imports: BulkCreateRecipe[]; -} - -export interface RecipeZipToken { - token: string; -} - -export interface CreateAsset { - name: string; - icon: string; - extension: string; - file: File; -} - -export interface RecipeCommentCreate { - recipeId: string; - text: string; -} - -export interface RecipeCommentUpdate extends RecipeCommentCreate { - id: string; -} - -interface RecipeCommentUser { - id: string; - username: string; - admin: boolean; -} - -export interface RecipeComment extends RecipeCommentUpdate { - createdAt: any; - updatedAt: any; - userId: number; - user: RecipeCommentUser; -} diff --git a/frontend/api/class-interfaces/users.ts b/frontend/api/class-interfaces/users.ts index 5d2ab8c03dc1..e48a1aef74c7 100644 --- a/frontend/api/class-interfaces/users.ts +++ b/frontend/api/class-interfaces/users.ts @@ -1,29 +1,5 @@ import { BaseCRUDAPI } from "../_base"; -import { UserIn, UserOut } from "~/types/api-types/user"; - -// Interfaces - -interface ChangePassword { - currentPassword: string; - newPassword: string; -} - -interface CreateAPIToken { - name: string; -} - -interface ResponseToken { - token: string; -} - -interface PasswordResetPayload { - token: string; - email: string; - password: string; - passwordConfirm: string; -} - -// Code +import { ChangePassword, DeleteTokenResponse, LongLiveTokenIn, LongLiveTokenOut, ResetPassword, UserBase, UserIn, UserOut } from "~/types/api-types/user"; const prefix = "/api"; @@ -43,7 +19,7 @@ const routes = { usersApiTokensTokenId: (token_id: string | number) => `${prefix}/users/api-tokens/${token_id}`, }; -export class UserApi extends BaseCRUDAPI { +export class UserApi extends BaseCRUDAPI { baseRoute: string = routes.users; itemRoute = (itemid: string) => routes.usersId(itemid); @@ -63,12 +39,12 @@ export class UserApi extends BaseCRUDAPI { return await this.requests.put(routes.usersIdPassword(id), changePassword); } - async createAPIToken(tokenName: CreateAPIToken) { - return await this.requests.post(routes.usersApiTokens, tokenName); + async createAPIToken(tokenName: LongLiveTokenIn) { + return await this.requests.post(routes.usersApiTokens, tokenName); } - async deleteAPIToken(tokenId: string | number) { - return await this.requests.delete(routes.usersApiTokensTokenId(tokenId)); + async deleteAPIToken(tokenId: number) { + return await this.requests.delete(routes.usersApiTokensTokenId(tokenId)); } userProfileImage(id: string) { @@ -76,7 +52,7 @@ export class UserApi extends BaseCRUDAPI { return `/api/users/${id}/image`; } - async resetPassword(payload: PasswordResetPayload) { + async resetPassword(payload: ResetPassword) { return await this.requests.post(routes.passwordReset, payload); } } diff --git a/frontend/api/class-interfaces/utils.ts b/frontend/api/class-interfaces/utils.ts index 73b3b874f9d3..882da79f2e1f 100644 --- a/frontend/api/class-interfaces/utils.ts +++ b/frontend/api/class-interfaces/utils.ts @@ -1,14 +1,11 @@ import { BaseAPI } from "../_base"; +import { FileTokenResponse } from "~/types/api-types/response"; const prefix = "/api"; -interface DownloadData { - fileToken: string; -} - export class UtilsAPI extends BaseAPI { async download(url: string) { - const { response } = await this.requests.get(url); + const { response } = await this.requests.get(url); if (!response) { return; diff --git a/frontend/api/public/validators.ts b/frontend/api/public/validators.ts index d20fe752e062..148bcc7a6540 100644 --- a/frontend/api/public/validators.ts +++ b/frontend/api/public/validators.ts @@ -1,8 +1,5 @@ import { BaseAPI } from "../_base"; - -export type Validation = { - valid: boolean; -}; +import { ValidationResponse } from "~/types/api-types/response"; const prefix = "/api"; @@ -15,18 +12,18 @@ const routes = { export class ValidatorsApi extends BaseAPI { async group(name: string) { - return await this.requests.get(routes.group(name)); + return await this.requests.get(routes.group(name)); } async username(name: string) { - return await this.requests.get(routes.user(name)); + return await this.requests.get(routes.user(name)); } async email(email: string) { - return await this.requests.get(routes.email(email)); + return await this.requests.get(routes.email(email)); } async recipe(groupId: string, name: string) { - return await this.requests.get(routes.recipe(groupId, name)); + return await this.requests.get(routes.recipe(groupId, name)); } } diff --git a/frontend/api/types/server-task.ts b/frontend/api/types/server-task.ts deleted file mode 100644 index 18bc3521690c..000000000000 --- a/frontend/api/types/server-task.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface ServerTask { - id: number; - groupId: number; - callback: string; - createdAt: string; - status: string; - log: string; -} diff --git a/frontend/components/Domain/Group/GroupExportData.vue b/frontend/components/Domain/Group/GroupExportData.vue index b1491882f7b6..c7443eff3516 100644 --- a/frontend/components/Domain/Group/GroupExportData.vue +++ b/frontend/components/Domain/Group/GroupExportData.vue @@ -20,7 +20,7 @@ - diff --git a/frontend/components/Domain/Recipe/RecipeComments.vue b/frontend/components/Domain/Recipe/RecipeComments.vue index 56a13e0c5d4f..b47c4c05d0ea 100644 --- a/frontend/components/Domain/Recipe/RecipeComments.vue +++ b/frontend/components/Domain/Recipe/RecipeComments.vue @@ -56,7 +56,7 @@ \ No newline at end of file + diff --git a/frontend/pages/admin/manage/groups/_id.vue b/frontend/pages/admin/manage/groups/_id.vue index 6c4c79207365..9589aa04cd56 100644 --- a/frontend/pages/admin/manage/groups/_id.vue +++ b/frontend/pages/admin/manage/groups/_id.vue @@ -28,8 +28,8 @@ import { defineComponent, useRoute, onMounted, ref } from "@nuxtjs/composition-a import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue"; import { useAdminApi } from "~/composables/api"; import { alert } from "~/composables/use-toast"; +import { GroupInDB } from "~/types/api-types/user"; import { VForm } from "~/types/vuetify"; -import { GroupRead } from "~/api/admin/admin-groups"; export default defineComponent({ components: { @@ -48,7 +48,7 @@ export default defineComponent({ const adminApi = useAdminApi(); - const group = ref(null); + const group = ref(null); const userError = ref(false); diff --git a/frontend/pages/admin/manage/groups/index.vue b/frontend/pages/admin/manage/groups/index.vue index f7d93936b352..202abb080335 100644 --- a/frontend/pages/admin/manage/groups/index.vue +++ b/frontend/pages/admin/manage/groups/index.vue @@ -71,9 +71,9 @@ - + \ No newline at end of file + diff --git a/frontend/pages/admin/site-settings.vue b/frontend/pages/admin/site-settings.vue index 0b369200f160..cc2b0c578ae5 100644 --- a/frontend/pages/admin/site-settings.vue +++ b/frontend/pages/admin/site-settings.vue @@ -259,7 +259,7 @@ export default defineComponent({ const { data } = await adminApi.about.checkApp(); if (data) { - appConfig.value = data; + appConfig.value = { ...data, isSiteSecure: false}; } appConfig.value.isSiteSecure = isLocalHostOrHttps(); @@ -323,7 +323,7 @@ export default defineComponent({ if (data.success) { state.success = true; } else { - state.error = data.error; + state.error = data.error ?? ""; state.success = false; } } diff --git a/frontend/pages/group/data/recipes.vue b/frontend/pages/group/data/recipes.vue index eacda1572c1d..db3a3b3c0299 100644 --- a/frontend/pages/group/data/recipes.vue +++ b/frontend/pages/group/data/recipes.vue @@ -154,7 +154,7 @@ import { useUserApi } from "~/composables/api"; import { useRecipes, allRecipes } from "~/composables/recipes"; import { Recipe } from "~/types/api-types/recipe"; import GroupExportData from "~/components/Domain/Group/GroupExportData.vue"; -import { GroupDataExport } from "~/api/class-interfaces/recipe-bulk-actions"; +import { GroupDataExport } from "~/types/api-types/group"; import { MenuItem } from "~/components/global/BaseOverflowButton.vue"; const MODES = { diff --git a/frontend/pages/group/mealplan/planner.vue b/frontend/pages/group/mealplan/planner.vue index 7acaf1bfffc8..86ba1defe68f 100644 --- a/frontend/pages/group/mealplan/planner.vue +++ b/frontend/pages/group/mealplan/planner.vue @@ -346,7 +346,7 @@ export default defineComponent({ date: "", title: "", text: "", - recipeId: undefined as number | undefined, + recipeId: undefined as string | undefined, entryType: "dinner" as PlanEntryType, }); diff --git a/frontend/pages/group/migrations.vue b/frontend/pages/group/migrations.vue index 763fdd2cc7c1..ac5800993ec5 100644 --- a/frontend/pages/group/migrations.vue +++ b/frontend/pages/group/migrations.vue @@ -66,10 +66,10 @@ - diff --git a/frontend/types/api-types/admin.ts b/frontend/types/api-types/admin.ts index 9b00e3d161b0..106646efea2a 100644 --- a/frontend/types/api-types/admin.ts +++ b/frontend/types/api-types/admin.ts @@ -50,10 +50,10 @@ export interface BackupOptions { notifications?: boolean; } export interface CheckAppConfig { - emailReady?: boolean; - ldapReady?: boolean; - baseUrlSet?: boolean; - isUpToDate?: boolean; + emailReady: boolean; + ldapReady: boolean; + baseUrlSet: boolean; + isUpToDate: boolean; } export interface ChowdownURL { url: string; @@ -174,6 +174,16 @@ export interface CustomPageOut { export interface DockerVolumeText { text: string; } +export interface EmailReady { + ready: boolean; +} +export interface EmailSuccess { + success: boolean; + error?: string; +} +export interface EmailTest { + email: string; +} export interface GroupImport { name: string; status: boolean; diff --git a/frontend/types/api-types/group.ts b/frontend/types/api-types/group.ts index 1fed05ce8b82..a65627053718 100644 --- a/frontend/types/api-types/group.ts +++ b/frontend/types/api-types/group.ts @@ -41,7 +41,7 @@ export interface EmailInvitation { export interface GroupAdminUpdate { id: string; name: string; - preferences: UpdateGroupPreferences; + preferences?: UpdateGroupPreferences; } export interface UpdateGroupPreferences { privateGroup?: boolean; diff --git a/frontend/types/api-types/meal-plan.ts b/frontend/types/api-types/meal-plan.ts index 9aa07b8ca7fa..a16f0551bf37 100644 --- a/frontend/types/api-types/meal-plan.ts +++ b/frontend/types/api-types/meal-plan.ts @@ -14,10 +14,6 @@ export interface Category { name: string; slug: string; } -export interface CreatRandomEntry { - date: string; - entryType?: PlanEntryType & string; -} export interface CreatePlanEntry { date: string; entryType?: PlanEntryType & string; @@ -25,6 +21,10 @@ export interface CreatePlanEntry { text?: string; recipeId?: string; } +export interface CreateRandomEntry { + date: string; + entryType?: PlanEntryType & string; +} export interface ListItem { title?: string; text?: string; diff --git a/frontend/types/api-types/recipe.ts b/frontend/types/api-types/recipe.ts index 7016b2a68a0e..038d748b941a 100644 --- a/frontend/types/api-types/recipe.ts +++ b/frontend/types/api-types/recipe.ts @@ -26,15 +26,6 @@ export interface TagBase { id: string; slug: string; } -export interface BulkActionError { - recipe: string; - error: string; -} -export interface BulkActionsResponse { - success: boolean; - message: string; - errors?: BulkActionError[]; -} export interface CategoryIn { name: string; } @@ -335,6 +326,9 @@ export interface RecipeToolSave { onHand?: boolean; groupId: string; } +export interface RecipeZipTokenResponse { + token: string; +} export interface SaveIngredientFood { name: string; description?: string; @@ -373,3 +367,6 @@ export interface UnitFoodBase { name: string; description?: string; } +export interface UpdateImageResponse { + image: string; +} diff --git a/frontend/types/api-types/response.ts b/frontend/types/api-types/response.ts index 83e53b52d590..8e1cb0f5d0a6 100644 --- a/frontend/types/api-types/response.ts +++ b/frontend/types/api-types/response.ts @@ -18,5 +18,5 @@ export interface SuccessResponse { error?: boolean; } export interface ValidationResponse { - valid?: boolean; + valid: boolean; } diff --git a/frontend/types/api-types/user.ts b/frontend/types/api-types/user.ts index 4ac866de03e7..af9ec82671b9 100644 --- a/frontend/types/api-types/user.ts +++ b/frontend/types/api-types/user.ts @@ -31,6 +31,9 @@ export interface CreateUserRegistration { seedData?: boolean; locale?: string; } +export interface DeleteTokenResponse { + tokenDelete: string; +} export interface ForgotPassword { email: string; } @@ -62,9 +65,7 @@ export interface UserOut { cacheKey: string; } export interface LongLiveTokenOut { - name: string; - id: number; - createdAt: string; + token: string; } export interface ReadGroupPreferences { privateGroup?: boolean; @@ -78,7 +79,7 @@ export interface ReadGroupPreferences { groupId: string; id: string; } -export interface LoingLiveTokenIn { +export interface LongLiveTokenIn { name: string; } export interface LongLiveTokenInDB { diff --git a/mealie/routes/admin/admin_email.py b/mealie/routes/admin/admin_email.py index d8f8e8eda96c..a80a25a9af70 100644 --- a/mealie/routes/admin/admin_email.py +++ b/mealie/routes/admin/admin_email.py @@ -1,25 +1,12 @@ from fastapi import APIRouter from mealie.routes._base import BaseAdminController, controller -from mealie.schema._mealie import MealieModel +from mealie.schema.admin.email import EmailReady, EmailSuccess, EmailTest from mealie.services.email import EmailService router = APIRouter(prefix="/email") -class EmailReady(MealieModel): - ready: bool - - -class EmailSuccess(MealieModel): - success: bool - error: str = None - - -class EmailTest(MealieModel): - email: str - - @controller(router) class AdminEmailController(BaseAdminController): @router.get("", response_model=EmailReady) diff --git a/mealie/routes/groups/controller_mealplan.py b/mealie/routes/groups/controller_mealplan.py index 49bbb0f471cc..6e00ac1884b6 100644 --- a/mealie/routes/groups/controller_mealplan.py +++ b/mealie/routes/groups/controller_mealplan.py @@ -9,7 +9,7 @@ from mealie.routes._base import BaseUserController, controller from mealie.routes._base.mixins import HttpRepo from mealie.schema import mapper from mealie.schema.meal_plan import CreatePlanEntry, ReadPlanEntry, SavePlanEntry, UpdatePlanEntry -from mealie.schema.meal_plan.new_meal import CreatRandomEntry +from mealie.schema.meal_plan.new_meal import CreateRandomEntry from mealie.schema.meal_plan.plan_rules import PlanRulesDay from mealie.schema.recipe.recipe import Recipe from mealie.schema.response.responses import ErrorResponse @@ -42,7 +42,7 @@ class GroupMealplanController(BaseUserController): return self.repo.get_today(group_id=self.group_id) @router.post("/random", response_model=ReadPlanEntry) - def create_random_meal(self, data: CreatRandomEntry): + def create_random_meal(self, data: CreateRandomEntry): """ create_random_meal is a route that provides the randomized funcitonality for mealplaners. It operates by following the rules setout in the Groups mealplan settings. If not settings diff --git a/mealie/routes/recipe/bulk_actions.py b/mealie/routes/recipe/bulk_actions.py index 50c932f770a9..f698590d5802 100644 --- a/mealie/routes/recipe/bulk_actions.py +++ b/mealie/routes/recipe/bulk_actions.py @@ -7,13 +7,7 @@ from mealie.core.dependencies.dependencies import temporary_zip_path from mealie.core.security import create_file_token from mealie.routes._base import BaseUserController, controller from mealie.schema.group.group_exports import GroupDataExport -from mealie.schema.recipe.recipe_bulk_actions import ( - AssignCategories, - AssignTags, - BulkActionsResponse, - DeleteRecipes, - ExportRecipes, -) +from mealie.schema.recipe.recipe_bulk_actions import AssignCategories, AssignTags, DeleteRecipes, ExportRecipes from mealie.schema.response.responses import SuccessResponse from mealie.services.recipe.recipe_bulk_service import RecipeBulkActionsService @@ -26,15 +20,16 @@ class RecipeBulkActionsController(BaseUserController): def service(self) -> RecipeBulkActionsService: return RecipeBulkActionsService(self.repos, self.user, self.group) - @router.post("/tag", response_model=BulkActionsResponse) + # TODO Should these actions return some success response? + @router.post("/tag") def bulk_tag_recipes(self, tag_data: AssignTags): self.service.assign_tags(tag_data.recipes, tag_data.tags) - @router.post("/categorize", response_model=BulkActionsResponse) + @router.post("/categorize") def bulk_categorize_recipes(self, assign_cats: AssignCategories): self.service.assign_categories(assign_cats.recipes, assign_cats.categories) - @router.post("/delete", response_model=BulkActionsResponse) + @router.post("/delete") def bulk_delete_recipes(self, delete_recipes: DeleteRecipes): self.service.delete_recipes(delete_recipes.recipes) diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index 61bf83822010..44999edef838 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -27,6 +27,7 @@ from mealie.schema.recipe import Recipe, RecipeImageTypes, ScrapeRecipe from mealie.schema.recipe.recipe import CreateRecipe, CreateRecipeByUrlBulk, RecipeSummary from mealie.schema.recipe.recipe_asset import RecipeAsset from mealie.schema.recipe.recipe_scraper import ScrapeRecipeTest +from mealie.schema.recipe.request_helpers import RecipeZipTokenResponse, UpdateImageResponse from mealie.schema.response.responses import ErrorResponse from mealie.schema.server.tasks import ServerTaskNames from mealie.services import urls @@ -59,10 +60,6 @@ class RecipeGetAll(GetAll): load_food: bool = False -class UpdateImageResponse(BaseModel): - image: str - - class FormatResponse(BaseModel): jjson: list[str] = Field(..., alias="json") zip: list[str] @@ -81,10 +78,10 @@ class RecipeExportController(BaseRecipeController): def get_recipe_formats_and_templates(self): return TemplateService().templates - @router_exports.post("/{slug}/exports") + @router_exports.post("/{slug}/exports", response_model=RecipeZipTokenResponse) def get_recipe_zip_token(self, slug: str): """Generates a recipe zip token to be used to download a recipe as a zip file""" - return {"token": create_recipe_slug_token(slug)} + return RecipeZipTokenResponse(token=create_recipe_slug_token(slug)) @router_exports.get("/{slug}/exports", response_class=FileResponse) def get_recipe_as_format(self, slug: str, template_name: str, temp_dir=Depends(temporary_dir)): diff --git a/mealie/routes/users/api_tokens.py b/mealie/routes/users/api_tokens.py index b65d3dc4bc27..0191f2598e02 100644 --- a/mealie/routes/users/api_tokens.py +++ b/mealie/routes/users/api_tokens.py @@ -5,17 +5,17 @@ from fastapi import HTTPException, status from mealie.core.security import create_access_token from mealie.routes._base import BaseUserController, controller from mealie.routes._base.routers import UserAPIRouter -from mealie.schema.user import CreateToken, LoingLiveTokenIn, LongLiveTokenInDB +from mealie.schema.user import CreateToken, DeleteTokenResponse, LongLiveTokenIn, LongLiveTokenInDB, LongLiveTokenOut router = UserAPIRouter(prefix="/users", tags=["Users: Tokens"]) @controller(router) class UserApiTokensController(BaseUserController): - @router.post("/api-tokens", status_code=status.HTTP_201_CREATED) + @router.post("/api-tokens", status_code=status.HTTP_201_CREATED, response_model=LongLiveTokenOut) def create_api_token( self, - token_name: LoingLiveTokenIn, + token_name: LongLiveTokenIn, ): """Create api_token in the Database""" @@ -33,9 +33,9 @@ class UserApiTokensController(BaseUserController): new_token_in_db = self.repos.api_tokens.create(token_model) if new_token_in_db: - return {"token": token} + return LongLiveTokenOut(token=token) - @router.delete("/api-tokens/{token_id}") + @router.delete("/api-tokens/{token_id}", response_model=DeleteTokenResponse) def delete_api_token(self, token_id: int): """Delete api_token from the Database""" token: LongLiveTokenInDB = self.repos.api_tokens.get(token_id) @@ -45,6 +45,6 @@ class UserApiTokensController(BaseUserController): if token.user.email == self.user.email: deleted_token = self.repos.api_tokens.delete(token_id) - return {"token_delete": deleted_token.name} + return DeleteTokenResponse(token_delete=deleted_token.name) else: raise HTTPException(status.HTTP_403_FORBIDDEN) diff --git a/mealie/schema/admin/__init__.py b/mealie/schema/admin/__init__.py index 7587c29e22ed..21eaeeb13b17 100644 --- a/mealie/schema/admin/__init__.py +++ b/mealie/schema/admin/__init__.py @@ -1,6 +1,7 @@ # GENERATED CODE - DO NOT MODIFY BY HAND from .about import * from .backup import * +from .email import * from .maintenance import * from .migration import * from .restore import * diff --git a/mealie/schema/admin/about.py b/mealie/schema/admin/about.py index edaeb71dfdff..68b644f7e34c 100644 --- a/mealie/schema/admin/about.py +++ b/mealie/schema/admin/about.py @@ -28,10 +28,10 @@ class AdminAboutInfo(AppInfo): class CheckAppConfig(MealieModel): - email_ready: bool = False - ldap_ready: bool = False - base_url_set: bool = False - is_up_to_date: bool = False + email_ready: bool + ldap_ready: bool + base_url_set: bool + is_up_to_date: bool class DockerVolumeText(MealieModel): diff --git a/mealie/schema/admin/email.py b/mealie/schema/admin/email.py new file mode 100644 index 000000000000..1f1a7180b6b3 --- /dev/null +++ b/mealie/schema/admin/email.py @@ -0,0 +1,14 @@ +from mealie.schema._mealie import MealieModel + + +class EmailReady(MealieModel): + ready: bool + + +class EmailSuccess(MealieModel): + success: bool + error: str = None + + +class EmailTest(MealieModel): + email: str diff --git a/mealie/schema/group/group.py b/mealie/schema/group/group.py index fe83f7b13e98..6f8d39cf12d0 100644 --- a/mealie/schema/group/group.py +++ b/mealie/schema/group/group.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import UUID4 from mealie.schema._mealie import MealieModel @@ -8,4 +10,4 @@ from .group_preferences import UpdateGroupPreferences class GroupAdminUpdate(MealieModel): id: UUID4 name: str - preferences: UpdateGroupPreferences + preferences: Optional[UpdateGroupPreferences] = None diff --git a/mealie/schema/meal_plan/new_meal.py b/mealie/schema/meal_plan/new_meal.py index 405e26f1f810..0fa29e03f93b 100644 --- a/mealie/schema/meal_plan/new_meal.py +++ b/mealie/schema/meal_plan/new_meal.py @@ -16,7 +16,7 @@ class PlanEntryType(str, Enum): side = "side" -class CreatRandomEntry(MealieModel): +class CreateRandomEntry(MealieModel): date: date entry_type: PlanEntryType = PlanEntryType.dinner diff --git a/mealie/schema/recipe/recipe_bulk_actions.py b/mealie/schema/recipe/recipe_bulk_actions.py index 9a1b003a4f24..f5a90cc14b4c 100644 --- a/mealie/schema/recipe/recipe_bulk_actions.py +++ b/mealie/schema/recipe/recipe_bulk_actions.py @@ -26,14 +26,3 @@ class AssignTags(ExportBase): class DeleteRecipes(ExportBase): pass - - -class BulkActionError(MealieModel): - recipe: str - error: str - - -class BulkActionsResponse(MealieModel): - success: bool - message: str - errors: list[BulkActionError] = [] diff --git a/mealie/schema/recipe/request_helpers.py b/mealie/schema/recipe/request_helpers.py index 16e5ca2c7f69..960b8faae2d5 100644 --- a/mealie/schema/recipe/request_helpers.py +++ b/mealie/schema/recipe/request_helpers.py @@ -12,3 +12,11 @@ class RecipeSlug(MealieModel): class SlugResponse(BaseModel): class Config: schema_extra = {"example": "adult-mac-and-cheese"} + + +class UpdateImageResponse(BaseModel): + image: str + + +class RecipeZipTokenResponse(BaseModel): + token: str diff --git a/mealie/schema/response/validation.py b/mealie/schema/response/validation.py index 882725d193d8..93374c68936a 100644 --- a/mealie/schema/response/validation.py +++ b/mealie/schema/response/validation.py @@ -2,4 +2,4 @@ from pydantic import BaseModel class ValidationResponse(BaseModel): - valid: bool = False + valid: bool diff --git a/mealie/schema/user/user.py b/mealie/schema/user/user.py index a0c3256ddde9..a26dc9960cb6 100644 --- a/mealie/schema/user/user.py +++ b/mealie/schema/user/user.py @@ -1,4 +1,3 @@ -from datetime import datetime from pathlib import Path from typing import Any, Optional from uuid import UUID @@ -18,19 +17,18 @@ from ..recipe import CategoryBase settings = get_app_settings() -class LoingLiveTokenIn(MealieModel): +class LongLiveTokenIn(MealieModel): name: str -class LongLiveTokenOut(LoingLiveTokenIn): - id: int - created_at: datetime +class LongLiveTokenOut(MealieModel): + token: str class Config: orm_mode = True -class CreateToken(LoingLiveTokenIn): +class CreateToken(LongLiveTokenIn): user_id: UUID4 token: str @@ -38,6 +36,13 @@ class CreateToken(LoingLiveTokenIn): orm_mode = True +class DeleteTokenResponse(MealieModel): + token_delete: str + + class Config: + orm_mode = True + + class ChangePassword(MealieModel): current_password: str new_password: str