mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 18:23:18 -04:00 
			
		
		
		
	events api
This commit is contained in:
		| @@ -0,0 +1,42 @@ | |||||||
|  | import { requests } from "../requests"; | ||||||
|  | import { BaseCRUDAPI } from "./_base"; | ||||||
|  |  | ||||||
|  | export type EventCategory = "general" | "recipe" | "backup" | "scheduled" | "migration" | "group" | "user"; | ||||||
|  | export type DeclaredTypes = "General" | "Discord" | "Gotify" | "Pushover" | "Home Assistant"; | ||||||
|  | export type GotifyPriority = "low" | "moderate" | "normal" | "high"; | ||||||
|  |  | ||||||
|  | export interface EventNotification { | ||||||
|  |   id?: number; | ||||||
|  |   name?: string; | ||||||
|  |   type?: DeclaredTypes & string; | ||||||
|  |   general?: boolean; | ||||||
|  |   recipe?: boolean; | ||||||
|  |   backup?: boolean; | ||||||
|  |   scheduled?: boolean; | ||||||
|  |   migration?: boolean; | ||||||
|  |   group?: boolean; | ||||||
|  |   user?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface CreateEventNotification extends EventNotification { | ||||||
|  |   notificationUrl?: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const prefix = "/api"; | ||||||
|  |  | ||||||
|  | const routes = { | ||||||
|  |   aboutEventsNotifications: `${prefix}/about/events/notifications`, | ||||||
|  |   aboutEventsNotificationsTest: `${prefix}/about/events/notifications/test`, | ||||||
|  |  | ||||||
|  |   aboutEventsNotificationsId: (id: number) => `${prefix}/about/events/notifications/${id}`, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export class NotificationsAPI extends BaseCRUDAPI<EventNotification, CreateEventNotification> { | ||||||
|  |   baseRoute = routes.aboutEventsNotifications; | ||||||
|  |   itemRoute = routes.aboutEventsNotificationsId; | ||||||
|  |   /** Returns the Group Data for the Current User | ||||||
|  |    */ | ||||||
|  |   async testNotification(id: number) { | ||||||
|  |     return await requests.post(routes.aboutEventsNotificationsTest, { id }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import { UploadFile } from "./class-interfaces/upload"; | |||||||
| import { CategoriesAPI } from "./class-interfaces/categories"; | import { CategoriesAPI } from "./class-interfaces/categories"; | ||||||
| import { TagsAPI } from "./class-interfaces/tags"; | import { TagsAPI } from "./class-interfaces/tags"; | ||||||
| import { UtilsAPI } from "./class-interfaces/utils"; | import { UtilsAPI } from "./class-interfaces/utils"; | ||||||
|  | import { NotificationsAPI } from "./class-interfaces/event-notifications"; | ||||||
| import { ApiRequestInstance } from "~/types/api"; | import { ApiRequestInstance } from "~/types/api"; | ||||||
|  |  | ||||||
| class Api { | class Api { | ||||||
| @@ -21,6 +22,7 @@ class Api { | |||||||
|   public categories: CategoriesAPI; |   public categories: CategoriesAPI; | ||||||
|   public tags: TagsAPI; |   public tags: TagsAPI; | ||||||
|   public utils: UtilsAPI; |   public utils: UtilsAPI; | ||||||
|  |   public notifications: NotificationsAPI; | ||||||
|  |  | ||||||
|   // Utils |   // Utils | ||||||
|   public upload: UploadFile; |   public upload: UploadFile; | ||||||
| @@ -43,6 +45,7 @@ class Api { | |||||||
|     this.debug = new DebugAPI(requests); |     this.debug = new DebugAPI(requests); | ||||||
|     this.events = new EventsAPI(requests); |     this.events = new EventsAPI(requests); | ||||||
|     this.backups = new BackupAPI(requests); |     this.backups = new BackupAPI(requests); | ||||||
|  |     this.notifications = new NotificationsAPI(requests); | ||||||
|  |  | ||||||
|     // Utils |     // Utils | ||||||
|     this.upload = new UploadFile(requests); |     this.upload = new UploadFile(requests); | ||||||
|   | |||||||
							
								
								
									
										88
									
								
								frontend/composables/use-notifications.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								frontend/composables/use-notifications.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | import { useAsync, ref } from "@nuxtjs/composition-api"; | ||||||
|  | import { CreateEventNotification } from "@/api/class-interfaces/event-notifications"; | ||||||
|  | import { useAsyncKey } from "./use-utils"; | ||||||
|  | import { useApiSingleton } from "~/composables/use-api"; | ||||||
|  |  | ||||||
|  | const notificationTypes = ["General", "Discord", "Gotify", "Pushover", "Home Assistant"]; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export const useNotifications = function () { | ||||||
|  |   const api = useApiSingleton(); | ||||||
|  |   const loading = ref(false); | ||||||
|  |  | ||||||
|  |   const createNotificationData = ref<CreateEventNotification>({ | ||||||
|  |     name: "", | ||||||
|  |     type: "General", | ||||||
|  |     general: true, | ||||||
|  |     recipe: true, | ||||||
|  |     backup: true, | ||||||
|  |     scheduled: true, | ||||||
|  |     migration: true, | ||||||
|  |     group: true, | ||||||
|  |     user: true, | ||||||
|  |     notificationUrl: "", | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const deleteTarget = ref(0) | ||||||
|  |  | ||||||
|  |   function getNotifications() { | ||||||
|  |     loading.value = true; | ||||||
|  |     const notifications = useAsync(async () => { | ||||||
|  |       const { data } = await api.notifications.getAll(); | ||||||
|  |       return data; | ||||||
|  |     }, useAsyncKey()); | ||||||
|  |     loading.value = false; | ||||||
|  |     return notifications; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async function refreshNotifications() { | ||||||
|  |     loading.value = true; | ||||||
|  |     const { data } = await api.notifications.getAll(); | ||||||
|  |     if (data) { | ||||||
|  |       notifications.value = data; | ||||||
|  |     } | ||||||
|  |     loading.value = false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async function createNotification() { | ||||||
|  |     if (createNotificationData.value.name === "" || createNotificationData.value.notificationUrl === "") { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     const { response } = await api.notifications.createOne(createNotificationData.value); | ||||||
|  |  | ||||||
|  |     if (response?.status === 200) { | ||||||
|  |       refreshNotifications(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async function deleteNotification() { | ||||||
|  |     const { response } = await api.notifications.deleteOne(deleteTarget.value); | ||||||
|  |     if (response?.status === 200) { | ||||||
|  |       refreshNotifications(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async function testById() { | ||||||
|  |       // TODO: Test by ID | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async function testByUrl() { | ||||||
|  |       // TODO: Test by URL | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const notifications = getNotifications(); | ||||||
|  |  | ||||||
|  |   return { | ||||||
|  |     createNotification, | ||||||
|  |     deleteNotification, | ||||||
|  |     refreshNotifications, | ||||||
|  |     getNotifications, | ||||||
|  |     testById, | ||||||
|  |     testByUrl, | ||||||
|  |     notifications, | ||||||
|  |     loading, | ||||||
|  |     createNotificationData, | ||||||
|  |     notificationTypes, | ||||||
|  |     deleteTarget, | ||||||
|  |   }; | ||||||
|  | }; | ||||||
| @@ -2,17 +2,213 @@ | |||||||
|   <v-container fluid> |   <v-container fluid> | ||||||
|     <BaseCardSectionTitle title="Event Notifications"> |     <BaseCardSectionTitle title="Event Notifications"> | ||||||
|       {{ $t("events.new-notification-form-description") }} |       {{ $t("events.new-notification-form-description") }} | ||||||
|  |  | ||||||
|  |       <div class="d-flex justify-space-around"> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki" target="_blanks"> Apprise </a> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki/Notify_gotify" target="_blanks"> Gotify </a> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki/Notify_discord" target="_blanks"> Discord </a> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki/Notify_homeassistant" target="_blanks"> Home Assistant </a> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki/Notify_matrix" target="_blanks"> Matrix </a> | ||||||
|  |         <a href="https://github.com/caronc/apprise/wiki/Notify_pushover" target="_blanks"> Pushover </a> | ||||||
|  |       </div> | ||||||
|     </BaseCardSectionTitle> |     </BaseCardSectionTitle> | ||||||
|  |  | ||||||
|  |     <BaseDialog | ||||||
|  |       ref="domDeleteConfirmation" | ||||||
|  |       :title="$t('settings.backup.delete-backup')" | ||||||
|  |       color="error" | ||||||
|  |       :icon="$globals.icons.alertCircle" | ||||||
|  |       @confirm="deleteNotification()" | ||||||
|  |     > | ||||||
|  |       <v-card-text> | ||||||
|  |         {{ $t("general.confirm-delete-generic") }} | ||||||
|  |       </v-card-text> | ||||||
|  |     </BaseDialog> | ||||||
|  |  | ||||||
|  |     <v-toolbar flat class="justify-between"> | ||||||
|  |       <BaseDialog | ||||||
|  |         :icon="$globals.icons.bellAlert" | ||||||
|  |         :title="$t('general.new') + ' ' + $t('events.notification')" | ||||||
|  |         @submit="createNotification" | ||||||
|  |       > | ||||||
|  |         <template #activator="{ open }"> | ||||||
|  |           <BaseButton @click="open"> {{ $t("events.notification") }}</BaseButton> | ||||||
|  |         </template> | ||||||
|  |  | ||||||
|  |         <v-card-text> | ||||||
|  |           <v-select | ||||||
|  |             v-model="createNotificationData.type" | ||||||
|  |             :items="notificationTypes" | ||||||
|  |             :label="$t('general.type')" | ||||||
|  |           ></v-select> | ||||||
|  |           <v-text-field v-model="createNotificationData.name" :label="$t('general.name')"></v-text-field> | ||||||
|  |           <v-text-field | ||||||
|  |             v-model="createNotificationData.notificationUrl" | ||||||
|  |             :label="$t('events.apprise-url')" | ||||||
|  |           ></v-text-field> | ||||||
|  |  | ||||||
|  |           <BaseButton class="d-flex ml-auto" small color="info" @click="testByUrl(newNotification.notificationUrl)"> | ||||||
|  |             <template #icon> {{ $globals.icons.testTube }}</template> | ||||||
|  |             {{ $t("general.test") }} | ||||||
|  |           </BaseButton> | ||||||
|  |  | ||||||
|  |           <p class="text-uppercase">{{ $t("events.subscribed-events") }}</p> | ||||||
|  |           <div class="d-flex flex-wrap justify-center"> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.general" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('general.general')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.recipe" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('general.recipe')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.backup" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('settings.backup-and-exports')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.scheduled" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('events.scheduled')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.migration" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('settings.migrations')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.group" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('group.group')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |             <v-checkbox | ||||||
|  |               v-model="createNotificationData.user" | ||||||
|  |               class="mb-n2 mt-n2 mx-2" | ||||||
|  |               :label="$t('user.user')" | ||||||
|  |             ></v-checkbox> | ||||||
|  |           </div> | ||||||
|  |         </v-card-text> | ||||||
|  |       </BaseDialog> | ||||||
|  |     </v-toolbar> | ||||||
|  |  | ||||||
|  |     <!-- Data Table --> | ||||||
|  |     <v-data-table | ||||||
|  |       :headers="headers" | ||||||
|  |       :items="notifications || []" | ||||||
|  |       class="elevation-0" | ||||||
|  |       hide-default-footer | ||||||
|  |       disable-pagination | ||||||
|  |     > | ||||||
|  |       <template v-for="boolHeader in headers" #[`item.${boolHeader.value}`]="{ item }"> | ||||||
|  |         <div :key="boolHeader.value"> | ||||||
|  |           <div v-if="boolHeader.value === 'type'"> | ||||||
|  |             {{ item[boolHeader.value] }} | ||||||
|  |           </div> | ||||||
|  |           <v-icon | ||||||
|  |             v-else-if="item[boolHeader.value] === true || item[boolHeader.value] === false" | ||||||
|  |             :color="item[boolHeader.value] ? 'success' : 'gray'" | ||||||
|  |           > | ||||||
|  |             {{ item[boolHeader.value] ? $globals.icons.check : $globals.icons.close }} | ||||||
|  |           </v-icon> | ||||||
|  |           <div v-else-if="boolHeader.value === 'actions'" class="d-flex"> | ||||||
|  |             <BaseButton | ||||||
|  |               class="mr-1" | ||||||
|  |               delete | ||||||
|  |               x-small | ||||||
|  |               minor | ||||||
|  |               @click=" | ||||||
|  |                 deleteTarget = item.id; | ||||||
|  |                 domDeleteConfirmation.open(); | ||||||
|  |               " | ||||||
|  |             /> | ||||||
|  |             <BaseButton edit x-small @click="testById(item.id)"> | ||||||
|  |               <template #icon> | ||||||
|  |                 {{ $globals.icons.testTube }} | ||||||
|  |               </template> | ||||||
|  |               {{ $t("general.test") }} | ||||||
|  |             </BaseButton> | ||||||
|  |           </div> | ||||||
|  |           <div v-else> | ||||||
|  |             {{ item[boolHeader.value] }} | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </v-data-table> | ||||||
|   </v-container> |   </v-container> | ||||||
| </template> | </template> | ||||||
|      |      | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { defineComponent } from "@nuxtjs/composition-api"; | import { defineComponent, reactive, useContext, toRefs, ref } from "@nuxtjs/composition-api"; | ||||||
|  | import { useNotifications } from "@/composables/use-notifications"; | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   layout: "admin", |   layout: "admin", | ||||||
|   setup() { |   setup() { | ||||||
|     return {}; |     // @ts-ignore -> Ignore missing $globals | ||||||
|  |     const { i18n } = useContext(); | ||||||
|  |  | ||||||
|  |     const state = reactive({ | ||||||
|  |       headers: [ | ||||||
|  |         { text: i18n.t("general.type"), value: "type" }, | ||||||
|  |         { text: i18n.t("general.name"), value: "name" }, | ||||||
|  |         { text: i18n.t("general.general"), value: "general", align: "center" }, | ||||||
|  |         { text: i18n.t("general.recipe"), value: "recipe", align: "center" }, | ||||||
|  |         { text: i18n.t("events.database"), value: "backup", align: "center" }, | ||||||
|  |         { text: i18n.t("events.scheduled"), value: "scheduled", align: "center" }, | ||||||
|  |         { text: i18n.t("settings.migrations"), value: "migration", align: "center" }, | ||||||
|  |         { text: i18n.t("group.group"), value: "group", align: "center" }, | ||||||
|  |         { text: i18n.t("user.user"), value: "user", align: "center" }, | ||||||
|  |         { text: "", value: "actions" }, | ||||||
|  |       ], | ||||||
|  |       keepDialogOpen: false, | ||||||
|  |       notifications: [], | ||||||
|  |       newNotification: { | ||||||
|  |         type: "General", | ||||||
|  |         name: "", | ||||||
|  |         notificationUrl: "", | ||||||
|  |       }, | ||||||
|  |       newNotificationOptions: { | ||||||
|  |         general: true, | ||||||
|  |         recipe: true, | ||||||
|  |         backup: true, | ||||||
|  |         scheduled: true, | ||||||
|  |         migration: true, | ||||||
|  |         group: true, | ||||||
|  |         user: true, | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     const { | ||||||
|  |       deleteNotification, | ||||||
|  |       createNotification, | ||||||
|  |       refreshNotifications, | ||||||
|  |       notifications, | ||||||
|  |       loading, | ||||||
|  |       testById, | ||||||
|  |       testByUrl, | ||||||
|  |       createNotificationData, | ||||||
|  |       notificationTypes, | ||||||
|  |       deleteTarget, | ||||||
|  |     } = useNotifications(); | ||||||
|  |  | ||||||
|  |     // API | ||||||
|  |     const domDeleteConfirmation = ref(null); | ||||||
|  |     return { | ||||||
|  |       ...toRefs(state), | ||||||
|  |       domDeleteConfirmation, | ||||||
|  |       notifications, | ||||||
|  |       loading, | ||||||
|  |       createNotificationData, | ||||||
|  |       deleteNotification, | ||||||
|  |       deleteTarget, | ||||||
|  |       createNotification, | ||||||
|  |       refreshNotifications, | ||||||
|  |       testById, | ||||||
|  |       testByUrl, | ||||||
|  |       notificationTypes, | ||||||
|  |     }; | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user