services/SeasonTeamService.jsjavascript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("../utils/errors.js");
const seasonTeam_1 = __importDefault(require("../db/models/seasonTeam"));
const MemberService_1 = __importDefault(require("./MemberService"));
const SeasonService_1 = __importDefault(require("./SeasonService"));
const accessControl_1 = require("../utils/accessControl");
const TeamService_1 = __importDefault(require("./TeamService"));
const { logger } = require("../plugins/winston");
const { Op } = require("sequelize");
/**
 * Service for managing season-team associations.
 * Handles CRUD operations and logic for teams within a season.
 *
 * @class SeasonTeamService
 */
class SeasonTeamService {
    /**
     * Find a season team by ID.
     * @param {UUID} id - The ID of the season team.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @param {boolean} isAdmin - Whether the user is an admin.
     * @returns {Promise<Object>} The season team object.
     */
    async findById(id, actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService findById ${JSON.stringify({ id, actingUserId, isAdmin })}`);
        const seasonTeam = await seasonTeam_1.default.findByPk(id);
        if (!seasonTeam) {
            return null;
        }
        await (0, accessControl_1.checkReadAccess)(seasonTeam.UserId, actingUserId, isAdmin);
        return seasonTeam_1.default.findOne({
            where: { id },
            include: ["Choreos", "Members"],
            order: [
                [seasonTeam_1.default.associations.Members, "name"],
                [seasonTeam_1.default.associations.Choreos, "name"],
            ],
        }); // njsscan-ignore: node_nosqli_injection
    }
    /**
     * Get all season teams.
     * @param {UUID[]} ownerIds - The IDs of the owners.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @param {boolean} [isAdmin=false]
     * @returns {Promise<Array>} List of all season teams.
     */
    async getAll(ownerIds, actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService getAll ${JSON.stringify({ ownerIds, actingUserId, isAdmin })}`);
        const accessibleOwnerIds = ownerIds.length > 0
            ? await (0, accessControl_1.filterAccessibleOwnerIds)(ownerIds, actingUserId, isAdmin)
            : [actingUserId];
        return seasonTeam_1.default.findAll({
            where: { UserId: { [Op.in]: accessibleOwnerIds } },
            include: ["Season", "Team", "User"],
        });
    }
    /**
     * Get the count of season teams.
     * @returns {Promise<number>} The count of season teams.
     */
    getCount() {
        logger.debug(`SeasonTeamService getCount`);
        return seasonTeam_1.default.count();
    }
    /**
     * Get the trend of season teams created and deleted in the last 30 days.
     * @returns {Promise<number>} The trend value (created - deleted).
     */
    getTrend() {
        logger.debug(`SeasonTeamService getTrend`);
        return Promise.all([
            seasonTeam_1.default.count({
                where: {
                    createdAt: {
                        [Op.gt]: new Date().valueOf() - 1000 * 60 * 60 * 24 * 30,
                    },
                },
            }),
            seasonTeam_1.default.count({
                where: {
                    deletedAt: {
                        [Op.gt]: new Date().valueOf() - 1000 * 60 * 60 * 24 * 30,
                    },
                },
            }),
        ]).then(([created, deleted]) => created - deleted);
    }
    /**
     * Create a new season team and copy members into it.
     * @param {UUID} TeamId - The ID of the team.
     * @param {UUID} SeasonId - The ID of the season.
     * @param {Array<string>} memberIds - List of member IDs to copy.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @param {boolean} [isAdmin=false]
     * @returns {Promise<Object>} The created season team object.
     */
    async create(TeamId, SeasonId, memberIds = [], actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService create ${JSON.stringify({
            TeamId,
            SeasonId,
            memberIds,
            actingUserId,
            isAdmin,
        })}`);
        // Inherit ownerId from parent Team
        const team = await TeamService_1.default.findById(TeamId, actingUserId, isAdmin);
        if (!team) {
            throw new errors_1.NotFoundError(`Team with ID ${TeamId} not found`);
        }
        const ownerId = team.UserId;
        await (0, accessControl_1.checkWriteAccess)(ownerId, actingUserId, isAdmin);
        return seasonTeam_1.default.create({
            TeamId,
            SeasonId,
            UserId: ownerId,
            creatorId: actingUserId,
            updaterId: actingUserId,
        }).then((seasonTeam) => Promise.all(memberIds.map((mId) => this.copyMemberIntoSeasonTeam(seasonTeam.id, mId, actingUserId, isAdmin))).then(() => this.findById(seasonTeam.id, actingUserId, isAdmin)));
    }
    /**
     * Copy a member into a season team.
     * @param {UUID} SeasonTeamId - The ID of the season team.
     * @param {UUID} MemberId - The ID of the member.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @returns {Promise<Object>} The created member object.
     */
    async copyMemberIntoSeasonTeam(SeasonTeamId, MemberId, actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService copyMemberIntoSeasonTeam ${JSON.stringify({
            SeasonTeamId,
            MemberId,
            actingUserId,
            isAdmin,
        })}`);
        // Inherit ownerId from parent SeasonTeam
        const seasonTeam = await this.findById(SeasonTeamId, actingUserId, isAdmin);
        if (!seasonTeam) {
            throw new errors_1.NotFoundError(`SeasonTeam with ID ${SeasonTeamId} not found`);
        }
        const ownerId = seasonTeam.UserId;
        return MemberService_1.default.findById(MemberId, actingUserId, isAdmin).then((member) => {
            (0, accessControl_1.checkWriteAccess)(ownerId, actingUserId, isAdmin);
            return member
                ? MemberService_1.default.create(member.name, member.nickname, member.abbreviation, SeasonTeamId, actingUserId, isAdmin)
                : null;
        });
    }
    /**
     * Copy multiple members into a season team.
     * @param {UUID} seasonTeamId - The ID of the season team.
     * @param {Array<string>} memberIds - List of member IDs to copy.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @param {boolean} isAdmin - Whether the user is an admin.
     * @returns {Promise<Array>} List of created member objects.
     */
    async copyMembersIntoSeasonTeam(seasonTeamId, memberIds, actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService copyMembersIntoSeasonTeam ${JSON.stringify({
            seasonTeamId,
            memberIds,
            actingUserId,
            isAdmin,
        })}`);
        // Inherit ownerId from parent SeasonTeam
        const seasonTeam = await this.findById(seasonTeamId, actingUserId, isAdmin);
        if (!seasonTeam) {
            throw new errors_1.NotFoundError(`SeasonTeam with ID ${seasonTeamId} not found`);
        }
        const ownerId = seasonTeam.UserId;
        await (0, accessControl_1.checkWriteAccess)(ownerId, actingUserId, isAdmin);
        const members = await Promise.all(memberIds.map((mId) => this.copyMemberIntoSeasonTeam(seasonTeamId, mId, actingUserId, isAdmin)));
        return members;
    }
    /**
     * Remove a season team.
     * @param {UUID} id - The season team ID.
     * @param {UUID} actingUserId - The ID of the acting user.
     * @returns {Promise<void>} Resolves when the season team is removed.
     * @throws {Error} Throws an error if the season team is not found.
     */
    async remove(id, actingUserId, isAdmin = false) {
        logger.debug(`SeasonTeamService remove ${JSON.stringify({ id, actingUserId, isAdmin })}`);
        const foundSeasonTeam = await seasonTeam_1.default.findByPk(id, {
            include: [{ association: "Season", include: ["SeasonTeams"] }],
        });
        if (!foundSeasonTeam) {
            logger.error(`No seasonTeam found with ID ${id} when deleting`);
            throw new errors_1.NotFoundError(`No seasonTeam found with ID ${id} when deleting`);
        }
        await (0, accessControl_1.checkDeleteAccess)(foundSeasonTeam.UserId, actingUserId, isAdmin);
        if (foundSeasonTeam.Season &&
            foundSeasonTeam.Season.SeasonTeams.length == 1 &&
            foundSeasonTeam.Season.UserId == actingUserId)
            SeasonService_1.default.remove(foundSeasonTeam.Season.id, actingUserId);
        return foundSeasonTeam.destroy();
    }
    async migrateCreatorUpdater() {
        logger.debug(`SeasonTeamService migrateCreatorUpdater`);
        const seasonTeams = await seasonTeam_1.default.findAll({
            where: { creatorId: { [Op.is]: null }, UserId: { [Op.not]: null } },
        });
        await Promise.all(seasonTeams.map((seasonTeam) => seasonTeam.update({
            creatorId: seasonTeam.UserId,
            updaterId: seasonTeam.UserId,
        })));
    }
}
exports.default = new SeasonTeamService();