File

src/module/pdf/file.service.ts

Index

Properties

Properties

sheetNo
sheetNo: string
Type : string
teamName
teamName: string
Type : string
import { Injectable } from '@nestjs/common';
import pug, { LocalsObject } from 'pug';
import { ITeamId } from 'shared/model/Team';
import { Sheet } from '../../database/entities/sheet.entity';
import { SettingsService } from '../settings/settings.service';
import { SheetService } from '../sheet/sheet.service';
import { TeamService } from '../team/team.service';
import { Template } from '../template/template.types';
import { TutorialService } from '../tutorial/tutorial.service';

export interface GenerateFilenameParams {
    sheetId: string;
    teamId: ITeamId;
}

export interface GenerateTutorialFilenameParams {
    sheetId: string;
    tutorialId: string;
}

type Extension = 'pdf' | 'zip';

interface FileNameParams {
    sheet: Sheet;
    teamName: string;
    extension?: Extension;
}

interface TutorialGradingFilenameParams {
    sheet: Sheet;
    tutorialSlot: string;
    extension?: Extension;
}

interface FilenameAttributes {
    sheetNo: string;
    teamName: string;
}

interface TutorialFilenameAttributes {
    sheetNo: string;
    tutorialSlot: string;
}

@Injectable()
export class FileService {
    private gradingFilename: Template<FilenameAttributes> | undefined;
    private tutorialGradingFilename: Template<TutorialFilenameAttributes> | undefined;

    constructor(
        private readonly sheetService: SheetService,
        private readonly teamService: TeamService,
        private readonly tutorialService: TutorialService,
        private readonly settingsService: SettingsService
    ) {}

    /**
     * Generates a grading filename without an extension.
     *
     * @param dto Params to generate the filename from.
     *
     * @returns Generated filename.
     */
    async generateGradingFilename(dto: GenerateFilenameParams): Promise<string> {
        const { sheetId, teamId } = dto;
        const sheet = await this.sheetService.findById(sheetId);
        const team = await this.teamService.findById(teamId);
        return this.getGradingFilename({ sheet, teamName: team.getTeamName() });
    }

    /**
     * Generates a filename for a grading zip file containing the gradings of all teams within a tutorial without an extension.
     *
     * @param dto Params to generate the filename from.
     *
     * @returns Generated filename.
     */
    async generateTutorialGradingFilename(dto: GenerateTutorialFilenameParams): Promise<string> {
        const { sheetId, tutorialId } = dto;
        const sheet = await this.sheetService.findById(sheetId);
        const tutorial = await this.tutorialService.findById(tutorialId);
        return this.getTutorialGradingFilename({
            sheet: sheet,
            tutorialSlot: tutorial.slot,
        });
    }

    /**
     * Creates a filename from the given sheet number and teamName.
     *
     * This function behaves like a sync function except the `this.filenameTemplate` property is not set yet. If it is set no internal async calls are made.
     *
     * @param sheet Sheet
     * @param teamName Name of the team.
     * @param extension Extension of the filename. Either 'pdf' or 'zip'. (__without__ leading '.').
     *
     * @returns Created filename.
     */
    async getGradingFilename({ sheet, teamName, extension }: FileNameParams): Promise<string> {
        await this.loadFilenameTemplates();

        const filename =
            this.gradingFilename?.({
                sheetNo: sheet.sheetNoAsString,
                teamName,
            }) ?? 'NO_FILE_NAME';

        return !!extension ? `${filename}.${extension}` : filename;
    }

    /**
     * Creates a filename for a file containing multiple gradings of a tutorial.
     *
     * @param sheet Sheet
     * @param tutorialSlot Slot of the tutorial.
     * @param extension Extension of the filename. Either 'pdf' or 'zip'. (__without__ leading '.').
     *
     * @returns Created filename.
     */
    private async getTutorialGradingFilename({
        sheet,
        tutorialSlot,
        extension,
    }: TutorialGradingFilenameParams): Promise<string> {
        await this.loadFilenameTemplates();

        const filename =
            this.tutorialGradingFilename?.({
                sheetNo: sheet.sheetNoAsString,
                tutorialSlot,
            }) ?? 'NO_FILE_NAME';

        return !!extension ? `${filename}.${extension}` : filename;
    }

    /**
     * Loads and compiles the template string for the gradings filename.
     *
     * Afterwards the `this.filenameTemplate` property is set to the compiled template.
     */
    private async loadFilenameTemplates(): Promise<void> {
        const { gradingFilename, tutorialGradingFilename } =
            await this.settingsService.getClientSettings();

        this.gradingFilename = this.parseAndCompileFilenameTemplate(gradingFilename);
        this.tutorialGradingFilename =
            this.parseAndCompileFilenameTemplate(tutorialGradingFilename);
    }

    /**
     * Adds a leading '|' if necessary and returns the compile pug template.
     *
     * @param template Pug-template to adjust
     *
     * @returns Compiled pug-template.
     */
    private parseAndCompileFilenameTemplate<T extends LocalsObject>(template: string): Template<T> {
        let parsedTemplate: string;
        if (template.startsWith('|')) {
            parsedTemplate = template;
        } else {
            parsedTemplate = `|${template}`;
        }

        return pug.compile(parsedTemplate);
    }
}

results matching ""

    No results matching ""