mirror of
https://github.com/unraid/api.git
synced 2025-12-30 21:19:49 -06:00
refactor: update notifications.resolver to handle filtering
- Updates the getNotifications function to use the refactored getNotificationsFromPaths function - Adds filtering logic to the updated getNotificationsFromPaths function - Update JSdocs
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -55,6 +55,9 @@ typings/
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Jetbrains Settings Files
|
||||
.idea
|
||||
|
||||
# Temp dir for tests
|
||||
test/__temp__/*
|
||||
|
||||
|
||||
82
api/.gitignore
vendored
Normal file
82
api/.gitignore
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
# Logs
|
||||
./logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
coverage-ts
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# Visual Studio Code workspace
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Temp dir for tests
|
||||
test/__temp__/*
|
||||
|
||||
# Built files
|
||||
dist
|
||||
|
||||
# Typescript
|
||||
typescript
|
||||
|
||||
# Ultra runner
|
||||
.ultra.cache.json
|
||||
|
||||
# Github actions
|
||||
RELEASE_NOTES.md
|
||||
|
||||
# Docker Deploy Folder
|
||||
deploy/*
|
||||
!deploy/.gitkeep
|
||||
|
||||
# pkg cache
|
||||
.pkg-cache
|
||||
|
||||
# IDE Settings Files
|
||||
.idea
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
Importance,
|
||||
NotificationType,
|
||||
type Notification,
|
||||
type NotificationInput,
|
||||
} from '@app/graphql/generated/api/types';
|
||||
import { NotificationSchema } from '@app/graphql/generated/api/operations';
|
||||
import { type RootState, type AppDispatch } from '@app/store/index';
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { type NotificationFilter } from '@app/graphql/generated/api/types';
|
||||
import { getters } from '@app/store/index';
|
||||
import { Query, Resolver, Args, Subscription } from '@nestjs/graphql';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { UseRoles } from 'nest-access-control';
|
||||
import { PUBSUB_CHANNEL, createSubscription } from '@app/core/pubsub';
|
||||
import { NotificationsService } from './notifications.service';
|
||||
@@ -18,9 +16,9 @@ export class NotificationsResolver {
|
||||
})
|
||||
public async notifications(
|
||||
@Args('filter')
|
||||
{ limit, importance, type, offset }: NotificationFilter
|
||||
filters: NotificationFilter
|
||||
) {
|
||||
return await this.notificationsService.getNotifications();
|
||||
await this.notificationsService.getNotifications(filters);
|
||||
}
|
||||
|
||||
@Subscription('notificationAdded')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NotificationIni } from '@app/core/types/states/notification';
|
||||
import { parseConfig } from '@app/core/utils/misc/parse-config';
|
||||
import { NotificationSchema } from '@app/graphql/generated/api/operations';
|
||||
import { Importance, NotificationType, type Notification, } from '@app/graphql/generated/api/types';
|
||||
import {Importance, NotificationType, type Notification, NotificationFilter,} from '@app/graphql/generated/api/types';
|
||||
import { getters } from '@app/store';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { readdir, stat } from 'fs/promises';
|
||||
import { readdir } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { isFulfilled, isRejected } from '@app/utils';
|
||||
@@ -18,58 +18,59 @@ export class NotificationsService {
|
||||
*
|
||||
* @returns An array of all notifications in the system.
|
||||
*/
|
||||
public async getNotifications(): Promise<Notification[]> {
|
||||
public async getNotifications(filters: NotificationFilter): Promise<Notification[]> {
|
||||
this.logger.debug('Getting Notifications');
|
||||
const logErrors = (error: unknown) => this.logger.error(error);
|
||||
|
||||
const notificationBasePath = getters.dynamix().notify!.path;
|
||||
const unreadDirectoryPath = join(notificationBasePath, NotificationType.UNREAD.toLowerCase());
|
||||
const archivedDirectoryPath = join(notificationBasePath, NotificationType.ARCHIVE.toLowerCase());
|
||||
const directoryPath = filters.type === NotificationType.ARCHIVE ? archivedDirectoryPath : unreadDirectoryPath;
|
||||
const unreadFiles = await this.getFilesInFolder(directoryPath);
|
||||
const [notifications] = await this.getNotificationsFromPaths(unreadFiles, filters);
|
||||
|
||||
const [unreadNotifications, unreadNotificationErrors] = await this.getUnreadNotifications(notificationBasePath);
|
||||
|
||||
this.logger.debug(`${unreadNotifications.length} Unread Notifications`);
|
||||
this.logger.debug(`${unreadNotificationErrors.length} Unread Notification Errors`);
|
||||
unreadNotificationErrors.forEach(logErrors);
|
||||
|
||||
const [archivedNotifications, archivedNotificationErrors] = await this.getArchiveNotifications(notificationBasePath);
|
||||
|
||||
this.logger.debug(`${archivedNotifications.length} Archived Notifications`);
|
||||
this.logger.debug(`${archivedNotificationErrors.length} Archived Notification Errors`);
|
||||
archivedNotificationErrors.forEach(logErrors);
|
||||
|
||||
return [...unreadNotifications, ...archivedNotifications];
|
||||
return notifications;
|
||||
}
|
||||
|
||||
private getUnreadNotifications(notificationsDirectory: string) {
|
||||
const unreadsDirectoryPath = join(notificationsDirectory, NotificationType.UNREAD.toLowerCase());
|
||||
return this.getNotificationsFromDirectory(unreadsDirectoryPath, NotificationType.UNREAD);
|
||||
}
|
||||
private async getFilesInFolder(folderPath: string): Promise<string[]> {
|
||||
const contents = await readdir(folderPath);
|
||||
|
||||
private getArchiveNotifications(notificationsDirectory: string) {
|
||||
const archivedDirectoryPath = join(notificationsDirectory, NotificationType.ARCHIVE.toLowerCase());
|
||||
return this.getNotificationsFromDirectory(archivedDirectoryPath, NotificationType.ARCHIVE);
|
||||
return contents.map((content) => join(folderPath, content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a directory path, reads all the files in the directory,
|
||||
* Given a an array of files, reads and filters all the files in the directory,
|
||||
* and attempts to parse each file as a Notification.
|
||||
* Returns an array of two elements:
|
||||
* - the first element is an array of successfully parsed Notifications,
|
||||
* - the first element is an array of successfully parsed and filtered Notifications,
|
||||
* - the second element is an array of errors for any files that failed parsing.
|
||||
* @param containingDirectory the directory to read
|
||||
* @param type the type of notification to load
|
||||
* @param files the files to read
|
||||
* @param filters the filters to apply to the notifications
|
||||
* @returns an array of two elements: [successes, errors/failures]
|
||||
*/
|
||||
private async getNotificationsFromDirectory(containingDirectory: string, type: NotificationType): Promise<[Notification[], unknown[]]> {
|
||||
const loadNotification = (filePath: string) => this.loadNotificationFile(filePath, type);
|
||||
private async getNotificationsFromPaths(files: string[], filters: NotificationFilter): Promise<[Notification[], unknown[]]> {
|
||||
const { limit, importance, type, offset } = filters;
|
||||
|
||||
const contents = await readdir(containingDirectory);
|
||||
const absolutePaths = contents.map((content) => join(containingDirectory, content));
|
||||
const fileReads = absolutePaths.map(loadNotification);
|
||||
const fileReads = files.slice(offset, limit + offset).map((file) => this.loadNotificationFile(file, type ?? NotificationType.UNREAD));
|
||||
const results = await Promise.allSettled(fileReads);
|
||||
|
||||
return [
|
||||
results.filter(isFulfilled).map((result) => result.value),
|
||||
results.filter(isRejected).map((result) => result.reason),
|
||||
results.filter(isFulfilled).map(result => result.value).filter((notification) => {
|
||||
if (importance && importance !== notification.importance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type && type !== notification.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.sort(
|
||||
(a, b) =>
|
||||
new Date(b.timestamp ?? 0).getTime() -
|
||||
new Date(a.timestamp ?? 0).getTime()
|
||||
),
|
||||
results.filter(isRejected).map((result) => result.reason),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user