Skip to content

Commit

Permalink
[FEATURE]: Save stakeholders into team_user table (#321)
Browse files Browse the repository at this point in the history
* feat: remove /all from GET /stakeholders/all to follow REST pattern

* feat: remove /all from getStakeholders /boards/stakeholders/all to follow REST pattern

* feat: remove ignored_users.json

* feat: get stakeholder from table teamuser.role

* feat: add geomarb as contributor

* feat: change get stakeholder to teams

* feat: add geomarb to README.md

* feat: add team param

* fix: chage user.role filter compare from strings to enums data

* feat: remove stakeholders

* feat: change way to handle stakeholder

* fix: compare user.role with enum data instead of string

* feat: remove prefetch getStakeholder

* feat: change the way to handle stakeholder

* feat: remove getStakeholders GET /boards/stakeholders

* feat: add stakeholder role

* feat: add team.filter.options lib

* feat: add getTeam(teamId, teamFilterOptions) & remove getTeamStakeholders

* feat: add stakeholder role

* feat: add filters loadUsers and userTeamRole to getTeam and remove GET /teams/member

* feat: add getTeam(teamId, teamFilterOptions) to get.team.application

* feat: add getTeam(teamId, teamFilterOptions) and remove getTeamStakeholders to get.team.service

* fix: rename TeamsFilterOptions to TeamQueryParams

* feat: improve code readability

* feat: improve code readability

* fix: error when merge sub-board to main-board

* fix: geomar profile link

Co-authored-by: Daniel Sousa <104842894+dsousa12@users.noreply.github.com>
  • Loading branch information
geomarb and dsousa12 authored Jul 19, 2022
1 parent 89e7238 commit 18c13cb
Show file tree
Hide file tree
Showing 22 changed files with 153 additions and 122 deletions.
2 changes: 1 addition & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"login": "geomarb",
"name": "Geomar Bastiani",
"avatar_url": "https://avatars.githubusercontent.com/u/33127565?v=4",
"profile": "http://xgeeks.io",
"profile": "https://github.com/geomarb",
"contributions": [
"code",
"doc"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/CatiaBarroco-xgeeks"><img src="https://avatars.githubusercontent.com/u/104831678?v=4?s=50" width="50px;" alt=""/><br /><sub><b>CatiaBarroco-xgeeks</b></sub></a><br /><a href="https://github.com/xgeekshq/split/commits?author=CatiaBarroco-xgeeks" title="Code">💻</a> <a href="https://github.com/xgeekshq/split/commits?author=CatiaBarroco-xgeeks" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/joaosantos99"><img src="https://avatars.githubusercontent.com/u/68588265?v=4?s=50" width="50px;" alt=""/><br /><sub><b>João Santos</b></sub></a><br /><a href="https://github.com/xgeekshq/split/commits?author=joaosantos99" title="Code">💻</a> <a href="https://github.com/xgeekshq/split/commits?author=joaosantos99" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dvpfran"><img src="https://avatars.githubusercontent.com/u/67462841?v=4?s=50" width="50px;" alt=""/><br /><sub><b>Luís Francisco</b></sub></a><br /><a href="https://github.com/xgeekshq/split/commits?author=dvpfran" title="Code">💻</a> <a href="https://github.com/xgeekshq/split/commits?author=dvpfran" title="Documentation">📖</a></td>
<td align="center"><a href="http://xgeeks.io"><img src="https://avatars.githubusercontent.com/u/33127565?v=4?s=50" width="50px;" alt=""/><br /><sub><b>Geomar Bastiani</b></sub></a><br /><a href="https://github.com/xgeekshq/split/commits?author=geomarb" title="Code">💻</a> <a href="https://github.com/xgeekshq/split/commits?author=geomarb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/geomarb"><img src="https://avatars.githubusercontent.com/u/33127565?v=4?s=50" width="50px;" alt=""/><br /><sub><b>Geomar Bastiani</b></sub></a><br /><a href="https://github.com/xgeekshq/split/commits?author=geomarb" title="Code">💻</a> <a href="https://github.com/xgeekshq/split/commits?author=geomarb" title="Documentation">📖</a></td>
</tr>
</table>

Expand Down
7 changes: 7 additions & 0 deletions backend/src/libs/dto/param/team.params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IsMongoId, IsString } from 'class-validator';

export class TeamParams {
@IsMongoId()
@IsString()
teamId!: string;
}
15 changes: 15 additions & 0 deletions backend/src/libs/dto/param/team.query.params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Transform } from 'class-transformer';
import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator';
import { TeamRoles } from 'src/libs/enum/team.roles';

export class TeamQueryParams {
@IsString()
@IsOptional()
@IsEnum(TeamRoles, { each: true })
teamUserRole?: TeamRoles;

@IsOptional()
@IsBoolean()
@Transform(({ value }) => [true, 'true', '', '1'].includes(value))
loadUsers?: boolean;
}
3 changes: 2 additions & 1 deletion backend/src/libs/enum/team.roles.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum TeamRoles {
ADMIN = 'admin',
MEMBER = 'member'
MEMBER = 'member',
STAKEHOLDER = 'stakeholder'
}
3 changes: 0 additions & 3 deletions backend/src/libs/utils/ignored_users.json

This file was deleted.

7 changes: 0 additions & 7 deletions backend/src/modules/boards/controller/boards.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
} from 'libs/exceptions/messages';
import JwtAuthenticationGuard from 'libs/guards/jwtAuth.guard';
import RequestWithUser from 'libs/interfaces/requestWithUser.interface';
import * as StakeholdersData from 'libs/utils/ignored_users.json';
import SocketGateway from 'modules/socket/gateway/socket.gateway';

import BoardDto from '../dto/board.dto';
Expand Down Expand Up @@ -83,12 +82,6 @@ export default class BoardsController {
return board;
}

@UseGuards(JwtAuthenticationGuard)
@Get('/stakeholders/all')
getStakeholders() {
return StakeholdersData as unknown as string[];
}

@UseGuards(JwtAuthenticationGuard)
@Put(':boardId')
async updateBoard(
Expand Down
23 changes: 11 additions & 12 deletions backend/src/modules/boards/services/create.board.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { InjectModel } from '@nestjs/mongoose';
import { LeanDocument, Model } from 'mongoose';

import { BoardRoles } from 'libs/enum/board.roles';
import { TeamRoles } from 'libs/enum/team.roles';
import { getDay, getNextMonth } from 'libs/utils/dates';
import { generateBoardDtoData, generateSubBoardDtoData } from 'libs/utils/generateBoardData';
import * as stakeHolders from 'libs/utils/ignored_users.json';
import isEmpty from 'libs/utils/isEmpty';
import { AddCronJobDto } from 'modules/schedules/dto/add.cronjob.dto';
import { CreateSchedulesServiceInterface } from 'modules/schedules/interfaces/services/create.schedules.service';
Expand All @@ -14,7 +14,7 @@ import TeamDto from 'modules/teams/dto/team.dto';
import { GetTeamServiceInterface } from 'modules/teams/interfaces/services/get.team.service.interface';
import { TYPES } from 'modules/teams/interfaces/types';
import TeamUser, { TeamUserDocument } from 'modules/teams/schemas/team.user.schema';
import User, { UserDocument } from 'modules/users/schemas/user.schema';
import { UserDocument } from 'modules/users/schemas/user.schema';

import BoardDto from '../dto/board.dto';
import BoardUserDto from '../dto/board.user.dto';
Expand Down Expand Up @@ -91,7 +91,7 @@ export default class CreateBoardServiceImpl implements CreateBoardService {
if (!usersIds.includes(user._id.toString())) {
newUsers.push({
user: user._id.toString(),
role: !stakeHolders.includes(user.email) ? BoardRoles.MEMBER : BoardRoles.STAKEHOLDER,
role: teamUser.role,
votesCount: 0
});
}
Expand Down Expand Up @@ -143,7 +143,7 @@ export default class CreateBoardServiceImpl implements CreateBoardService {

const teamUsers = await this.getTeamService.getUsersOfTeam(teamId);
const teamUsersWotStakeholders = teamUsers.filter(
(teamUser) => !stakeHolders?.includes((teamUser.user as User).email) ?? []
(teamUser) => !(teamUser.role === TeamRoles.STAKEHOLDER) ?? []
);
const teamUsersWotStakeholdersCount = teamUsersWotStakeholders?.length ?? 0;
const teamLength = teamUsersWotStakeholdersCount;
Expand All @@ -170,15 +170,15 @@ export default class CreateBoardServiceImpl implements CreateBoardService {

handleSplitBoards = (maxTeams: number, teamMembers: LeanDocument<TeamUserDocument>[]) => {
const subBoards: BoardDto[] = [];
const splitedUsers: BoardUserDto[][] = new Array(maxTeams).fill([]);
const splitUsers: BoardUserDto[][] = new Array(maxTeams).fill([]);

const availableUsers = [...teamMembers];

new Array(teamMembers.length).fill(0).reduce((j) => {
if (j >= maxTeams) j = 0;
const teamUser = this.getRandomUser(availableUsers);
splitedUsers[j] = [
...splitedUsers[j],
splitUsers[j] = [
...splitUsers[j],
{
user: (teamUser.user as LeanDocument<UserDocument>)._id.toString(),
role: BoardRoles.MEMBER,
Expand All @@ -188,17 +188,16 @@ export default class CreateBoardServiceImpl implements CreateBoardService {
return ++j;
}, 0);

this.generateSubBoards(maxTeams, splitedUsers, subBoards);
this.generateSubBoards(maxTeams, splitUsers, subBoards);

return subBoards;
};

generateSubBoards(maxTeams: number, splitedUsers: BoardUserDto[][], subBoards: BoardDto[]) {
generateSubBoards(maxTeams: number, splitUsers: BoardUserDto[][], subBoards: BoardDto[]) {
new Array(maxTeams).fill(0).forEach((_, i) => {
const newBoard = generateSubBoardDtoData(i + 1);
splitedUsers[i][Math.floor(Math.random() * splitedUsers[i].length)].role =
BoardRoles.RESPONSIBLE;
newBoard.users = splitedUsers[i];
splitUsers[i][Math.floor(Math.random() * splitUsers[i].length)].role = BoardRoles.RESPONSIBLE;
newBoard.users = splitUsers[i];
subBoards.push(newBoard);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';

import { TeamQueryParams } from '../../../libs/dto/param/team.query.params';
import { GetTeamApplicationInterface } from '../interfaces/applications/get.team.application.interface';
import { GetTeamServiceInterface } from '../interfaces/services/get.team.service.interface';
import { TYPES } from '../interfaces/types';
Expand All @@ -19,6 +20,10 @@ export class GetTeamApplication implements GetTeamApplicationInterface {
return this.getTeamService.getAllTeams();
}

getTeam(teamId: string, teamQueryParams?: TeamQueryParams) {
return this.getTeamService.getTeam(teamId, teamQueryParams);
}

getTeamsOfUser(userId: string) {
return this.getTeamService.getTeamsOfUser(userId);
}
Expand Down
15 changes: 11 additions & 4 deletions backend/src/modules/teams/controller/team.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import {
Controller,
Get,
Inject,
Param,
Post,
Put,
Query,
Req,
UseGuards
UseGuards,
UsePipes,
ValidationPipe
} from '@nestjs/common';

import { TeamParams } from 'libs/dto/param/team.params';
import { TeamQueryParams } from 'libs/dto/param/team.query.params';
import { INSERT_FAILED } from 'libs/exceptions/messages';
import JwtAuthenticationGuard from 'libs/guards/jwtAuth.guard';
import RequestWithUser from 'libs/interfaces/requestWithUser.interface';
Expand Down Expand Up @@ -52,8 +58,9 @@ export default class TeamsController {
}

@UseGuards(JwtAuthenticationGuard)
@Get('/member')
getTeamsOfUser(@Req() request: RequestWithUser) {
return this.getTeamApp.getTeamsOfUser(request.user._id);
@Get(':teamId')
@UsePipes(new ValidationPipe({ transform: true }))
getTeam(@Param() { teamId }: TeamParams, @Query() teamQueryParams?: TeamQueryParams) {
return this.getTeamApp.getTeam(teamId, teamQueryParams);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { LeanDocument } from 'mongoose';

import { TeamQueryParams } from 'libs/dto/param/team.query.params';

import { TeamDocument } from '../../schemas/teams.schema';

export interface GetTeamApplicationInterface {
countTeams(userId: string): Promise<number>;

getAllTeams(): Promise<LeanDocument<TeamDocument>[]>;

getTeam(
teamId: string,
teamQueryParams?: TeamQueryParams
): Promise<LeanDocument<TeamDocument> | null>;

getTeamsOfUser(userId: string): Promise<LeanDocument<TeamDocument>[]>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { LeanDocument } from 'mongoose';

import { TeamQueryParams } from 'libs/dto/param/team.query.params';

import { TeamUserDocument } from '../../schemas/team.user.schema';
import { TeamDocument } from '../../schemas/teams.schema';

Expand All @@ -10,7 +12,10 @@ export interface GetTeamServiceInterface {

getTeamsOfUser(userId: string): Promise<LeanDocument<TeamDocument>[]>;

getTeam(teamId: string): Promise<LeanDocument<TeamDocument> | null>;
getTeam(
teamId: string,
teamQueryParams?: TeamQueryParams
): Promise<LeanDocument<TeamDocument> | null>;

getUsersOfTeam(teamId: string): Promise<LeanDocument<TeamUserDocument>[]>;

Expand Down
2 changes: 1 addition & 1 deletion backend/src/modules/teams/schemas/team.user.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class TeamUser {
@Prop({
nullable: false,
type: String,
enum: [TeamRoles.ADMIN, TeamRoles.MEMBER]
enum: [TeamRoles.ADMIN, TeamRoles.MEMBER, TeamRoles.STAKEHOLDER]
})
role!: string;

Expand Down
29 changes: 27 additions & 2 deletions backend/src/modules/teams/services/get.team.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';

import { TeamQueryParams } from '../../../libs/dto/param/team.query.params';
import { GetTeamServiceInterface } from '../interfaces/services/get.team.service.interface';
import TeamUser, { TeamUserDocument } from '../schemas/team.user.schema';
import Team, { TeamDocument } from '../schemas/teams.schema';
Expand All @@ -25,8 +26,32 @@ export default class GetTeamService implements GetTeamServiceInterface {
return this.teamModel.countDocuments().exec();
}

getTeam(teamId: string) {
return this.teamModel.findById(teamId).lean().exec();
getTeam(teamId: string, teamQueryParams: TeamQueryParams = {}) {
const { loadUsers, teamUserRole } = teamQueryParams;
const teamModel = this.teamModel.findById(teamId);
let teamUserRoleFilter = {};

if (teamUserRole) {
teamUserRoleFilter = { match: { role: { $eq: teamUserRole } } };
}

if (loadUsers || teamUserRole) {
teamModel
.populate({
path: 'users',
select: 'user role',
...teamUserRoleFilter,
populate: {
path: 'user',
select: '_id firstName lastName email joinedAt'
}
})
.lean({ virtuals: true });
} else {
teamModel.lean();
}

return teamModel.exec();
}

async getTeamsOfUser(userId: string) {
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/api/boardService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ export const getBoardRequest = (
return fetchData<GetBoardResponse>(`/boards/${id}`, { context, serverSide: !!context });
};

export const getStakeholders = (context?: GetServerSidePropsContext): Promise<string[]> => {
return fetchData<string[]>(`/boards/stakeholders/all`, { context, serverSide: !!context });
};

export const getDashboardBoardsRequest = (
pageParam: number,
context?: GetServerSidePropsContext
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/Board/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { boardInfoState } from 'store/board/atoms/board.atom';
import BoardType from 'types/board/board';
import { BoardUser, BoardUserNoPopulated } from 'types/board/board.user';
import { BreadcrumbType } from 'types/board/Breadcrumb';
import { BoardUserRoles } from 'utils/enums/board.user.roles';
import {
BoardCounter,
MergeIconContainer,
Expand Down Expand Up @@ -149,7 +150,7 @@ const BoardHeader = () => {
</Flex>

{(boardData!.board.users || users).filter(
(user: BoardUser) => user.role === 'stakeholder'
(user: BoardUser) => user.role === BoardUserRoles.STAKEHOLDER
).length > 0 && (
<>
<Separator
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/components/CardBoard/CardAvatars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ const CardAvatars = React.memo<CardAvatarProps>(
const data = useMemo(() => {
if (responsible)
return listUsers
.filter((user) => user.role === 'responsible')
.filter((user) => user.role === BoardUserRoles.RESPONSIBLE)
.map((user) => user.user);

if (teamAdmins)
return listUsers.filter((user) => user.role === 'admin').map((user) => user.user);
return listUsers
.filter((user) => user.role === TeamUserRoles.ADMIN)
.map((user) => user.user);

if (stakeholders) {
return listUsers
.filter((user) => user.role === 'stakeholder')
.filter((user) => user.role === TeamUserRoles.STAKEHOLDER)
.map((user) => user.user);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CreateBoardData, createBoardError } from 'store/createBoard/atoms/creat
import { BoardToAdd } from 'types/board/board';
import { Team } from 'types/team/team';
import { BoardUserRoles } from 'utils/enums/board.user.roles';
import { TeamUserRoles } from '../../../utils/enums/team.user.roles';
import SubCardBoard from './SubCardBoard';

const MainContainer = styled(Flex, Box, {
Expand All @@ -34,7 +35,6 @@ interface SubBoardListProp {

interface MainBoardCardInterface {
team: Team;
stakeholders: string[];
}

const SubBoardList = React.memo(({ dividedBoards, setBoard }: SubBoardListProp) => {
Expand All @@ -52,7 +52,7 @@ const SubBoardList = React.memo(({ dividedBoards, setBoard }: SubBoardListProp)
);
});

const MainBoardCard = React.memo(({ team, stakeholders }: MainBoardCardInterface) => {
const MainBoardCard = React.memo(({ team }: MainBoardCardInterface) => {
/**
* Recoil Atoms
*/
Expand All @@ -66,9 +66,8 @@ const MainBoardCard = React.memo(({ team, stakeholders }: MainBoardCardInterface
setCreateBoardData,
canAdd,
canReduce,
teamMembers,
stakeHolders
} = useCreateBoard(team, stakeholders);
teamMembers
} = useCreateBoard(team);

const slackGroupHandler = () => {
setCreateBoardData((prev) => ({
Expand All @@ -84,7 +83,7 @@ const MainBoardCard = React.memo(({ team, stakeholders }: MainBoardCardInterface
const teamsCount = Math.ceil(teamMembersCount / maxUsersCount);

const users = team.users.flatMap((teamUser) => {
if (!stakeHolders?.includes(teamUser.user.email)) return [];
if (teamUser.role !== TeamUserRoles.STAKEHOLDER) return [];
return [
{
user: teamUser.user._id,
Expand Down
Loading

0 comments on commit 18c13cb

Please sign in to comment.