Consolidate frontend types (#1245)

This commit is contained in:
Philipp Fischbeck 2022-05-21 21:22:02 +02:00 committed by GitHub
parent 6a88a59981
commit 479900e912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 261 additions and 582 deletions

File diff suppressed because one or more lines are too long

View File

@ -18,33 +18,33 @@ export abstract class BaseAPI {
} }
} }
export abstract class BaseCRUDAPI<T, U> extends BaseAPI implements CrudAPIInterface { export abstract class BaseCRUDAPI<CreateType, ReadType, UpdateType=CreateType> extends BaseAPI implements CrudAPIInterface {
abstract baseRoute: string; abstract baseRoute: string;
abstract itemRoute(itemId: string | number): string; abstract itemRoute(itemId: string | number): string;
async getAll(start = 0, limit = 9999, params = {} as any) { async getAll(start = 0, limit = 9999, params = {} as any) {
return await this.requests.get<T[]>(this.baseRoute, { return await this.requests.get<ReadType[]>(this.baseRoute, {
params: { start, limit, ...params }, params: { start, limit, ...params },
}); });
} }
async createOne(payload: U) { async createOne(payload: CreateType) {
return await this.requests.post<T>(this.baseRoute, payload); return await this.requests.post<ReadType>(this.baseRoute, payload);
} }
async getOne(itemId: string | number) { async getOne(itemId: string | number) {
return await this.requests.get<T>(this.itemRoute(itemId)); return await this.requests.get<ReadType>(this.itemRoute(itemId));
} }
async updateOne(itemId: string | number, payload: T) { async updateOne(itemId: string | number, payload: UpdateType) {
return await this.requests.put<T>(this.itemRoute(itemId), payload); return await this.requests.put<ReadType, UpdateType>(this.itemRoute(itemId), payload);
} }
async patchOne(itemId: string, payload: Partial<T>) { async patchOne(itemId: string, payload: Partial<UpdateType>) {
return await this.requests.patch<T>(this.itemRoute(itemId), payload); return await this.requests.patch<ReadType, Partial<UpdateType>>(this.itemRoute(itemId), payload);
} }
async deleteOne(itemId: string | number) { async deleteOne(itemId: string | number) {
return await this.requests.delete<T>(this.itemRoute(itemId)); return await this.requests.delete<ReadType>(this.itemRoute(itemId));
} }
} }

View File

@ -1,55 +1,19 @@
import { BaseCRUDAPI } from "../_base"; 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"; 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 = { const routes = {
adminUsers: `${prefix}/admin/groups`, adminUsers: `${prefix}/admin/groups`,
adminUsersId: (id: number) => `${prefix}/admin/groups/${id}`, adminUsersId: (id: string) => `${prefix}/admin/groups/${id}`,
}; };
export class AdminGroupsApi extends BaseCRUDAPI<GroupRead, GroupCreate> { export class AdminGroupsApi extends BaseCRUDAPI<GroupBase, GroupInDB, GroupAdminUpdate> {
baseRoute: string = routes.adminUsers; baseRoute: string = routes.adminUsers;
itemRoute = routes.adminUsersId; 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 // TODO: This should probably be a patch request, which isn't offered by the API currently
return await this.requests.put<GroupRead, AdminGroupUpdate>(this.itemRoute(id), payload); return await this.requests.put<GroupInDB, GroupAdminUpdate>(this.itemRoute(id), payload);
} }
} }

View File

@ -1,5 +1,5 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { ServerTask } from "~/api/types/server-task"; import { ServerTask } from "~/types/api-types/server";
const prefix = "/api"; const prefix = "/api";

View File

@ -8,7 +8,7 @@ const routes = {
adminUsersId: (tag: string) => `${prefix}/admin/users/${tag}`, adminUsersId: (tag: string) => `${prefix}/admin/users/${tag}`,
}; };
export class AdminUsersApi extends BaseCRUDAPI<UserOut, UserIn> { export class AdminUsersApi extends BaseCRUDAPI<UserIn, UserOut, UserOut> {
baseRoute: string = routes.adminUsers; baseRoute: string = routes.adminUsers;
itemRoute = routes.adminUsersId; itemRoute = routes.adminUsersId;
} }

View File

@ -1,35 +1,5 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { AllBackups, BackupOptions, CreateBackup } from "~/types/api-types/admin";
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[];
}
const prefix = "/api"; const prefix = "/api";
@ -52,7 +22,7 @@ export class BackupAPI extends BaseAPI {
/** Generates a backup of the recipe database in json format. /** 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); return await this.requests.post(routes.backupsExportDatabase, payload);
} }

View File

@ -1,4 +1,7 @@
import { BaseAPI } from "../_base"; 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 = { const routes = {
base: "/api/admin/email", base: "/api/admin/email",
@ -7,30 +10,16 @@ const routes = {
invitation: "/api/groups/invitations/email", 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 { export class EmailAPI extends BaseAPI {
test(payload: EmailPayload) { test(payload: EmailTest) {
return this.requests.post<EmailResponse>(routes.base, payload); return this.requests.post<EmailInitationResponse>(routes.base, payload);
} }
sendInvitation(payload: InvitationEmail) { sendInvitation(payload: EmailInvitation) {
return this.requests.post<EmailResponse>(routes.invitation, payload); return this.requests.post<EmailInitationResponse>(routes.invitation, payload);
} }
sendForgotPassword(payload: EmailPayload) { sendForgotPassword(payload: ForgotPassword) {
return this.requests.post<EmailResponse>(routes.forgotPassword, payload); return this.requests.post<EmailInitationResponse>(routes.forgotPassword, payload);
} }
} }

View File

@ -8,7 +8,7 @@ const routes = {
cookbooksId: (id: number) => `${prefix}/groups/cookbooks/${id}`, cookbooksId: (id: number) => `${prefix}/groups/cookbooks/${id}`,
}; };
export class CookbookAPI extends BaseCRUDAPI<RecipeCookBook, CreateCookBook> { export class CookbookAPI extends BaseCRUDAPI<CreateCookBook, RecipeCookBook, UpdateCookBook> {
baseRoute: string = routes.cookbooks; baseRoute: string = routes.cookbooks;
itemRoute = routes.cookbooksId; itemRoute = routes.cookbooksId;

View File

@ -1,5 +1,5 @@
import { BaseCRUDAPI } from "../_base"; import { BaseCRUDAPI } from "../_base";
import { GroupEventNotifierCreate, GroupEventNotifierOut } from "~/types/api-types/group"; import { GroupEventNotifierCreate, GroupEventNotifierOut, GroupEventNotifierUpdate } from "~/types/api-types/group";
const prefix = "/api"; const prefix = "/api";
@ -8,7 +8,7 @@ const routes = {
eventNotifierId: (id: string | number) => `${prefix}/groups/events/notifications/${id}`, eventNotifierId: (id: string | number) => `${prefix}/groups/events/notifications/${id}`,
}; };
export class GroupEventNotifierApi extends BaseCRUDAPI<GroupEventNotifierOut, GroupEventNotifierCreate> { export class GroupEventNotifierApi extends BaseCRUDAPI<GroupEventNotifierCreate, GroupEventNotifierOut, GroupEventNotifierUpdate> {
baseRoute = routes.eventNotifier; baseRoute = routes.eventNotifier;
itemRoute = routes.eventNotifierId; itemRoute = routes.eventNotifierId;

View File

@ -8,7 +8,7 @@ const routes = {
ruleId: (id: string | number) => `${prefix}/groups/mealplans/rules/${id}`, ruleId: (id: string | number) => `${prefix}/groups/mealplans/rules/${id}`,
}; };
export class MealPlanRulesApi extends BaseCRUDAPI<PlanRulesOut, PlanRulesCreate> { export class MealPlanRulesApi extends BaseCRUDAPI<PlanRulesCreate, PlanRulesOut> {
baseRoute = routes.rule; baseRoute = routes.rule;
itemRoute = routes.ruleId; itemRoute = routes.ruleId;
} }

View File

@ -1,5 +1,5 @@
import { BaseCRUDAPI } from "../_base"; 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"; const prefix = "/api";
@ -9,31 +9,12 @@ const routes = {
mealplanId: (id: string | number) => `${prefix}/groups/mealplans/${id}`, mealplanId: (id: string | number) => `${prefix}/groups/mealplans/${id}`,
}; };
type PlanEntryType = "breakfast" | "lunch" | "dinner" | "side"; export class MealPlanAPI extends BaseCRUDAPI<CreatePlanEntry, ReadPlanEntry, UpdatePlanEntry> {
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<MealPlan, CreateMealPlan> {
baseRoute = routes.mealplan; baseRoute = routes.mealplan;
itemRoute = routes.mealplanId; itemRoute = routes.mealplanId;
async setRandom(payload: CreatRandomEntry) { async setRandom(payload: CreateRandomEntry) {
console.log(payload); console.log(payload);
return await this.requests.post<MealPlan>(routes.random, payload); return await this.requests.post<ReadPlanEntry>(routes.random, payload);
} }
} }

View File

@ -1,13 +1,11 @@
import { BaseAPI } from "../_base"; 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"; const prefix = "/api";
export type SupportedMigration = "nextcloud" | "chowdown" | "mealie_alpha" | "paprika";
export interface MigrationPayload { export interface MigrationPayload {
addMigrationTag: boolean; addMigrationTag: boolean;
migrationType: SupportedMigration; migrationType: SupportedMigrations;
archive: File; archive: File;
} }

View File

@ -1,5 +1,5 @@
import { BaseCRUDAPI } from "../_base"; import { BaseCRUDAPI } from "../_base";
import { MultiPurposeLabelCreate, MultiPurposeLabelOut } from "~/types/api-types/labels"; import { MultiPurposeLabelCreate, MultiPurposeLabelOut, MultiPurposeLabelUpdate } from "~/types/api-types/labels";
const prefix = "/api"; const prefix = "/api";
@ -8,7 +8,7 @@ const routes = {
labelsId: (id: string | number) => `${prefix}/groups/labels/${id}`, labelsId: (id: string | number) => `${prefix}/groups/labels/${id}`,
}; };
export class MultiPurposeLabelsApi extends BaseCRUDAPI<MultiPurposeLabelOut, MultiPurposeLabelCreate> { export class MultiPurposeLabelsApi extends BaseCRUDAPI<MultiPurposeLabelCreate, MultiPurposeLabelOut, MultiPurposeLabelUpdate> {
baseRoute = routes.labels; baseRoute = routes.labels;
itemRoute = routes.labelsId; itemRoute = routes.labelsId;
} }

View File

@ -1,33 +1,8 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { ReportCategory, ReportOut, ReportSummary } from "~/types/api-types/reports";
const prefix = "/api"; 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 = { const routes = {
base: `${prefix}/groups/reports`, base: `${prefix}/groups/reports`,
getOne: (id: string) => `${prefix}/groups/reports/${id}`, getOne: (id: string) => `${prefix}/groups/reports/${id}`,
@ -40,7 +15,7 @@ export class GroupReportsApi extends BaseAPI {
} }
async getOne(id: string) { async getOne(id: string) {
return await this.requests.get<Report>(routes.getOne(id)); return await this.requests.get<ReportOut>(routes.getOne(id));
} }
async deleteOne(id: string) { async deleteOne(id: string) {

View File

@ -4,7 +4,9 @@ import {
ShoppingListCreate, ShoppingListCreate,
ShoppingListItemCreate, ShoppingListItemCreate,
ShoppingListItemOut, ShoppingListItemOut,
ShoppingListItemUpdate,
ShoppingListOut, ShoppingListOut,
ShoppingListUpdate,
} from "~/types/api-types/group"; } from "~/types/api-types/group";
const prefix = "/api"; const prefix = "/api";
@ -18,7 +20,7 @@ const routes = {
shoppingListItemsId: (id: string) => `${prefix}/groups/shopping/items/${id}`, shoppingListItemsId: (id: string) => `${prefix}/groups/shopping/items/${id}`,
}; };
export class ShoppingListsApi extends BaseCRUDAPI<ShoppingListOut, ShoppingListCreate> { export class ShoppingListsApi extends BaseCRUDAPI<ShoppingListCreate, ShoppingListOut, ShoppingListUpdate> {
baseRoute = routes.shoppingLists; baseRoute = routes.shoppingLists;
itemRoute = routes.shoppingListsId; itemRoute = routes.shoppingListsId;
@ -31,7 +33,7 @@ export class ShoppingListsApi extends BaseCRUDAPI<ShoppingListOut, ShoppingListC
} }
} }
export class ShoppingListItemsApi extends BaseCRUDAPI<ShoppingListItemOut, ShoppingListItemCreate> { export class ShoppingListItemsApi extends BaseCRUDAPI<ShoppingListItemCreate, ShoppingListItemOut, ShoppingListItemUpdate> {
baseRoute = routes.shoppingListItems; baseRoute = routes.shoppingListItems;
itemRoute = routes.shoppingListItemsId; itemRoute = routes.shoppingListItemsId;

View File

@ -1,5 +1,5 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { ServerTask } from "~/api/types/server-task"; import { ServerTask } from "~/types/api-types/server";
const prefix = "/api"; const prefix = "/api";
const routes = { const routes = {

View File

@ -1,4 +1,5 @@
import { BaseCRUDAPI } from "../_base"; import { BaseCRUDAPI } from "../_base";
import { CreateWebhook, ReadWebhook } from "~/types/api-types/group";
const prefix = "/api"; const prefix = "/api";
@ -7,19 +8,7 @@ const routes = {
webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`, webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`,
}; };
export interface CreateGroupWebhook { export class WebhooksAPI extends BaseCRUDAPI<CreateWebhook, ReadWebhook> {
enabled: boolean;
name: string;
url: string;
time: string;
}
export interface GroupWebhook extends CreateGroupWebhook {
id: string;
groupId: string;
}
export class WebhooksAPI extends BaseCRUDAPI<GroupWebhook, CreateGroupWebhook> {
baseRoute = routes.webhooks; baseRoute = routes.webhooks;
itemRoute = routes.webhooksId; itemRoute = routes.webhooksId;
} }

View File

@ -1,6 +1,6 @@
import { BaseCRUDAPI } from "../_base"; import { BaseCRUDAPI } from "../_base";
import { GroupInDB, UserOut } from "~/types/api-types/user"; import { CategoryBase, GroupBase, GroupInDB, UserOut } from "~/types/api-types/user";
import { GroupStatistics, GroupStorage } from "~/types/api-types/group"; import { CreateInviteToken, GroupAdminUpdate, GroupStatistics, GroupStorage, ReadGroupPreferences, ReadInviteToken, SetPermissions, UpdateGroupPreferences } from "~/types/api-types/group";
const prefix = "/api"; const prefix = "/api";
@ -20,82 +20,34 @@ const routes = {
groupsId: (id: string | number) => `${prefix}/admin/groups/${id}`, groupsId: (id: string | number) => `${prefix}/admin/groups/${id}`,
}; };
interface Category { export class GroupAPI extends BaseCRUDAPI<GroupBase, GroupInDB, GroupAdminUpdate> {
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<GroupInDB, CreateGroup> {
baseRoute = routes.groups; baseRoute = routes.groups;
itemRoute = routes.groupsId; itemRoute = routes.groupsId;
/** Returns the Group Data for the Current User /** Returns the Group Data for the Current User
*/ */
async getCurrentUserGroup() { async getCurrentUserGroup() {
return await this.requests.get<Group>(routes.groupsSelf); return await this.requests.get<GroupInDB>(routes.groupsSelf);
} }
async getCategories() { async getCategories() {
return await this.requests.get<Category[]>(routes.categories); return await this.requests.get<CategoryBase[]>(routes.categories);
} }
async setCategories(payload: Category[]) { async setCategories(payload: CategoryBase[]) {
return await this.requests.put<Category[]>(routes.categories, payload); return await this.requests.put<CategoryBase[]>(routes.categories, payload);
} }
async getPreferences() { async getPreferences() {
return await this.requests.get<Preferences>(routes.preferences); return await this.requests.get<ReadGroupPreferences>(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 // TODO: This should probably be a patch request, which isn't offered by the API currently
return await this.requests.put<Preferences, UpdatePreferences>(routes.preferences, payload); return await this.requests.put<ReadGroupPreferences, UpdateGroupPreferences>(routes.preferences, payload);
} }
async createInvitation(payload: CreateInvitation) { async createInvitation(payload: CreateInviteToken) {
return await this.requests.post<Invitation>(routes.invitation, payload); return await this.requests.post<ReadInviteToken>(routes.invitation, payload);
} }
async fetchMembers() { async fetchMembers() {
@ -104,7 +56,7 @@ export class GroupAPI extends BaseCRUDAPI<GroupInDB, CreateGroup> {
async setMemberPermissions(payload: SetPermissions) { async setMemberPermissions(payload: SetPermissions) {
// TODO: This should probably be a patch request, which isn't offered by the API currently // TODO: This should probably be a patch request, which isn't offered by the API currently
return await this.requests.put<Permissions, SetPermissions>(routes.permissions, payload); return await this.requests.put<UserOut, SetPermissions>(routes.permissions, payload);
} }
async statistics() { async statistics() {

View File

@ -10,7 +10,7 @@ const routes = {
categoriesSlug: (category: string) => `${prefix}/categories/slug/${category}`, categoriesSlug: (category: string) => `${prefix}/categories/slug/${category}`,
}; };
export class CategoriesAPI extends BaseCRUDAPI<RecipeCategoryResponse, CategoryIn> { export class CategoriesAPI extends BaseCRUDAPI<CategoryIn, RecipeCategoryResponse> {
baseRoute: string = routes.categories; baseRoute: string = routes.categories;
itemRoute = routes.categoriesId; itemRoute = routes.categoriesId;

View File

@ -10,7 +10,7 @@ const routes = {
tagsSlug: (tag: string) => `${prefix}/tags/slug/${tag}`, tagsSlug: (tag: string) => `${prefix}/tags/slug/${tag}`,
}; };
export class TagsAPI extends BaseCRUDAPI<RecipeTagResponse, TagIn> { export class TagsAPI extends BaseCRUDAPI<TagIn, RecipeTagResponse> {
baseRoute: string = routes.tags; baseRoute: string = routes.tags;
itemRoute = routes.tagsId; itemRoute = routes.tagsId;

View File

@ -11,7 +11,7 @@ const routes = {
toolsSlug: (id: string) => `${prefix}/tools/slug/${id}`, toolsSlug: (id: string) => `${prefix}/tools/slug/${id}`,
}; };
export class ToolsApi extends BaseCRUDAPI<RecipeTool, RecipeToolCreate> { export class ToolsApi extends BaseCRUDAPI<RecipeToolCreate, RecipeTool> {
baseRoute: string = routes.tools; baseRoute: string = routes.tools;
itemRoute = routes.toolsId; itemRoute = routes.toolsId;

View File

@ -1,45 +1,10 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { AssignCategories, AssignTags, DeleteRecipes, ExportRecipes } from "~/types/api-types/recipe";
import { GroupDataExport } from "~/types/api-types/group";
interface BasePayload { // Many bulk actions return nothing
recipes: string[];
}
type exportType = "json";
// eslint-disable-next-line @typescript-eslint/no-empty-interface // 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 { 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"; const prefix = "/api";
@ -53,19 +18,19 @@ const routes = {
}; };
export class BulkActionsAPI extends BaseAPI { export class BulkActionsAPI extends BaseAPI {
async bulkExport(payload: RecipeBulkExport) { async bulkExport(payload: ExportRecipes) {
return await this.requests.post<BulkActionResponse>(routes.bulkExport, payload); return await this.requests.post<BulkActionResponse>(routes.bulkExport, payload);
} }
async bulkCategorize(payload: RecipeBulkCategorize) { async bulkCategorize(payload: AssignCategories) {
return await this.requests.post<BulkActionResponse>(routes.bulkCategorize, payload); return await this.requests.post<BulkActionResponse>(routes.bulkCategorize, payload);
} }
async bulkTag(payload: RecipeBulkTag) { async bulkTag(payload: AssignTags) {
return await this.requests.post<BulkActionResponse>(routes.bulkTag, payload); return await this.requests.post<BulkActionResponse>(routes.bulkTag, payload);
} }
async bulkDelete(payload: RecipeBulkDelete) { async bulkDelete(payload: DeleteRecipes) {
return await this.requests.post<BulkActionResponse>(routes.bulkDelete, payload); return await this.requests.post<BulkActionResponse>(routes.bulkDelete, payload);
} }
@ -74,6 +39,6 @@ export class BulkActionsAPI extends BaseAPI {
} }
async purgeExports() { async purgeExports() {
return await this.requests.delete(routes.purgeExports); return await this.requests.delete<BulkActionResponse>(routes.purgeExports);
} }
} }

View File

@ -9,7 +9,7 @@ const routes = {
merge: `${prefix}/foods/merge`, merge: `${prefix}/foods/merge`,
}; };
export class FoodAPI extends BaseCRUDAPI<IngredientFood, CreateIngredientFood> { export class FoodAPI extends BaseCRUDAPI<CreateIngredientFood, IngredientFood> {
baseRoute: string = routes.food; baseRoute: string = routes.food;
itemRoute = routes.foodsFood; itemRoute = routes.foodsFood;

View File

@ -9,7 +9,7 @@ const routes = {
merge: `${prefix}/units/merge`, merge: `${prefix}/units/merge`,
}; };
export class UnitAPI extends BaseCRUDAPI<IngredientUnit, CreateIngredientUnit> { export class UnitAPI extends BaseCRUDAPI<CreateIngredientUnit, IngredientUnit> {
baseRoute: string = routes.unit; baseRoute: string = routes.unit;
itemRoute = routes.unitsUnit; itemRoute = routes.unitsUnit;

View File

@ -1,5 +1,5 @@
import { RecipeComment, RecipeCommentCreate } from "./types";
import { BaseCRUDAPI } from "~/api/_base"; import { BaseCRUDAPI } from "~/api/_base";
import { RecipeCommentCreate, RecipeCommentOut, RecipeCommentUpdate } from "~/types/api-types/recipe";
const prefix = "/api"; const prefix = "/api";
@ -9,11 +9,11 @@ const routes = {
commentsId: (id: string) => `${prefix}/comments/${id}`, commentsId: (id: string) => `${prefix}/comments/${id}`,
}; };
export class CommentsApi extends BaseCRUDAPI<RecipeComment, RecipeCommentCreate> { export class CommentsApi extends BaseCRUDAPI<RecipeCommentCreate, RecipeCommentOut, RecipeCommentUpdate> {
baseRoute: string = routes.comment; baseRoute: string = routes.comment;
itemRoute = routes.commentsId; itemRoute = routes.commentsId;
async byRecipe(slug: string) { async byRecipe(slug: string) {
return await this.requests.get<RecipeComment[]>(routes.byRecipe(slug)); return await this.requests.get<RecipeCommentOut[]>(routes.byRecipe(slug));
} }
} }

View File

@ -1,4 +1,5 @@
import { BaseCRUDAPI } from "~/api/_base"; import { BaseCRUDAPI } from "~/api/_base";
import { RecipeShareToken, RecipeShareTokenCreate } from "~/types/api-types/recipe";
const prefix = "/api"; const prefix = "/api";
@ -7,20 +8,7 @@ const routes = {
shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`, shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`,
}; };
export interface RecipeShareTokenCreate { export class RecipeShareApi extends BaseCRUDAPI<RecipeShareTokenCreate, RecipeShareToken> {
recipeId: string;
expiresAt?: Date;
}
export interface RecipeShareToken {
recipeId: string;
id: string;
groupId: number;
expiresAt: string;
createdAt: string;
}
export class RecipeShareApi extends BaseCRUDAPI<RecipeShareToken, RecipeShareTokenCreate> {
baseRoute: string = routes.shareToken; baseRoute: string = routes.shareToken;
itemRoute = routes.shareTokenId; itemRoute = routes.shareTokenId;
} }

View File

@ -1,11 +1,19 @@
import { CreateAsset, ParsedIngredient, Parser, RecipeZipToken, BulkCreatePayload } from "./types";
import { CommentsApi } from "./recipe-comments"; import { CommentsApi } from "./recipe-comments";
import { RecipeShareApi } from "./recipe-share"; import { RecipeShareApi } from "./recipe-share";
import { BaseCRUDAPI } from "~/api/_base"; 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"; 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 prefix = "/api";
const routes = { const routes = {
@ -31,7 +39,7 @@ const routes = {
recipeShareToken: (token: string) => `${prefix}/recipes/shared/${token}`, recipeShareToken: (token: string) => `${prefix}/recipes/shared/${token}`,
}; };
export class RecipeAPI extends BaseCRUDAPI<Recipe, CreateRecipe> { export class RecipeAPI extends BaseCRUDAPI<CreateRecipe, Recipe, Recipe> {
baseRoute: string = routes.recipesBase; baseRoute: string = routes.recipesBase;
itemRoute = routes.recipesRecipeSlug; itemRoute = routes.recipesRecipeSlug;
@ -58,7 +66,7 @@ export class RecipeAPI extends BaseCRUDAPI<Recipe, CreateRecipe> {
formData.append("extension", payload.extension); formData.append("extension", payload.extension);
formData.append("icon", payload.icon); formData.append("icon", payload.icon);
return await this.requests.post(routes.recipesRecipeSlugAssets(recipeSlug), formData); return await this.requests.post<RecipeAsset>(routes.recipesRecipeSlugAssets(recipeSlug), formData);
} }
updateImage(slug: string, fileObject: File) { updateImage(slug: string, fileObject: File) {
@ -66,11 +74,11 @@ export class RecipeAPI extends BaseCRUDAPI<Recipe, CreateRecipe> {
formData.append("image", fileObject); formData.append("image", fileObject);
formData.append("extension", fileObject.name.split(".").pop() ?? ""); formData.append("extension", fileObject.name.split(".").pop() ?? "");
return this.requests.put<any>(routes.recipesRecipeSlugImage(slug), formData); return this.requests.put<UpdateImageResponse, FormData>(routes.recipesRecipeSlugImage(slug), formData);
} }
updateImagebyURL(slug: string, url: string) { updateImagebyURL(slug: string, url: string) {
return this.requests.post(routes.recipesRecipeSlugImage(slug), { url }); return this.requests.post<UpdateImageResponse>(routes.recipesRecipeSlugImage(slug), { url });
} }
async testCreateOneUrl(url: string) { async testCreateOneUrl(url: string) {
@ -81,8 +89,8 @@ export class RecipeAPI extends BaseCRUDAPI<Recipe, CreateRecipe> {
return await this.requests.post<string>(routes.recipesCreateUrl, { url, includeTags }); return await this.requests.post<string>(routes.recipesCreateUrl, { url, includeTags });
} }
async createManyByUrl(payload: BulkCreatePayload) { async createManyByUrl(payload: CreateRecipeByUrlBulk) {
return await this.requests.post(routes.recipesCreateUrlBulk, payload); return await this.requests.post<string>(routes.recipesCreateUrlBulk, payload);
} }
async parseIngredients(parser: Parser, ingredients: Array<string>) { async parseIngredients(parser: Parser, ingredients: Array<string>) {
@ -96,7 +104,7 @@ export class RecipeAPI extends BaseCRUDAPI<Recipe, CreateRecipe> {
} }
async getZipToken(recipeSlug: string) { async getZipToken(recipeSlug: string) {
return await this.requests.post<RecipeZipToken>(routes.recipesRecipeSlugExport(recipeSlug), {}); return await this.requests.post<RecipeZipTokenResponse>(routes.recipesRecipeSlugExport(recipeSlug), {});
} }
getZipRedirectUrl(recipeSlug: string, token: string) { getZipRedirectUrl(recipeSlug: string, token: string) {

View File

@ -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;
}

View File

@ -1,29 +1,5 @@
import { BaseCRUDAPI } from "../_base"; import { BaseCRUDAPI } from "../_base";
import { UserIn, UserOut } from "~/types/api-types/user"; import { ChangePassword, DeleteTokenResponse, LongLiveTokenIn, LongLiveTokenOut, ResetPassword, UserBase, 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
const prefix = "/api"; const prefix = "/api";
@ -43,7 +19,7 @@ const routes = {
usersApiTokensTokenId: (token_id: string | number) => `${prefix}/users/api-tokens/${token_id}`, usersApiTokensTokenId: (token_id: string | number) => `${prefix}/users/api-tokens/${token_id}`,
}; };
export class UserApi extends BaseCRUDAPI<UserOut, UserIn> { export class UserApi extends BaseCRUDAPI<UserIn, UserOut, UserBase> {
baseRoute: string = routes.users; baseRoute: string = routes.users;
itemRoute = (itemid: string) => routes.usersId(itemid); itemRoute = (itemid: string) => routes.usersId(itemid);
@ -63,12 +39,12 @@ export class UserApi extends BaseCRUDAPI<UserOut, UserIn> {
return await this.requests.put(routes.usersIdPassword(id), changePassword); return await this.requests.put(routes.usersIdPassword(id), changePassword);
} }
async createAPIToken(tokenName: CreateAPIToken) { async createAPIToken(tokenName: LongLiveTokenIn) {
return await this.requests.post<ResponseToken>(routes.usersApiTokens, tokenName); return await this.requests.post<LongLiveTokenOut>(routes.usersApiTokens, tokenName);
} }
async deleteAPIToken(tokenId: string | number) { async deleteAPIToken(tokenId: number) {
return await this.requests.delete(routes.usersApiTokensTokenId(tokenId)); return await this.requests.delete<DeleteTokenResponse>(routes.usersApiTokensTokenId(tokenId));
} }
userProfileImage(id: string) { userProfileImage(id: string) {
@ -76,7 +52,7 @@ export class UserApi extends BaseCRUDAPI<UserOut, UserIn> {
return `/api/users/${id}/image`; return `/api/users/${id}/image`;
} }
async resetPassword(payload: PasswordResetPayload) { async resetPassword(payload: ResetPassword) {
return await this.requests.post(routes.passwordReset, payload); return await this.requests.post(routes.passwordReset, payload);
} }
} }

View File

@ -1,14 +1,11 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { FileTokenResponse } from "~/types/api-types/response";
const prefix = "/api"; const prefix = "/api";
interface DownloadData {
fileToken: string;
}
export class UtilsAPI extends BaseAPI { export class UtilsAPI extends BaseAPI {
async download(url: string) { async download(url: string) {
const { response } = await this.requests.get<DownloadData>(url); const { response } = await this.requests.get<FileTokenResponse>(url);
if (!response) { if (!response) {
return; return;

View File

@ -1,8 +1,5 @@
import { BaseAPI } from "../_base"; import { BaseAPI } from "../_base";
import { ValidationResponse } from "~/types/api-types/response";
export type Validation = {
valid: boolean;
};
const prefix = "/api"; const prefix = "/api";
@ -15,18 +12,18 @@ const routes = {
export class ValidatorsApi extends BaseAPI { export class ValidatorsApi extends BaseAPI {
async group(name: string) { async group(name: string) {
return await this.requests.get<Validation>(routes.group(name)); return await this.requests.get<ValidationResponse>(routes.group(name));
} }
async username(name: string) { async username(name: string) {
return await this.requests.get<Validation>(routes.user(name)); return await this.requests.get<ValidationResponse>(routes.user(name));
} }
async email(email: string) { async email(email: string) {
return await this.requests.get<Validation>(routes.email(email)); return await this.requests.get<ValidationResponse>(routes.email(email));
} }
async recipe(groupId: string, name: string) { async recipe(groupId: string, name: string) {
return await this.requests.get<Validation>(routes.recipe(groupId, name)); return await this.requests.get<ValidationResponse>(routes.recipe(groupId, name));
} }
} }

View File

@ -1,8 +0,0 @@
export interface ServerTask {
id: number;
groupId: number;
callback: string;
createdAt: string;
status: string;
log: string;
}

View File

@ -20,7 +20,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api"; import { defineComponent } from "@nuxtjs/composition-api";
import { parseISO, formatDistanceToNow } from "date-fns"; import { parseISO, formatDistanceToNow } from "date-fns";
import { GroupDataExport } from "~/api/class-interfaces/recipe-bulk-actions"; import { GroupDataExport } from "~/types/api-types/group";
export default defineComponent({ export default defineComponent({
props: { props: {
exports: { exports: {
@ -57,4 +57,3 @@ export default defineComponent({
}, },
}); });
</script> </script>

View File

@ -56,7 +56,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, toRefs, onMounted, reactive } from "@nuxtjs/composition-api"; import { defineComponent, ref, toRefs, onMounted, reactive } from "@nuxtjs/composition-api";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { RecipeComment } from "~/api/class-interfaces/recipes/types"; import { RecipeCommentOut } from "~/types/api-types/recipe";
import UserAvatar from "~/components/Domain/User/UserAvatar.vue"; import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
export default defineComponent({ export default defineComponent({
@ -76,7 +76,7 @@ export default defineComponent({
setup(props) { setup(props) {
const api = useUserApi(); const api = useUserApi();
const comments = ref<RecipeComment[]>([]); const comments = ref<RecipeCommentOut[]>([]);
const state = reactive({ const state = reactive({
comment: "", comment: "",

View File

@ -95,8 +95,9 @@ import { defineComponent, reactive, toRefs, useContext, useRouter, ref } from "@
import RecipeDialogShare from "./RecipeDialogShare.vue"; import RecipeDialogShare from "./RecipeDialogShare.vue";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast"; import { alert } from "~/composables/use-toast";
import { MealType, planTypeOptions } from "~/composables/use-group-mealplan"; import { planTypeOptions } from "~/composables/use-group-mealplan";
import { ShoppingListSummary } from "~/types/api-types/group"; import { ShoppingListSummary } from "~/types/api-types/group";
import { PlanEntryType } from "~/types/api-types/meal-plan";
import { useAxiosDownloader } from "~/composables/api/use-axios-download"; import { useAxiosDownloader } from "~/composables/api/use-axios-download";
export interface ContextMenuIncludes { export interface ContextMenuIncludes {
@ -183,7 +184,7 @@ export default defineComponent({
loading: false, loading: false,
menuItems: [] as ContextMenuItem[], menuItems: [] as ContextMenuItem[],
newMealdate: "", newMealdate: "",
newMealType: "dinner" as MealType, newMealType: "dinner" as PlanEntryType,
pickerMenu: false, pickerMenu: false,
}); });

View File

@ -59,7 +59,7 @@
import { defineComponent, computed, toRefs, reactive, useContext } from "@nuxtjs/composition-api"; import { defineComponent, computed, toRefs, reactive, useContext } from "@nuxtjs/composition-api";
import { whenever } from "@vueuse/shared"; import { whenever } from "@vueuse/shared";
import { useClipboard, useShare } from "@vueuse/core"; import { useClipboard, useShare } from "@vueuse/core";
import { RecipeShareToken } from "~/api/class-interfaces/recipes/recipe-share"; import { RecipeShareToken } from "~/types/api-types/recipe";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast"; import { alert } from "~/composables/use-toast";
@ -118,7 +118,7 @@ export default defineComponent({
const { data } = await userApi.recipes.share.createOne({ const { data } = await userApi.recipes.share.createOne({
recipeId: props.recipeId, recipeId: props.recipeId,
expiresAt: expirationDate, expiresAt: expirationDate.toISOString(),
}); });
if (data) { if (data) {

View File

@ -26,7 +26,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, useRouter } from "@nuxtjs/composition-api"; import { defineComponent, useRouter } from "@nuxtjs/composition-api";
import { ReportSummary } from "~/api/class-interfaces/group-reports"; import { ReportSummary } from "~/types/api-types/reports";
export default defineComponent({ export default defineComponent({
props: { props: {

View File

@ -1,8 +1,13 @@
import { useAsync, ref, reactive } from "@nuxtjs/composition-api"; import { useAsync, ref, reactive } from "@nuxtjs/composition-api";
import { toastLoading, loader } from "./use-toast"; import { toastLoading, loader } from "./use-toast";
import { AllBackups, ImportBackup } from "~/api/class-interfaces/backups"; import { AllBackups, BackupOptions } from "~/types/api-types/admin";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
interface ImportBackup {
name: string;
options: BackupOptions;
}
const backups = ref<AllBackups>({ const backups = ref<AllBackups>({
imports: [], imports: [],
templates: [], templates: [],
@ -41,7 +46,6 @@ export const useBackups = function (fetch = true) {
options: { options: {
recipes: true, recipes: true,
settings: true, settings: true,
pages: true,
themes: true, themes: true,
groups: true, groups: true,
users: true, users: true,

View File

@ -1,7 +1,7 @@
import { useAsync, ref, Ref } from "@nuxtjs/composition-api"; import { useAsync, ref, Ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils"; import { useAsyncKey } from "./use-utils";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { ReadCookBook, RecipeCookBook, UpdateCookBook } from "~/types/api-types/cookbook"; import { ReadCookBook, UpdateCookBook } from "~/types/api-types/cookbook";
let cookbookStore: Ref<ReadCookBook[] | null> | null = null; let cookbookStore: Ref<ReadCookBook[] | null> | null = null;
@ -66,7 +66,7 @@ export const useCookbooks = function () {
} }
loading.value = true; loading.value = true;
const { data } = await api.cookbooks.updateOne(updateData.id, updateData as RecipeCookBook); const { data } = await api.cookbooks.updateOne(updateData.id, updateData);
if (data && cookbookStore?.value) { if (data && cookbookStore?.value) {
this.refreshAll(); this.refreshAll();
} }

View File

@ -2,9 +2,7 @@ import { useAsync, ref, Ref, watch } from "@nuxtjs/composition-api";
import { format } from "date-fns"; import { format } from "date-fns";
import { useAsyncKey } from "./use-utils"; import { useAsyncKey } from "./use-utils";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { CreateMealPlan, UpdateMealPlan } from "~/api/class-interfaces/group-mealplan"; import { CreatePlanEntry, PlanEntryType, UpdatePlanEntry } from "~/types/api-types/meal-plan";
export type MealType = "breakfast" | "lunch" | "dinner" | "side";
export const planTypeOptions = [ export const planTypeOptions = [
{ text: "Breakfast", value: "breakfast" }, { text: "Breakfast", value: "breakfast" },
@ -55,7 +53,7 @@ export const useMealplans = function (range: Ref<DateRange>) {
loading.value = false; loading.value = false;
}, },
async createOne(payload: CreateMealPlan) { async createOne(payload: CreatePlanEntry) {
loading.value = true; loading.value = true;
const { data } = await api.mealplans.createOne(payload); const { data } = await api.mealplans.createOne(payload);
@ -65,13 +63,12 @@ export const useMealplans = function (range: Ref<DateRange>) {
loading.value = false; loading.value = false;
}, },
async updateOne(updateData: UpdateMealPlan) { async updateOne(updateData: UpdatePlanEntry) {
if (!updateData.id) { if (!updateData.id) {
return; return;
} }
loading.value = true; loading.value = true;
// @ts-ignore TODO Modify mealpan types to be from auto-generated files
const { data } = await api.mealplans.updateOne(updateData.id, updateData); const { data } = await api.mealplans.updateOne(updateData.id, updateData);
if (data) { if (data) {
this.refreshAll(); this.refreshAll();
@ -87,8 +84,8 @@ export const useMealplans = function (range: Ref<DateRange>) {
} }
}, },
async setType(payload: UpdateMealPlan, typ: MealType) { async setType(payload: UpdatePlanEntry, type: PlanEntryType) {
payload.entryType = typ; payload.entryType = type;
await this.updateOne(payload); await this.updateOne(payload);
}, },
}; };

View File

@ -1,7 +1,7 @@
import { useAsync, ref } from "@nuxtjs/composition-api"; import { useAsync, ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils"; import { useAsyncKey } from "./use-utils";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { GroupWebhook } from "~/api/class-interfaces/group-webhooks"; import { ReadWebhook } from "~/types/api-types/group";
export const useGroupWebhooks = function () { export const useGroupWebhooks = function () {
const api = useUserApi(); const api = useUserApi();
@ -47,7 +47,7 @@ export const useGroupWebhooks = function () {
loading.value = false; loading.value = false;
}, },
async updateOne(updateData: GroupWebhook) { async updateOne(updateData: ReadWebhook) {
if (!updateData.id) { if (!updateData.id) {
return; return;
} }

View File

@ -1,7 +1,7 @@
import { useAsync, ref } from "@nuxtjs/composition-api"; import { useAsync, ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils"; import { useAsyncKey } from "./use-utils";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { CreateGroup } from "~/api/class-interfaces/groups"; import { GroupBase } from "~/types/api-types/user";
export const useGroupSelf = function () { export const useGroupSelf = function () {
const api = useUserApi(); const api = useUserApi();
@ -17,7 +17,7 @@ export const useGroupSelf = function () {
return group; return group;
}, },
async updatePreferences() { async updatePreferences() {
if (!group.value) { if (!group.value?.preferences) {
return; return;
} }
@ -65,7 +65,7 @@ export const useGroups = function () {
return data; return data;
} }
async function createGroup(payload: CreateGroup) { async function createGroup(payload: GroupBase) {
loading.value = true; loading.value = true;
const { data } = await api.groups.createOne(payload); const { data } = await api.groups.createOne(payload);

View File

@ -1,6 +1,6 @@
import { ref, Ref } from "@nuxtjs/composition-api"; import { ref, Ref } from "@nuxtjs/composition-api";
import { RequestResponse } from "~/types/api"; import { RequestResponse } from "~/types/api";
import { Validation } from "~/api/public/validators"; import { ValidationResponse } from "~/types/api-types/response";
const EMAIL_REGEX = const EMAIL_REGEX =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@ -23,7 +23,7 @@ export const validators = {
*/ */
export const useAsyncValidator = ( export const useAsyncValidator = (
value: Ref<string>, value: Ref<string>,
validatorFunc: (v: string) => Promise<RequestResponse<Validation>>, validatorFunc: (v: string) => Promise<RequestResponse<ValidationResponse>>,
validatorMessage: string, validatorMessage: string,
errorMessages: Ref<string[]> errorMessages: Ref<string[]>
) => { ) => {

View File

@ -38,10 +38,10 @@
</v-expansion-panels> </v-expansion-panels>
</v-container> </v-container>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, ref } from "@nuxtjs/composition-api"; import { defineComponent, onMounted, ref } from "@nuxtjs/composition-api";
import { ServerTask } from "~/api/types/server-task"; import { ServerTask } from "~/types/api-types/server";
import { useAdminApi } from "~/composables/api"; import { useAdminApi } from "~/composables/api";
export default defineComponent({ export default defineComponent({
@ -84,4 +84,4 @@ export default defineComponent({
}; };
}, },
}); });
</script> </script>

View File

@ -28,8 +28,8 @@ import { defineComponent, useRoute, onMounted, ref } from "@nuxtjs/composition-a
import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue"; import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue";
import { useAdminApi } from "~/composables/api"; import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast"; import { alert } from "~/composables/use-toast";
import { GroupInDB } from "~/types/api-types/user";
import { VForm } from "~/types/vuetify"; import { VForm } from "~/types/vuetify";
import { GroupRead } from "~/api/admin/admin-groups";
export default defineComponent({ export default defineComponent({
components: { components: {
@ -48,7 +48,7 @@ export default defineComponent({
const adminApi = useAdminApi(); const adminApi = useAdminApi();
const group = ref<GroupRead | null>(null); const group = ref<GroupInDB | null>(null);
const userError = ref(false); const userError = ref(false);

View File

@ -71,9 +71,9 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, toRefs, useContext, useRouter } from "@nuxtjs/composition-api"; import { defineComponent, reactive, toRefs, useContext, useRouter } from "@nuxtjs/composition-api";
import { Group } from "~/api/class-interfaces/groups";
import { fieldTypes } from "~/composables/forms"; import { fieldTypes } from "~/composables/forms";
import { useGroups } from "~/composables/use-groups"; import { useGroups } from "~/composables/use-groups";
import { GroupInDB } from "~/types/api-types/user";
export default defineComponent({ export default defineComponent({
layout: "admin", layout: "admin",
@ -121,7 +121,7 @@ export default defineComponent({
const router = useRouter(); const router = useRouter();
function handleRowClick(item: Group) { function handleRowClick(item: GroupInDB) {
router.push(`/admin/manage/groups/${item.id}`); router.push(`/admin/manage/groups/${item.id}`);
} }

View File

@ -65,10 +65,11 @@
</v-container> </v-container>
</v-container> </v-container>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, toRefs } from "@nuxtjs/composition-api"; import { defineComponent, reactive, ref, toRefs } from "@nuxtjs/composition-api";
import { Confidence, Parser } from "~/api/class-interfaces/recipes/types"; import { Parser } from "~/api/class-interfaces/recipes/recipe";
import { IngredientConfidence } from "~/types/api-types/recipe";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
type ConfidenceAttribute = "average" | "comment" | "name" | "unit" | "quantity" | "food"; type ConfidenceAttribute = "average" | "comment" | "name" | "unit" | "quantity" | "food";
@ -85,7 +86,7 @@ export default defineComponent({
parser: "nlp" as Parser, parser: "nlp" as Parser,
}); });
const confidence = ref<Confidence>({}); const confidence = ref<IngredientConfidence>({});
function getColor(attribute: ConfidenceAttribute) { function getColor(attribute: ConfidenceAttribute) {
const percentage = getConfidence(attribute); const percentage = getConfidence(attribute);
@ -141,7 +142,8 @@ export default defineComponent({
if (data) { if (data) {
state.results = true; state.results = true;
confidence.value = data.confidence; if (data.confidence)
confidence.value = data.confidence;
// TODO: Remove ts-ignore // TODO: Remove ts-ignore
// ts-ignore because data will likely change significantly once I figure out how to return results // ts-ignore because data will likely change significantly once I figure out how to return results
@ -215,6 +217,6 @@ export default defineComponent({
}, },
}); });
</script> </script>
<style scoped> <style scoped>
</style> </style>

View File

@ -259,7 +259,7 @@ export default defineComponent({
const { data } = await adminApi.about.checkApp(); const { data } = await adminApi.about.checkApp();
if (data) { if (data) {
appConfig.value = data; appConfig.value = { ...data, isSiteSecure: false};
} }
appConfig.value.isSiteSecure = isLocalHostOrHttps(); appConfig.value.isSiteSecure = isLocalHostOrHttps();
@ -323,7 +323,7 @@ export default defineComponent({
if (data.success) { if (data.success) {
state.success = true; state.success = true;
} else { } else {
state.error = data.error; state.error = data.error ?? "";
state.success = false; state.success = false;
} }
} }

View File

@ -154,7 +154,7 @@ import { useUserApi } from "~/composables/api";
import { useRecipes, allRecipes } from "~/composables/recipes"; import { useRecipes, allRecipes } from "~/composables/recipes";
import { Recipe } from "~/types/api-types/recipe"; import { Recipe } from "~/types/api-types/recipe";
import GroupExportData from "~/components/Domain/Group/GroupExportData.vue"; 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"; import { MenuItem } from "~/components/global/BaseOverflowButton.vue";
const MODES = { const MODES = {

View File

@ -346,7 +346,7 @@ export default defineComponent({
date: "", date: "",
title: "", title: "",
text: "", text: "",
recipeId: undefined as number | undefined, recipeId: undefined as string | undefined,
entryType: "dinner" as PlanEntryType, entryType: "dinner" as PlanEntryType,
}); });

View File

@ -66,10 +66,10 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, toRefs, useContext, computed, onMounted } from "@nuxtjs/composition-api"; import { defineComponent, reactive, toRefs, useContext, computed, onMounted } from "@nuxtjs/composition-api";
import { SupportedMigration } from "~/api/class-interfaces/group-migrations"; import { ReportSummary } from "~/types/api-types/reports";
import { ReportSummary } from "~/api/class-interfaces/group-reports";
import { MenuItem } from "~/components/global/BaseOverflowButton.vue"; import { MenuItem } from "~/components/global/BaseOverflowButton.vue";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { SupportedMigrations } from "~/types/api-types/group";
const MIGRATIONS = { const MIGRATIONS = {
nextcloud: "nextcloud", nextcloud: "nextcloud",
@ -88,7 +88,7 @@ export default defineComponent({
addMigrationTag: false, addMigrationTag: false,
loading: false, loading: false,
treeState: true, treeState: true,
migrationType: MIGRATIONS.nextcloud as SupportedMigration, migrationType: MIGRATIONS.nextcloud as SupportedMigrations,
fileObject: {} as File, fileObject: {} as File,
reports: [] as ReportSummary[], reports: [] as ReportSummary[],
}); });

View File

@ -702,8 +702,8 @@ export default defineComponent({
return; return;
} }
const newVersion = await api.recipes.updateImage(recipe.value.slug, fileObject); const newVersion = await api.recipes.updateImage(recipe.value.slug, fileObject);
if (newVersion?.data?.version) { if (newVersion?.data?.image) {
recipe.value.image = newVersion.data.version; recipe.value.image = newVersion.data.image;
} }
state.imageKey++; state.imageKey++;
} }

View File

@ -83,8 +83,8 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, useRoute, useRouter } from "@nuxtjs/composition-api"; import { defineComponent, ref, useRoute, useRouter } from "@nuxtjs/composition-api";
import { invoke, until } from "@vueuse/core"; import { invoke, until } from "@vueuse/core";
import { ParsedIngredient, Parser } from "~/api/class-interfaces/recipes/types"; import { Parser } from "~/api/class-interfaces/recipes/recipe";
import { CreateIngredientFood, CreateIngredientUnit, IngredientFood, IngredientUnit } from "~/types/api-types/recipe"; import { CreateIngredientFood, CreateIngredientUnit, IngredientFood, IngredientUnit, ParsedIngredient } from "~/types/api-types/recipe";
import RecipeIngredientEditor from "~/components/Domain/Recipe/RecipeIngredientEditor.vue"; import RecipeIngredientEditor from "~/components/Domain/Recipe/RecipeIngredientEditor.vue";
import { useUserApi } from "~/composables/api"; import { useUserApi } from "~/composables/api";
import { useFoods, useRecipe, useUnits } from "~/composables/recipes"; import { useFoods, useRecipe, useUnits } from "~/composables/recipes";

View File

@ -111,7 +111,7 @@ export default defineComponent({
} }
} }
async function deleteToken(id: string | number) { async function deleteToken(id: number) {
const { data } = await api.users.deleteAPIToken(id); const { data } = await api.users.deleteAPIToken(id);
nuxtContext.$auth.fetchUser(); nuxtContext.$auth.fetchUser();
return data; return data;
@ -126,4 +126,3 @@ export default defineComponent({
}, },
}); });
</script> </script>

View File

@ -50,10 +50,10 @@ export interface BackupOptions {
notifications?: boolean; notifications?: boolean;
} }
export interface CheckAppConfig { export interface CheckAppConfig {
emailReady?: boolean; emailReady: boolean;
ldapReady?: boolean; ldapReady: boolean;
baseUrlSet?: boolean; baseUrlSet: boolean;
isUpToDate?: boolean; isUpToDate: boolean;
} }
export interface ChowdownURL { export interface ChowdownURL {
url: string; url: string;
@ -174,6 +174,16 @@ export interface CustomPageOut {
export interface DockerVolumeText { export interface DockerVolumeText {
text: string; text: string;
} }
export interface EmailReady {
ready: boolean;
}
export interface EmailSuccess {
success: boolean;
error?: string;
}
export interface EmailTest {
email: string;
}
export interface GroupImport { export interface GroupImport {
name: string; name: string;
status: boolean; status: boolean;

View File

@ -41,7 +41,7 @@ export interface EmailInvitation {
export interface GroupAdminUpdate { export interface GroupAdminUpdate {
id: string; id: string;
name: string; name: string;
preferences: UpdateGroupPreferences; preferences?: UpdateGroupPreferences;
} }
export interface UpdateGroupPreferences { export interface UpdateGroupPreferences {
privateGroup?: boolean; privateGroup?: boolean;

View File

@ -14,10 +14,6 @@ export interface Category {
name: string; name: string;
slug: string; slug: string;
} }
export interface CreatRandomEntry {
date: string;
entryType?: PlanEntryType & string;
}
export interface CreatePlanEntry { export interface CreatePlanEntry {
date: string; date: string;
entryType?: PlanEntryType & string; entryType?: PlanEntryType & string;
@ -25,6 +21,10 @@ export interface CreatePlanEntry {
text?: string; text?: string;
recipeId?: string; recipeId?: string;
} }
export interface CreateRandomEntry {
date: string;
entryType?: PlanEntryType & string;
}
export interface ListItem { export interface ListItem {
title?: string; title?: string;
text?: string; text?: string;

View File

@ -26,15 +26,6 @@ export interface TagBase {
id: string; id: string;
slug: string; slug: string;
} }
export interface BulkActionError {
recipe: string;
error: string;
}
export interface BulkActionsResponse {
success: boolean;
message: string;
errors?: BulkActionError[];
}
export interface CategoryIn { export interface CategoryIn {
name: string; name: string;
} }
@ -335,6 +326,9 @@ export interface RecipeToolSave {
onHand?: boolean; onHand?: boolean;
groupId: string; groupId: string;
} }
export interface RecipeZipTokenResponse {
token: string;
}
export interface SaveIngredientFood { export interface SaveIngredientFood {
name: string; name: string;
description?: string; description?: string;
@ -373,3 +367,6 @@ export interface UnitFoodBase {
name: string; name: string;
description?: string; description?: string;
} }
export interface UpdateImageResponse {
image: string;
}

View File

@ -18,5 +18,5 @@ export interface SuccessResponse {
error?: boolean; error?: boolean;
} }
export interface ValidationResponse { export interface ValidationResponse {
valid?: boolean; valid: boolean;
} }

View File

@ -31,6 +31,9 @@ export interface CreateUserRegistration {
seedData?: boolean; seedData?: boolean;
locale?: string; locale?: string;
} }
export interface DeleteTokenResponse {
tokenDelete: string;
}
export interface ForgotPassword { export interface ForgotPassword {
email: string; email: string;
} }
@ -62,9 +65,7 @@ export interface UserOut {
cacheKey: string; cacheKey: string;
} }
export interface LongLiveTokenOut { export interface LongLiveTokenOut {
name: string; token: string;
id: number;
createdAt: string;
} }
export interface ReadGroupPreferences { export interface ReadGroupPreferences {
privateGroup?: boolean; privateGroup?: boolean;
@ -78,7 +79,7 @@ export interface ReadGroupPreferences {
groupId: string; groupId: string;
id: string; id: string;
} }
export interface LoingLiveTokenIn { export interface LongLiveTokenIn {
name: string; name: string;
} }
export interface LongLiveTokenInDB { export interface LongLiveTokenInDB {

View File

@ -1,25 +1,12 @@
from fastapi import APIRouter from fastapi import APIRouter
from mealie.routes._base import BaseAdminController, controller 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 from mealie.services.email import EmailService
router = APIRouter(prefix="/email") router = APIRouter(prefix="/email")
class EmailReady(MealieModel):
ready: bool
class EmailSuccess(MealieModel):
success: bool
error: str = None
class EmailTest(MealieModel):
email: str
@controller(router) @controller(router)
class AdminEmailController(BaseAdminController): class AdminEmailController(BaseAdminController):
@router.get("", response_model=EmailReady) @router.get("", response_model=EmailReady)

View File

@ -9,7 +9,7 @@ from mealie.routes._base import BaseUserController, controller
from mealie.routes._base.mixins import HttpRepo from mealie.routes._base.mixins import HttpRepo
from mealie.schema import mapper from mealie.schema import mapper
from mealie.schema.meal_plan import CreatePlanEntry, ReadPlanEntry, SavePlanEntry, UpdatePlanEntry 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.meal_plan.plan_rules import PlanRulesDay
from mealie.schema.recipe.recipe import Recipe from mealie.schema.recipe.recipe import Recipe
from mealie.schema.response.responses import ErrorResponse from mealie.schema.response.responses import ErrorResponse
@ -42,7 +42,7 @@ class GroupMealplanController(BaseUserController):
return self.repo.get_today(group_id=self.group_id) return self.repo.get_today(group_id=self.group_id)
@router.post("/random", response_model=ReadPlanEntry) @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. 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 It operates by following the rules setout in the Groups mealplan settings. If not settings

View File

@ -7,13 +7,7 @@ from mealie.core.dependencies.dependencies import temporary_zip_path
from mealie.core.security import create_file_token from mealie.core.security import create_file_token
from mealie.routes._base import BaseUserController, controller from mealie.routes._base import BaseUserController, controller
from mealie.schema.group.group_exports import GroupDataExport from mealie.schema.group.group_exports import GroupDataExport
from mealie.schema.recipe.recipe_bulk_actions import ( from mealie.schema.recipe.recipe_bulk_actions import AssignCategories, AssignTags, DeleteRecipes, ExportRecipes
AssignCategories,
AssignTags,
BulkActionsResponse,
DeleteRecipes,
ExportRecipes,
)
from mealie.schema.response.responses import SuccessResponse from mealie.schema.response.responses import SuccessResponse
from mealie.services.recipe.recipe_bulk_service import RecipeBulkActionsService from mealie.services.recipe.recipe_bulk_service import RecipeBulkActionsService
@ -26,15 +20,16 @@ class RecipeBulkActionsController(BaseUserController):
def service(self) -> RecipeBulkActionsService: def service(self) -> RecipeBulkActionsService:
return RecipeBulkActionsService(self.repos, self.user, self.group) 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): def bulk_tag_recipes(self, tag_data: AssignTags):
self.service.assign_tags(tag_data.recipes, tag_data.tags) 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): def bulk_categorize_recipes(self, assign_cats: AssignCategories):
self.service.assign_categories(assign_cats.recipes, assign_cats.categories) 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): def bulk_delete_recipes(self, delete_recipes: DeleteRecipes):
self.service.delete_recipes(delete_recipes.recipes) self.service.delete_recipes(delete_recipes.recipes)

View File

@ -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 import CreateRecipe, CreateRecipeByUrlBulk, RecipeSummary
from mealie.schema.recipe.recipe_asset import RecipeAsset from mealie.schema.recipe.recipe_asset import RecipeAsset
from mealie.schema.recipe.recipe_scraper import ScrapeRecipeTest 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.response.responses import ErrorResponse
from mealie.schema.server.tasks import ServerTaskNames from mealie.schema.server.tasks import ServerTaskNames
from mealie.services import urls from mealie.services import urls
@ -59,10 +60,6 @@ class RecipeGetAll(GetAll):
load_food: bool = False load_food: bool = False
class UpdateImageResponse(BaseModel):
image: str
class FormatResponse(BaseModel): class FormatResponse(BaseModel):
jjson: list[str] = Field(..., alias="json") jjson: list[str] = Field(..., alias="json")
zip: list[str] zip: list[str]
@ -81,10 +78,10 @@ class RecipeExportController(BaseRecipeController):
def get_recipe_formats_and_templates(self): def get_recipe_formats_and_templates(self):
return TemplateService().templates return TemplateService().templates
@router_exports.post("/{slug}/exports") @router_exports.post("/{slug}/exports", response_model=RecipeZipTokenResponse)
def get_recipe_zip_token(self, slug: str): def get_recipe_zip_token(self, slug: str):
"""Generates a recipe zip token to be used to download a recipe as a zip file""" """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) @router_exports.get("/{slug}/exports", response_class=FileResponse)
def get_recipe_as_format(self, slug: str, template_name: str, temp_dir=Depends(temporary_dir)): def get_recipe_as_format(self, slug: str, template_name: str, temp_dir=Depends(temporary_dir)):

View File

@ -5,17 +5,17 @@ from fastapi import HTTPException, status
from mealie.core.security import create_access_token from mealie.core.security import create_access_token
from mealie.routes._base import BaseUserController, controller from mealie.routes._base import BaseUserController, controller
from mealie.routes._base.routers import UserAPIRouter 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"]) router = UserAPIRouter(prefix="/users", tags=["Users: Tokens"])
@controller(router) @controller(router)
class UserApiTokensController(BaseUserController): 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( def create_api_token(
self, self,
token_name: LoingLiveTokenIn, token_name: LongLiveTokenIn,
): ):
"""Create api_token in the Database""" """Create api_token in the Database"""
@ -33,9 +33,9 @@ class UserApiTokensController(BaseUserController):
new_token_in_db = self.repos.api_tokens.create(token_model) new_token_in_db = self.repos.api_tokens.create(token_model)
if new_token_in_db: 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): def delete_api_token(self, token_id: int):
"""Delete api_token from the Database""" """Delete api_token from the Database"""
token: LongLiveTokenInDB = self.repos.api_tokens.get(token_id) token: LongLiveTokenInDB = self.repos.api_tokens.get(token_id)
@ -45,6 +45,6 @@ class UserApiTokensController(BaseUserController):
if token.user.email == self.user.email: if token.user.email == self.user.email:
deleted_token = self.repos.api_tokens.delete(token_id) deleted_token = self.repos.api_tokens.delete(token_id)
return {"token_delete": deleted_token.name} return DeleteTokenResponse(token_delete=deleted_token.name)
else: else:
raise HTTPException(status.HTTP_403_FORBIDDEN) raise HTTPException(status.HTTP_403_FORBIDDEN)

View File

@ -1,6 +1,7 @@
# GENERATED CODE - DO NOT MODIFY BY HAND # GENERATED CODE - DO NOT MODIFY BY HAND
from .about import * from .about import *
from .backup import * from .backup import *
from .email import *
from .maintenance import * from .maintenance import *
from .migration import * from .migration import *
from .restore import * from .restore import *

View File

@ -28,10 +28,10 @@ class AdminAboutInfo(AppInfo):
class CheckAppConfig(MealieModel): class CheckAppConfig(MealieModel):
email_ready: bool = False email_ready: bool
ldap_ready: bool = False ldap_ready: bool
base_url_set: bool = False base_url_set: bool
is_up_to_date: bool = False is_up_to_date: bool
class DockerVolumeText(MealieModel): class DockerVolumeText(MealieModel):

View File

@ -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

View File

@ -1,3 +1,5 @@
from typing import Optional
from pydantic import UUID4 from pydantic import UUID4
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
@ -8,4 +10,4 @@ from .group_preferences import UpdateGroupPreferences
class GroupAdminUpdate(MealieModel): class GroupAdminUpdate(MealieModel):
id: UUID4 id: UUID4
name: str name: str
preferences: UpdateGroupPreferences preferences: Optional[UpdateGroupPreferences] = None

View File

@ -16,7 +16,7 @@ class PlanEntryType(str, Enum):
side = "side" side = "side"
class CreatRandomEntry(MealieModel): class CreateRandomEntry(MealieModel):
date: date date: date
entry_type: PlanEntryType = PlanEntryType.dinner entry_type: PlanEntryType = PlanEntryType.dinner

View File

@ -26,14 +26,3 @@ class AssignTags(ExportBase):
class DeleteRecipes(ExportBase): class DeleteRecipes(ExportBase):
pass pass
class BulkActionError(MealieModel):
recipe: str
error: str
class BulkActionsResponse(MealieModel):
success: bool
message: str
errors: list[BulkActionError] = []

View File

@ -12,3 +12,11 @@ class RecipeSlug(MealieModel):
class SlugResponse(BaseModel): class SlugResponse(BaseModel):
class Config: class Config:
schema_extra = {"example": "adult-mac-and-cheese"} schema_extra = {"example": "adult-mac-and-cheese"}
class UpdateImageResponse(BaseModel):
image: str
class RecipeZipTokenResponse(BaseModel):
token: str

View File

@ -2,4 +2,4 @@ from pydantic import BaseModel
class ValidationResponse(BaseModel): class ValidationResponse(BaseModel):
valid: bool = False valid: bool

View File

@ -1,4 +1,3 @@
from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any, Optional
from uuid import UUID from uuid import UUID
@ -18,19 +17,18 @@ from ..recipe import CategoryBase
settings = get_app_settings() settings = get_app_settings()
class LoingLiveTokenIn(MealieModel): class LongLiveTokenIn(MealieModel):
name: str name: str
class LongLiveTokenOut(LoingLiveTokenIn): class LongLiveTokenOut(MealieModel):
id: int token: str
created_at: datetime
class Config: class Config:
orm_mode = True orm_mode = True
class CreateToken(LoingLiveTokenIn): class CreateToken(LongLiveTokenIn):
user_id: UUID4 user_id: UUID4
token: str token: str
@ -38,6 +36,13 @@ class CreateToken(LoingLiveTokenIn):
orm_mode = True orm_mode = True
class DeleteTokenResponse(MealieModel):
token_delete: str
class Config:
orm_mode = True
class ChangePassword(MealieModel): class ChangePassword(MealieModel):
current_password: str current_password: str
new_password: str new_password: str