Add updateRole endpoint (#6771)

This commit is contained in:
Tom Moor
2024-04-06 07:32:15 -06:00
committed by GitHub
parent 52643c511c
commit 3f209101e6
14 changed files with 314 additions and 207 deletions

View File

@@ -10,8 +10,8 @@ import {
FindOptions,
InferAttributes,
InferCreationAttributes,
InstanceUpdateOptions,
} from "sequelize";
import { type InstanceUpdateOptions } from "sequelize";
import {
Table,
Column,
@@ -29,6 +29,7 @@ import {
IsDate,
AllowNull,
AfterUpdate,
BeforeUpdate,
} from "sequelize-typescript";
import { UserPreferenceDefaults } from "@shared/constants";
import { languages } from "@shared/i18n";
@@ -42,9 +43,9 @@ import {
UserRole,
DocumentPermission,
} from "@shared/types";
import { UserRoleHelper } from "@shared/utils/UserRoleHelper";
import { stringToColor } from "@shared/utils/color";
import env from "@server/env";
import Model from "@server/models/base/Model";
import DeleteAttachmentTask from "@server/queues/tasks/DeleteAttachmentTask";
import parseAttachmentIds from "@server/utils/parseAttachmentIds";
import { ValidationError } from "../errors";
@@ -567,51 +568,6 @@ class User extends ParanoidModel<
],
});
demote: (
to: UserRole,
options?: InstanceUpdateOptions<InferAttributes<Model>>
) => Promise<void> = async (to, options) => {
const res = await (this.constructor as typeof User).findAndCountAll({
where: {
teamId: this.teamId,
role: UserRole.Admin,
id: {
[Op.ne]: this.id,
},
},
limit: 1,
...options,
});
if (res.count >= 1) {
if (to === UserRole.Member) {
await this.update({ role: to }, options);
} else if (to === UserRole.Viewer) {
await this.update({ role: to }, options);
await UserMembership.update(
{
permission: CollectionPermission.Read,
},
{
...options,
where: {
userId: this.id,
},
}
);
}
return undefined;
} else {
throw ValidationError("At least one admin is required");
}
};
promote: (
options?: InstanceUpdateOptions<InferAttributes<User>>
) => Promise<User> = (options) =>
this.update({ role: UserRole.Admin }, options);
// hooks
@BeforeDestroy
@@ -638,6 +594,62 @@ class User extends ParanoidModel<
model.jwtSecret = crypto.randomBytes(64).toString("hex");
};
@BeforeUpdate
static async checkRoleChange(
model: User,
options: InstanceUpdateOptions<InferAttributes<User>>
) {
const previousRole = model.previous("role");
if (
model.changed("role") &&
previousRole === UserRole.Admin &&
UserRoleHelper.isRoleLower(model.role, UserRole.Admin)
) {
const { count } = await this.findAndCountAll({
where: {
teamId: model.teamId,
role: UserRole.Admin,
id: {
[Op.ne]: model.id,
},
},
limit: 1,
transaction: options.transaction,
});
if (count === 0) {
throw ValidationError("At least one admin is required");
}
}
}
@AfterUpdate
static async updateMembershipPermissions(
model: User,
options: InstanceUpdateOptions<InferAttributes<User>>
) {
const previousRole = model.previous("role");
if (
previousRole &&
model.changed("role") &&
UserRoleHelper.isRoleLower(model.role, UserRole.Member) &&
UserRoleHelper.isRoleHigher(previousRole, UserRole.Viewer)
) {
await UserMembership.update(
{
permission: CollectionPermission.Read,
},
{
transaction: options.transaction,
where: {
userId: model.id,
},
}
);
}
}
@AfterUpdate
static deletePreviousAvatar = async (model: User) => {
const previousAvatarUrl = model.previous("avatarUrl");