chore: Migrate user role to new column (#6721)
* Migration * Double write * Backfill script * Simplify for self-hosted * flip * migration
This commit is contained in:
41
server/migrations/20240327015248-add-user-role.js
Normal file
41
server/migrations/20240327015248-add-user-role.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async up (queryInterface, Sequelize) {
|
||||||
|
await queryInterface.addColumn("users", "role", {
|
||||||
|
type: Sequelize.ENUM("admin", "member", "viewer", "guest"),
|
||||||
|
allowNull: true,
|
||||||
|
});
|
||||||
|
if (process.env.DEPLOYMENT === "hosted") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryInterface.sequelize.transaction(async (transaction) => {
|
||||||
|
await queryInterface.sequelize.query(
|
||||||
|
`UPDATE users SET role = 'viewer' WHERE "isViewer" = true`,
|
||||||
|
{
|
||||||
|
transaction,
|
||||||
|
type: queryInterface.sequelize.QueryTypes.UPDATE,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await queryInterface.sequelize.query(
|
||||||
|
`UPDATE users SET role = 'admin' WHERE "isAdmin" = true`,
|
||||||
|
{
|
||||||
|
transaction,
|
||||||
|
type: queryInterface.sequelize.QueryTypes.UPDATE,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await queryInterface.sequelize.query(
|
||||||
|
`UPDATE users SET role = 'member' WHERE role IS NULL`,
|
||||||
|
{
|
||||||
|
transaction,
|
||||||
|
type: queryInterface.sequelize.QueryTypes.UPDATE,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async down (queryInterface) {
|
||||||
|
await queryInterface.removeColumn("users", "role");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
IsDate,
|
IsDate,
|
||||||
AllowNull,
|
AllowNull,
|
||||||
AfterUpdate,
|
AfterUpdate,
|
||||||
|
BeforeSave,
|
||||||
} from "sequelize-typescript";
|
} from "sequelize-typescript";
|
||||||
import { UserPreferenceDefaults } from "@shared/constants";
|
import { UserPreferenceDefaults } from "@shared/constants";
|
||||||
import { languages } from "@shared/i18n";
|
import { languages } from "@shared/i18n";
|
||||||
@@ -144,6 +145,10 @@ class User extends ParanoidModel<
|
|||||||
@Column
|
@Column
|
||||||
isViewer: boolean;
|
isViewer: boolean;
|
||||||
|
|
||||||
|
@Default(UserRole.Member)
|
||||||
|
@Column(DataType.ENUM(...Object.values(UserRole)))
|
||||||
|
role: UserRole;
|
||||||
|
|
||||||
@Column(DataType.BLOB)
|
@Column(DataType.BLOB)
|
||||||
@Encrypted
|
@Encrypted
|
||||||
get jwtSecret() {
|
get jwtSecret() {
|
||||||
@@ -623,6 +628,20 @@ class User extends ParanoidModel<
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary hook to double write role while we transition to the new field.
|
||||||
|
*/
|
||||||
|
@BeforeSave
|
||||||
|
static doubleWriteRole = async (model: User) => {
|
||||||
|
if (model.isAdmin) {
|
||||||
|
model.role = UserRole.Admin;
|
||||||
|
} else if (model.isViewer) {
|
||||||
|
model.role = UserRole.Viewer;
|
||||||
|
} else {
|
||||||
|
model.role = UserRole.Member;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@BeforeCreate
|
@BeforeCreate
|
||||||
static setRandomJwtSecret = (model: User) => {
|
static setRandomJwtSecret = (model: User) => {
|
||||||
model.jwtSecret = crypto.randomBytes(64).toString("hex");
|
model.jwtSecret = crypto.randomBytes(64).toString("hex");
|
||||||
|
|||||||
Reference in New Issue
Block a user