@coko/server
Version:
Reusable server for use by Coko's projects
241 lines • 8.95 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const objection_1 = require("objection");
const logger_1 = __importDefault(require("../../logger"));
const base_model_1 = __importDefault(require("../base.model"));
const teamMember_model_1 = __importDefault(require("../teamMember/teamMember.model"));
const user_model_1 = __importDefault(require("../user/user.model"));
const teams_1 = require("../../utils/teams");
const types_1 = require("../_helpers/types");
const config_1 = __importDefault(require("../../configManager/config"));
const useTransaction_1 = __importDefault(require("../useTransaction"));
class Team extends base_model_1.default {
objectId;
objectType;
displayName;
role;
global;
members;
users;
constructor() {
super();
this.type = 'team';
}
static get tableName() {
return 'teams';
}
static get relationMappings() {
return {
members: {
relation: base_model_1.default.HasManyRelation,
modelClass: teamMember_model_1.default,
join: {
from: 'teams.id',
to: 'team_members.teamId',
},
},
users: {
relation: base_model_1.default.ManyToManyRelation,
modelClass: user_model_1.default,
join: {
from: 'teams.id',
through: {
modelClass: teamMember_model_1.default,
from: 'team_members.teamId',
to: 'team_members.userId',
},
to: 'users.id',
},
},
};
}
static get schema() {
const rolesEnum = (0, teams_1.teamRolesEnum)();
const displayNamesEnum = (0, teams_1.teamDisplayNamesEnum)();
return {
type: 'object',
required: ['role', 'displayName'],
properties: {
objectId: types_1.idNullable,
objectType: types_1.stringNullable,
displayName: {
type: 'string',
enum: displayNamesEnum,
},
role: {
type: 'string',
enum: rolesEnum,
},
global: types_1.booleanDefaultFalse,
},
};
}
/* eslint-disable-next-line class-methods-use-this */
$beforeValidate(jsonSchema, json) {
let validTeamChoice;
let validCombinationOfRoleAndName = true;
const { global, role, displayName } = json;
if (global) {
const globalTeams = config_1.default.get('teams.global');
validTeamChoice = globalTeams.find(t => t.role === role);
if (displayName && validTeamChoice) {
validCombinationOfRoleAndName =
validTeamChoice.displayName === displayName;
}
}
else {
const nonGlobalTeams = config_1.default.get('teams.nonGlobal');
validTeamChoice = nonGlobalTeams.find(t => t.role === role);
if (displayName && validTeamChoice) {
validCombinationOfRoleAndName =
validTeamChoice.displayName === displayName;
}
}
if (!validTeamChoice) {
const errorMessage = `Role ${role} is not valid for ${global ? '' : 'non-'}global teams`;
throw new objection_1.ValidationError({
type: 'ModelValidation',
message: errorMessage,
});
}
if (!validCombinationOfRoleAndName) {
const errorMessage = `Display name ${displayName} does not correspond to the provided role ${role} of ${global ? '' : 'non-'}global teams`;
throw new objection_1.ValidationError({
type: 'ModelValidation',
message: errorMessage,
});
}
return jsonSchema;
}
static async findAllGlobalTeams(options = {}) {
try {
return (0, useTransaction_1.default)(async (tr) => {
return this.query(tr).where({ global: true });
}, { trx: options.trx, passedTrxOnly: true });
}
catch (e) {
logger_1.default.error('Team model: findAllGlobalTeams failed', e);
throw e;
}
}
static async findGlobalTeamByRole(role, options = {}) {
try {
return (0, useTransaction_1.default)(async (tr) => {
return this.query(tr).findOne({
role,
global: true,
});
}, { trx: options.trx, passedTrxOnly: true });
}
catch (e) {
logger_1.default.error('Team model: findGlobalTeamByRole failed', e);
throw e;
}
}
static async findTeamByRoleAndObject(role, objectId, options = {}) {
try {
return (0, useTransaction_1.default)(async (tr) => {
return this.query(tr).findOne({
role,
objectId,
});
}, { trx: options.trx, passedTrxOnly: true });
}
catch (e) {
logger_1.default.error('Team model: findTeamByRoleAndObject failed', e);
throw e;
}
}
/**
* Members should be an array of user ids
*/
static async updateMembershipByTeamId(teamId, members, options = {}) {
const queries = async (trx) => {
const existingMembers = await teamMember_model_1.default.query(trx).where({ teamId });
const existingMemberUserIds = existingMembers.map(m => m.userId);
// add members that exist in the incoming array, but not in the db
const toAdd = members.filter(id => !existingMemberUserIds.includes(id));
await Promise.all(toAdd.map(userId => Team.addMember(teamId, userId, {
trx,
...(options.status && { status: options.status }),
})));
// delete members that exist in the db, but not in the incoming array
const toDelete = existingMemberUserIds.filter(id => !members.includes(id));
await Promise.all(toDelete.map(userId => Team.removeMember(teamId, userId, { trx })));
return Team.findById(teamId, { trx });
};
return (0, useTransaction_1.default)(queries, { trx: options.trx });
}
static async addMember(teamId, userId, options = {}) {
const data = {
teamId,
userId,
status: options.status,
};
const add = async (trx) => {
await teamMember_model_1.default.query(trx).insert(data);
return Team.findById(teamId, { trx });
};
const trxOptions = {
trx: options.trx,
passedTrxOnly: true,
};
try {
return (0, useTransaction_1.default)(add, trxOptions);
}
catch (e) {
logger_1.default.error('Team Model: Add member: Insert failed!');
throw e;
}
}
static async removeMember(teamId, userId, options = {}) {
const remove = async (trx) => {
await teamMember_model_1.default.query(trx)
.delete()
.where({
teamId,
userId,
})
.throwIfNotFound();
return Team.findById(teamId, { trx });
};
try {
return (0, useTransaction_1.default)(remove, { trx: options.trx, passedTrxOnly: true });
}
catch (e) {
logger_1.default.error('Team model: Remove member: Transaction failed! Rolling back...');
throw e;
}
}
static async addMemberToGlobalTeam(userId, role, options = {}) {
try {
const team = await Team.findOne({
role,
global: true,
}, { trx: options.trx });
return Team.addMember(team.id, userId, options);
}
catch (e) {
logger_1.default.error(`Team model: Add member to global team: ${e.message}`);
throw e;
}
}
static async removeMemberFromGlobalTeam(userId, role, options = {}) {
try {
const team = await Team.findOne({
role,
global: true,
}, { trx: options.trx });
return Team.removeMember(team.id, userId, options);
}
catch (e) {
logger_1.default.error(`Team model: Remove member from global team: ${e.message}`);
throw e;
}
}
}
exports.default = Team;
//# sourceMappingURL=team.model.js.map