mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-08 01:15:49 +02:00
parent
0c8ebd4dcc
commit
38e428dacf
@ -42,7 +42,6 @@ const rowToGroupUser = (row) => {
|
|||||||
return {
|
return {
|
||||||
userId: row.user_id,
|
userId: row.user_id,
|
||||||
groupId: row.group_id,
|
groupId: row.group_id,
|
||||||
role: row.role,
|
|
||||||
joinedAt: row.created_at,
|
joinedAt: row.created_at,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -112,7 +111,7 @@ export default class GroupStore implements IGroupStore {
|
|||||||
|
|
||||||
async getAllUsersByGroups(groupIds: number[]): Promise<IGroupUser[]> {
|
async getAllUsersByGroups(groupIds: number[]): Promise<IGroupUser[]> {
|
||||||
const rows = await this.db
|
const rows = await this.db
|
||||||
.select('gu.group_id', 'u.id as user_id', 'role', 'gu.created_at')
|
.select('gu.group_id', 'u.id as user_id', 'gu.created_at')
|
||||||
.from(`${T.GROUP_USER} AS gu`)
|
.from(`${T.GROUP_USER} AS gu`)
|
||||||
.join(`${T.USERS} AS u`, 'u.id', 'gu.user_id')
|
.join(`${T.USERS} AS u`, 'u.id', 'gu.user_id')
|
||||||
.whereIn('gu.group_id', groupIds);
|
.whereIn('gu.group_id', groupIds);
|
||||||
@ -174,32 +173,12 @@ export default class GroupStore implements IGroupStore {
|
|||||||
return {
|
return {
|
||||||
group_id: groupId,
|
group_id: groupId,
|
||||||
user_id: user.user.id,
|
user_id: user.user.id,
|
||||||
role: user.role,
|
|
||||||
created_by: userName,
|
created_by: userName,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return (transaction || this.db).batchInsert(T.GROUP_USER, rows);
|
return (transaction || this.db).batchInsert(T.GROUP_USER, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateExistingUsersInGroup(
|
|
||||||
groupId: number,
|
|
||||||
existingUsers: IGroupUserModel[],
|
|
||||||
transaction?: Transaction,
|
|
||||||
): Promise<void> {
|
|
||||||
const queries = [];
|
|
||||||
|
|
||||||
existingUsers.forEach((user) => {
|
|
||||||
queries.push(
|
|
||||||
(transaction || this.db)(T.GROUP_USER)
|
|
||||||
.where({ group_id: groupId, user_id: user.user.id })
|
|
||||||
.update({ role: user.role })
|
|
||||||
.transacting(transaction),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteOldUsersFromGroup(
|
async deleteOldUsersFromGroup(
|
||||||
deletableUsers: IGroupUser[],
|
deletableUsers: IGroupUser[],
|
||||||
transaction?: Transaction,
|
transaction?: Transaction,
|
||||||
@ -221,7 +200,6 @@ export default class GroupStore implements IGroupStore {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.db.transaction(async (tx) => {
|
await this.db.transaction(async (tx) => {
|
||||||
await this.addNewUsersToGroup(groupId, newUsers, userName, tx);
|
await this.addNewUsersToGroup(groupId, newUsers, userName, tx);
|
||||||
await this.updateExistingUsersInGroup(groupId, existingUsers, tx);
|
|
||||||
await this.deleteOldUsersFromGroup(deletableUsers, tx);
|
await this.deleteOldUsersFromGroup(deletableUsers, tx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,12 @@ export const groupUserModelSchema = {
|
|||||||
$id: '#/components/schemas/groupUserModelSchema',
|
$id: '#/components/schemas/groupUserModelSchema',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
required: ['role', 'user'],
|
required: ['user'],
|
||||||
properties: {
|
properties: {
|
||||||
joinedAt: {
|
joinedAt: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
format: 'date-time',
|
format: 'date-time',
|
||||||
},
|
},
|
||||||
role: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
user: {
|
user: {
|
||||||
$ref: '#/components/schemas/userSchema',
|
$ref: '#/components/schemas/userSchema',
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,6 @@ test('groupsSchema', () => {
|
|||||||
name: 'Group',
|
name: 'Group',
|
||||||
users: [
|
users: [
|
||||||
{
|
{
|
||||||
role: 'Owner',
|
|
||||||
user: {
|
user: {
|
||||||
id: 3,
|
id: 3,
|
||||||
},
|
},
|
||||||
|
@ -176,7 +176,7 @@ export class GroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validateGroup(
|
async validateGroup(
|
||||||
{ name, users }: IGroupModel,
|
{ name }: IGroupModel,
|
||||||
existingGroup?: IGroup,
|
existingGroup?: IGroup,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@ -188,10 +188,6 @@ export class GroupService {
|
|||||||
throw new NameExistsError('Group name already exists');
|
throw new NameExistsError('Group name already exists');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (users.length == 0 || !users.some((u) => u.role == 'Owner')) {
|
|
||||||
throw new BadDataError('Group needs to have at least one Owner');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRolesForProject(projectId: string): Promise<IGroupRole[]> {
|
async getRolesForProject(projectId: string): Promise<IGroupRole[]> {
|
||||||
@ -215,7 +211,6 @@ export class GroupService {
|
|||||||
return {
|
return {
|
||||||
user: user,
|
user: user,
|
||||||
joinedAt: roleUser.joinedAt,
|
joinedAt: roleUser.joinedAt,
|
||||||
role: roleUser.role,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return { ...group, users: finalUsers };
|
return { ...group, users: finalUsers };
|
||||||
|
@ -13,7 +13,6 @@ export interface IGroup {
|
|||||||
export interface IGroupUser {
|
export interface IGroupUser {
|
||||||
groupId: number;
|
groupId: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
role: string;
|
|
||||||
joinedAt: Date;
|
joinedAt: Date;
|
||||||
seenAt?: Date;
|
seenAt?: Date;
|
||||||
}
|
}
|
||||||
@ -37,7 +36,6 @@ export interface IGroupProject {
|
|||||||
|
|
||||||
export interface IGroupUserModel {
|
export interface IGroupUserModel {
|
||||||
user: IUser;
|
user: IUser;
|
||||||
role: string;
|
|
||||||
joinedAt?: Date;
|
joinedAt?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +40,6 @@ export interface IGroupStore extends Store<IGroup, number> {
|
|||||||
userName: string,
|
userName: string,
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
|
||||||
updateExistingUsersInGroup(
|
|
||||||
groupId: number,
|
|
||||||
users: IGroupUserModel[],
|
|
||||||
): Promise<void>;
|
|
||||||
|
|
||||||
existsWithName(name: string): Promise<boolean>;
|
existsWithName(name: string): Promise<boolean>;
|
||||||
|
|
||||||
create(group: IStoreGroup): Promise<IGroup>;
|
create(group: IStoreGroup): Promise<IGroup>;
|
||||||
|
19
src/migrations/20220808084524-add-group-permissions.js
Normal file
19
src/migrations/20220808084524-add-group-permissions.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.up = function (db, cb) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
ALTER TABLE group_user DROP COLUMN IF EXISTS role;
|
||||||
|
`,
|
||||||
|
cb,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (db, cb) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
ALTER TABLE group_user ADD COLUMN role text check(role in ('Owner', 'Member')) default 'Member';
|
||||||
|
`,
|
||||||
|
cb,
|
||||||
|
);
|
||||||
|
};
|
@ -1359,15 +1359,11 @@ Object {
|
|||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"role": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"user": Object {
|
"user": Object {
|
||||||
"$ref": "#/components/schemas/userSchema",
|
"$ref": "#/components/schemas/userSchema",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": Array [
|
"required": Array [
|
||||||
"role",
|
|
||||||
"user",
|
"user",
|
||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -882,7 +882,7 @@ test('Should be allowed move feature toggle to project when given access through
|
|||||||
|
|
||||||
await groupStore.addNewUsersToGroup(
|
await groupStore.addNewUsersToGroup(
|
||||||
groupWithProjectAccess.id,
|
groupWithProjectAccess.id,
|
||||||
[{ user: viewerUser, role: 'Owner' }],
|
[{ user: viewerUser }],
|
||||||
'Admin',
|
'Admin',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -919,7 +919,7 @@ test('Should not lose user role access when given permissions from a group', asy
|
|||||||
|
|
||||||
await groupStore.addNewUsersToGroup(
|
await groupStore.addNewUsersToGroup(
|
||||||
groupWithNoAccess.id,
|
groupWithNoAccess.id,
|
||||||
[{ user: user, role: 'Owner' }],
|
[{ user: user }],
|
||||||
'Admin',
|
'Admin',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -968,13 +968,13 @@ test('Should allow user to take multiple group roles and have expected permissio
|
|||||||
|
|
||||||
await groupStore.addNewUsersToGroup(
|
await groupStore.addNewUsersToGroup(
|
||||||
groupWithCreateAccess.id,
|
groupWithCreateAccess.id,
|
||||||
[{ user: viewerUser, role: 'Owner' }],
|
[{ user: viewerUser }],
|
||||||
'Admin',
|
'Admin',
|
||||||
);
|
);
|
||||||
|
|
||||||
await groupStore.addNewUsersToGroup(
|
await groupStore.addNewUsersToGroup(
|
||||||
groupWithDeleteAccess.id,
|
groupWithDeleteAccess.id,
|
||||||
[{ user: viewerUser, role: 'Owner' }],
|
[{ user: viewerUser }],
|
||||||
'Admin',
|
'Admin',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
7
src/test/fixtures/fake-group-store.ts
vendored
7
src/test/fixtures/fake-group-store.ts
vendored
@ -50,13 +50,6 @@ export default class FakeGroupStore implements IGroupStore {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateExistingUsersInGroup(
|
|
||||||
id: number,
|
|
||||||
users: IGroupUserModel[],
|
|
||||||
): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllUsersByGroups(groupIds: number[]): Promise<IGroupUser[]> {
|
getAllUsersByGroups(groupIds: number[]): Promise<IGroupUser[]> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user