Files
hexabot/api/src/setting/services/setting.service.ts
Mohamed Marrouchi 30e5766487 feat: initial commit
2024-09-10 10:50:11 +01:00

131 lines
4.4 KiB
TypeScript

/*
* Copyright © 2024 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
* 3. SaaS Restriction: This software, or any derivative of it, may not be used to offer a competing product or service (SaaS) without prior written consent from Hexastack. Offering the software as a service or using it in a commercial cloud environment without express permission is strictly prohibited.
*/
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { Cache } from 'cache-manager';
import { config } from '@/config';
import { Config } from '@/config/types';
import { LoggerService } from '@/logger/logger.service';
import { SETTING_CACHE_KEY } from '@/utils/constants/cache';
import { Cacheable } from '@/utils/decorators/cacheable.decorator';
import { BaseService } from '@/utils/generics/base-service';
import { SettingCreateDto } from '../dto/setting.dto';
import { SettingRepository } from '../repositories/setting.repository';
import { Setting } from '../schemas/setting.schema';
import { Settings } from '../schemas/types';
import { SettingSeeder } from '../seeds/setting.seed';
@Injectable()
export class SettingService extends BaseService<Setting> {
constructor(
readonly repository: SettingRepository,
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
private readonly logger: LoggerService,
private readonly seeder: SettingSeeder,
) {
super(repository);
}
/**
* Seeds the settings if they don't already exist for the provided group.
*
* @param group - The group of settings to check.
* @param data - The array of settings to seed if none exist.
*/
async seedIfNotExist(group: string, data: SettingCreateDto[]) {
const count = await this.count({ group });
if (count === 0) {
await this.seeder.seed(data);
}
}
/**
* Loads all settings and returns them grouped in ascending order by weight.
*
* @returns A grouped object of settings.
*/
async load() {
const settings = await this.findAll(['weight', 'asc']);
return this.group(settings);
}
/**
* Builds a tree structure from the settings array.
*
* Each setting is grouped by its `group` and returned as a structured object.
*
* @param settings - An array of settings to build into a tree structure.
*
* @returns A `Settings` object organized by group.
*/
public buildTree(settings: Setting[]): Settings {
return settings.reduce((acc: Settings, s: Setting) => {
const groupKey = s.group || 'undefinedGroup';
acc[groupKey] = acc[groupKey] || {};
acc[groupKey][s.label] = s.value;
return acc;
}, {} as Settings);
}
/**
* Groups the settings into a record where the key is the setting group and
* the value is an array of settings in that group.
*
* @param settings - An array of settings to group.
*
* @returns A record where each key is a group and each value is an array of settings.
*/
public group(settings: Setting[]): Record<string, Setting[]> {
return (
settings?.reduce((acc, curr) => {
const group = acc[curr.group] || [];
group.push(curr);
acc[curr.group] = group;
return acc;
}, {}) || {}
);
}
/**
* Retrieves the application configuration object.
*
* @returns The global configuration object.
*/
getConfig(): Config {
return config;
}
/**
* Event handler for setting updates. Listens to 'hook:settings:*:*' events
* and invalidates the cache for settings when triggered.
*/
@OnEvent('hook:settings:*:*')
async handleSettingUpdateEvent() {
this.cacheManager.del(SETTING_CACHE_KEY);
}
/**
* Retrieves settings from the cache if available, or loads them from the
* repository and caches the result.
*
* @returns A promise that resolves to a `Settings` object.
*/
@Cacheable(SETTING_CACHE_KEY)
async getSettings(): Promise<Settings> {
const settings = await this.findAll();
return this.buildTree(settings);
}
}