mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
Wrong number on the project page regarding members in that project (#1917)
* Fix project member count * Fix * Add editors to projects
This commit is contained in:
parent
9676165de9
commit
037b8eacd3
@ -29,6 +29,11 @@ export interface IEnvironmentProjectLink {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IProjectMembersCount {
|
||||||
|
count: number;
|
||||||
|
project: string;
|
||||||
|
}
|
||||||
|
|
||||||
class ProjectStore implements IProjectStore {
|
class ProjectStore implements IProjectStore {
|
||||||
private db: Knex;
|
private db: Knex;
|
||||||
|
|
||||||
@ -89,12 +94,11 @@ class ProjectStore implements IProjectStore {
|
|||||||
);
|
);
|
||||||
projectTimer();
|
projectTimer();
|
||||||
const memberTimer = this.timer('getMemberCount');
|
const memberTimer = this.timer('getMemberCount');
|
||||||
const memberCount = await this.db.raw(
|
|
||||||
`SELECT count(role_id) as member_count, project FROM role_user GROUP BY project`,
|
const memberCount = await this.getMembersCount();
|
||||||
);
|
|
||||||
memberTimer();
|
memberTimer();
|
||||||
const memberMap = new Map<string, number>(
|
const memberMap = new Map<string, number>(
|
||||||
memberCount.rows.map((c) => [c.project, Number(c.member_count)]),
|
memberCount.map((c) => [c.project, Number(c.count)]),
|
||||||
);
|
);
|
||||||
return projectsWithFeatureCount.map((r) => {
|
return projectsWithFeatureCount.map((r) => {
|
||||||
return { ...r, memberCount: memberMap.get(r.id) };
|
return { ...r, memberCount: memberMap.get(r.id) };
|
||||||
@ -247,23 +251,75 @@ class ProjectStore implements IProjectStore {
|
|||||||
.pluck('project_environments.environment_name');
|
.pluck('project_environments.environment_name');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMembers(projectId: string): Promise<number> {
|
async getMembersCount(): Promise<IProjectMembersCount[]> {
|
||||||
const rolesFromProject = this.db('role_permission')
|
const members = await this.db
|
||||||
.select('role_id')
|
.select('project')
|
||||||
.distinct();
|
.from((db) => {
|
||||||
|
db.select('user_id', 'project')
|
||||||
const numbers = await this.db('role_user')
|
.from('role_user')
|
||||||
.countDistinct('user_id as members')
|
.leftJoin('roles', 'role_user.role_id', 'roles.id')
|
||||||
.where('project', projectId)
|
.where((builder) => builder.whereNot('type', 'root'))
|
||||||
.whereIn('role_id', rolesFromProject)
|
.union((queryBuilder) => {
|
||||||
.first();
|
queryBuilder
|
||||||
const { members } = numbers;
|
.select('user_id', 'project')
|
||||||
if (typeof members === 'string') {
|
.from('group_role')
|
||||||
return parseInt(members, 10);
|
.leftJoin(
|
||||||
}
|
'group_user',
|
||||||
|
'group_user.group_id',
|
||||||
|
'group_role.group_id',
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.union((queryBuilder) => {
|
||||||
|
queryBuilder
|
||||||
|
.select('user_id', 'projects.name as project')
|
||||||
|
.from('role_user')
|
||||||
|
.leftJoin('roles', 'role_user.role_id', 'roles.id')
|
||||||
|
.crossJoin('projects')
|
||||||
|
.where((builder) =>
|
||||||
|
builder
|
||||||
|
.where('type', 'root')
|
||||||
|
.where('roles.name', 'Editor'),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
|
})
|
||||||
|
.groupBy('project')
|
||||||
|
.count('user_id');
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getMembersCountByProject(projectId?: string): Promise<number> {
|
||||||
|
const members = await this.db
|
||||||
|
.from((db) => {
|
||||||
|
db.select('user_id')
|
||||||
|
.from('role_user')
|
||||||
|
.leftJoin('roles', 'role_user.role_id', 'roles.id')
|
||||||
|
.where((builder) =>
|
||||||
|
builder
|
||||||
|
.where('project', projectId)
|
||||||
|
.whereNot('type', 'root'),
|
||||||
|
)
|
||||||
|
.orWhere((builder) =>
|
||||||
|
builder.where('type', 'root').where('name', 'Editor'),
|
||||||
|
)
|
||||||
|
.union((queryBuilder) => {
|
||||||
|
queryBuilder
|
||||||
|
.select('user_id')
|
||||||
|
.from('group_role')
|
||||||
|
.leftJoin(
|
||||||
|
'group_user',
|
||||||
|
'group_user.group_id',
|
||||||
|
'group_role.group_id',
|
||||||
|
)
|
||||||
|
.where('project', projectId);
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
.first();
|
||||||
|
return Number(members.count);
|
||||||
|
}
|
||||||
|
|
||||||
async count(): Promise<number> {
|
async count(): Promise<number> {
|
||||||
return this.db
|
return this.db
|
||||||
.from(TABLE)
|
.from(TABLE)
|
||||||
|
@ -67,7 +67,9 @@ export default class ProjectHealthService {
|
|||||||
projectId,
|
projectId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
const members = await this.projectStore.getMembers(projectId);
|
const members = await this.projectStore.getMembersCountByProject(
|
||||||
|
projectId,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
name: project.name,
|
name: project.name,
|
||||||
description: project.description,
|
description: project.description,
|
||||||
|
@ -573,7 +573,7 @@ export default class ProjectService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMembers(projectId: string): Promise<number> {
|
async getMembers(projectId: string): Promise<number> {
|
||||||
return this.store.getMembers(projectId);
|
return this.store.getMembersCountByProject(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProjectOverview(
|
async getProjectOverview(
|
||||||
@ -588,7 +588,7 @@ export default class ProjectService {
|
|||||||
projectId,
|
projectId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
const members = await this.store.getMembers(projectId);
|
const members = await this.store.getMembersCountByProject(projectId);
|
||||||
return {
|
return {
|
||||||
name: project.name,
|
name: project.name,
|
||||||
environments,
|
environments,
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { IEnvironmentProjectLink } from '../../db/project-store';
|
import {
|
||||||
|
IEnvironmentProjectLink,
|
||||||
|
IProjectMembersCount,
|
||||||
|
} from '../../db/project-store';
|
||||||
import { IProject, IProjectWithCount } from '../model';
|
import { IProject, IProjectWithCount } from '../model';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
|
|
||||||
@ -32,7 +35,8 @@ export interface IProjectStore extends Store<IProject, string> {
|
|||||||
addEnvironmentToProject(id: string, environment: string): Promise<void>;
|
addEnvironmentToProject(id: string, environment: string): Promise<void>;
|
||||||
deleteEnvironmentForProject(id: string, environment: string): Promise<void>;
|
deleteEnvironmentForProject(id: string, environment: string): Promise<void>;
|
||||||
getEnvironmentsForProject(id: string): Promise<string[]>;
|
getEnvironmentsForProject(id: string): Promise<string[]>;
|
||||||
getMembers(projectId: string): Promise<number>;
|
getMembersCountByProject(projectId: string): Promise<number>;
|
||||||
|
getMembersCount(): Promise<IProjectMembersCount[]>;
|
||||||
getProjectsWithCounts(query?: IProjectQuery): Promise<IProjectWithCount[]>;
|
getProjectsWithCounts(query?: IProjectQuery): Promise<IProjectWithCount[]>;
|
||||||
count(): Promise<number>;
|
count(): Promise<number>;
|
||||||
getAll(query?: IProjectQuery): Promise<IProject[]>;
|
getAll(query?: IProjectQuery): Promise<IProject[]>;
|
||||||
|
11
src/test/fixtures/fake-project-store.ts
vendored
11
src/test/fixtures/fake-project-store.ts
vendored
@ -5,7 +5,10 @@ import {
|
|||||||
} from '../../lib/types/stores/project-store';
|
} from '../../lib/types/stores/project-store';
|
||||||
import { IProject, IProjectWithCount } from '../../lib/types/model';
|
import { IProject, IProjectWithCount } from '../../lib/types/model';
|
||||||
import NotFoundError from '../../lib/error/notfound-error';
|
import NotFoundError from '../../lib/error/notfound-error';
|
||||||
import { IEnvironmentProjectLink } from 'lib/db/project-store';
|
import {
|
||||||
|
IEnvironmentProjectLink,
|
||||||
|
IProjectMembersCount,
|
||||||
|
} from 'lib/db/project-store';
|
||||||
|
|
||||||
export default class FakeProjectStore implements IProjectStore {
|
export default class FakeProjectStore implements IProjectStore {
|
||||||
projects: IProject[] = [];
|
projects: IProject[] = [];
|
||||||
@ -99,7 +102,7 @@ export default class FakeProjectStore implements IProjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async getMembers(projectId: string): Promise<number> {
|
async getMembersCountByProject(projectId: string): Promise<number> {
|
||||||
return Promise.resolve(0);
|
return Promise.resolve(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,4 +123,8 @@ export default class FakeProjectStore implements IProjectStore {
|
|||||||
this.projects.find((p) => p.id === healthUpdate.id).health =
|
this.projects.find((p) => p.id === healthUpdate.id).health =
|
||||||
healthUpdate.health;
|
healthUpdate.health;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMembersCount(): Promise<IProjectMembersCount[]> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user