mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
Consolidate frontend types (#1245)
This commit is contained in:
parent
6a88a59981
commit
479900e912
File diff suppressed because one or more lines are too long
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 = {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
export interface ServerTask {
|
|
||||||
id: number;
|
|
||||||
groupId: number;
|
|
||||||
callback: string;
|
|
||||||
createdAt: string;
|
|
||||||
status: string;
|
|
||||||
log: string;
|
|
||||||
}
|
|
@ -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>
|
||||||
|
|
||||||
|
@ -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: "",
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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: {
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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[]>
|
||||||
) => {
|
) => {
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 = {
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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[],
|
||||||
});
|
});
|
||||||
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -18,5 +18,5 @@ export interface SuccessResponse {
|
|||||||
error?: boolean;
|
error?: boolean;
|
||||||
}
|
}
|
||||||
export interface ValidationResponse {
|
export interface ValidationResponse {
|
||||||
valid?: boolean;
|
valid: boolean;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)):
|
||||||
|
@ -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)
|
||||||
|
@ -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 *
|
||||||
|
@ -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):
|
||||||
|
14
mealie/schema/admin/email.py
Normal file
14
mealie/schema/admin/email.py
Normal 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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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] = []
|
|
||||||
|
@ -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
|
||||||
|
@ -2,4 +2,4 @@ from pydantic import BaseModel
|
|||||||
|
|
||||||
|
|
||||||
class ValidationResponse(BaseModel):
|
class ValidationResponse(BaseModel):
|
||||||
valid: bool = False
|
valid: bool
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user