fix team permissions.

This commit is contained in:
Simon Larsen
2022-11-21 21:34:53 +00:00
parent ad4f9c65b9
commit 97bf748682
4 changed files with 216 additions and 5 deletions

View File

@@ -429,6 +429,7 @@ export class Service extends DatabaseService<Model> {
let ownerTeam: Team = new Team();
ownerTeam.projectId = createdItem.id!;
ownerTeam.name = 'Owners';
ownerTeam.shouldHaveAtleastOneMember = true;
ownerTeam.isPermissionsEditable = false;
ownerTeam.isTeamEditable = false;
ownerTeam.isTeamDeleteable = false;
@@ -469,6 +470,7 @@ export class Service extends DatabaseService<Model> {
data: ownerPermissions,
props: {
isRoot: true,
ignoreHooks: true
},
});
@@ -498,6 +500,7 @@ export class Service extends DatabaseService<Model> {
data: adminPermissions,
props: {
isRoot: true,
ignoreHooks: true
},
});
@@ -526,6 +529,7 @@ export class Service extends DatabaseService<Model> {
data: memberPermissions,
props: {
isRoot: true,
ignoreHooks: true
},
});

View File

@@ -29,6 +29,7 @@ import MailService from './MailService';
import EmailTemplateType from 'Common/Types/Email/EmailTemplateType';
import URL from 'Common/Types/API/URL';
import logger from '../Utils/Logger';
import BadDataException from 'Common/Types/Exception/BadDataException';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
@@ -154,23 +155,52 @@ export class Service extends DatabaseService<Model> {
): Promise<OnDelete<Model>> {
const items: Array<Model> = await this.findBy({
const members: Array<Model> = await this.findBy({
query: deleteBy.query,
select: {
userId: true,
projectId: true,
team: true,
teamId: true
},
limit: LIMIT_MAX,
skip: 0,
populate: {},
populate: {
team: {
_id: true,
shouldHaveAtleastOneMember: true
}
},
props: {
isRoot: true,
},
});
// check if there's one member in the team.
for (const member of members) {
if (member.team?.shouldHaveAtleastOneMember) {
const membersInTeam = await this.countBy({
query: {
_id: member.teamId?.toString() as string
},
skip: 0,
limit: LIMIT_MAX,
props: {
isRoot: true
}
});
if (membersInTeam.toNumber() <= 1) {
throw new BadDataException("This team should have atleast 1 member");
}
}
}
return {
deleteBy: deleteBy,
carryForward: items,
carryForward: members,
};
}

View File

@@ -1,17 +1,49 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Model/Models/TeamPermission';
import DatabaseService, { OnCreate } from './DatabaseService';
import DatabaseService, { OnCreate, OnDelete, OnUpdate } from './DatabaseService';
import CreateBy from '../Types/Database/CreateBy';
import AccessTokenService from './AccessTokenService';
import TeamMemberService from './TeamMemberService';
import LIMIT_MAX from 'Common/Types/Database/LimitMax';
import TeamMember from 'Model/Models/TeamMember';
import BadDataException from 'Common/Types/Exception/BadDataException';
import TeamService from './TeamService';
import UpdateBy from '../Types/Database/UpdateBy';
import DeleteBy from '../Types/Database/DeleteBy';
import ObjectID from 'Common/Types/ObjectID';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
}
protected override async onBeforeCreate(createBy: CreateBy<Model>): Promise<OnCreate<Model>> {
if (!createBy.data.teamId) {
throw new BadDataException("Team Id is required to create permission");
}
// get team.
const team = await TeamService.findOneById({
id: createBy.data.teamId!,
select: {
isPermissionsEditable: true
},
props: {
isRoot: false
}
});
if (!team) {
throw new BadDataException("Invalid Team ID");
}
if (!team.isPermissionsEditable) {
throw new BadDataException("You cannot create new permissions for this team because this team is not editable");
}
return { createBy, carryForward: null };
}
protected override async onCreateSuccess(
onCreate: OnCreate<Model>,
createdItem: Model
@@ -46,6 +78,135 @@ export class Service extends DatabaseService<Model> {
return createdItem;
}
// TODO - OnDelete and OnUpdate pending.
protected override async onBeforeUpdate(updateBy: UpdateBy<Model>): Promise<OnUpdate<Model>> {
const teamPermissions = await this.findBy({
query: updateBy.query,
select: {
_id: true,
teamId: true,
projectId: true
},
populate: {
team: {
isPermissionsEditable: true
}
},
skip: 0,
limit: LIMIT_MAX,
props: {
isRoot: true,
}
});
for (const permission of teamPermissions) {
if (!permission.team?.isPermissionsEditable) {
throw new BadDataException("Permissions for this team is not updateable. You can create a new team and add permissions to that team instead.");
}
}
return { updateBy, carryForward: teamPermissions };
}
protected override async onUpdateSuccess(onUpdate: OnUpdate<Model>, _updatedItemIds: ObjectID[]): Promise<OnUpdate<Model>> {
for (const permission of onUpdate.carryForward) {
const teamMembers: Array<TeamMember> = await TeamMemberService.findBy({
query: {
teamId: permission.teamId!,
},
select: {
userId: true,
},
props: {
isRoot: true,
},
limit: LIMIT_MAX,
skip: 0,
});
for (const member of teamMembers) {
/// Refresh tokens.
await AccessTokenService.refreshUserGlobalAccessPermission(
member.userId!
);
await AccessTokenService.refreshUserTenantAccessPermission(
member.userId!,
permission.data.projectId!
);
}
}
return onUpdate;
}
protected override async onBeforeDelete(deleteBy: DeleteBy<Model>): Promise<OnDelete<Model>> {
const teamPermissions = await this.findBy({
query: deleteBy.query,
select: {
_id: true,
teamId: true,
projectId: true
},
populate: {
team: {
isPermissionsEditable: true
}
},
skip: 0,
limit: LIMIT_MAX,
props: {
isRoot: true,
}
});
for (const permission of teamPermissions) {
if (!permission.team?.isPermissionsEditable) {
throw new BadDataException("Permissions for this team is not deleteable. You can create a new team and add permissions to that team instead.");
}
}
let teamMembers: Array<TeamMember> = [];
for (const permission of teamPermissions) {
const members: Array<TeamMember> = await TeamMemberService.findBy({
query: {
teamId: permission.teamId!,
},
select: {
userId: true,
projectId: true
},
props: {
isRoot: true,
},
limit: LIMIT_MAX,
skip: 0,
});
teamMembers = teamMembers.concat(members);
}
return { deleteBy, carryForward: teamMembers };
}
protected override async onDeleteSuccess(onDelete: OnDelete<Model>, _itemIdsBeforeDelete: ObjectID[]): Promise<OnDelete<Model>> {
for (const member of onDelete.carryForward) {
/// Refresh tokens.
await AccessTokenService.refreshUserGlobalAccessPermission(
member.userId!
);
await AccessTokenService.refreshUserTenantAccessPermission(
member.userId!,
member.data.projectId!
);
}
return onDelete;
}
}
export default new Service();

View File

@@ -229,6 +229,22 @@ export default class Team extends BaseModel {
})
public isTeamDeleteable?: boolean = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.CanEditProjectTeam,
Permission.CanEditProjectTeamPermissions,
],
update: [],
})
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
@Column({
type: ColumnType.Boolean,
default: false,
})
public shouldHaveAtleastOneMember?: boolean = undefined;
@ColumnAccessControl({
create: [],
read: [