mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
fix team permissions.
This commit is contained in:
@@ -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
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user