Add routes for managing users in teams
This commit is contained in:
parent
dd358154b6
commit
46e56b7ad4
@ -3,6 +3,7 @@ import {INewUser} from './INewUser'
|
||||
import {ITeam} from './ITeam'
|
||||
import {IUserTeam} from './IUserTeam'
|
||||
import {IUser} from './IUser'
|
||||
import {IUserInTeam} from './IUserInTeam'
|
||||
|
||||
export interface IAPIDef {
|
||||
'/auth/register': {
|
||||
@ -70,6 +71,30 @@ export interface IAPIDef {
|
||||
}
|
||||
}
|
||||
|
||||
'/teams/:teamId/users': {
|
||||
get: {
|
||||
params: {
|
||||
teamId: number
|
||||
}
|
||||
response: IUserInTeam[] // TODO
|
||||
}
|
||||
}
|
||||
|
||||
'/teams/:teamId/users/:userId': {
|
||||
post: {
|
||||
params: {
|
||||
teamId: number
|
||||
userId: number
|
||||
}
|
||||
}
|
||||
delete: {
|
||||
params: {
|
||||
teamId: number
|
||||
userId: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
'/my/teams': {
|
||||
get: {
|
||||
response: IUserTeam[]
|
||||
|
||||
7
packages/common/src/IUserInTeam.ts
Normal file
7
packages/common/src/IUserInTeam.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface IUserInTeam {
|
||||
teamId: number
|
||||
userId: number
|
||||
displayName: string
|
||||
roleId: number
|
||||
roleName: string
|
||||
}
|
||||
@ -6,4 +6,7 @@ export * from './IRole'
|
||||
export * from './IRoutes'
|
||||
export * from './ITeam'
|
||||
export * from './IUser'
|
||||
export * from './IUser'
|
||||
export * from './IUserInTeam'
|
||||
export * from './IUserTeam'
|
||||
export * from './URLFormatter'
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {Team} from '../entities/Team'
|
||||
import {UserTeam} from '../entities/UserTeam'
|
||||
import {IUserTeamParams} from './IUserTeamParams'
|
||||
import {IUserInTeam} from '@rondo/common'
|
||||
|
||||
export interface ITeamService {
|
||||
create(params: {name: string, userId: number}): Promise<Team>
|
||||
@ -17,5 +18,7 @@ export interface ITeamService {
|
||||
|
||||
find(userId: number): Promise<UserTeam[]>
|
||||
|
||||
findUsers(teamId: number): Promise<IUserInTeam[]>
|
||||
|
||||
// TODO add other methods
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {test} from '../test'
|
||||
import {createTeam} from './TeamTestUtils'
|
||||
import {addUser, removeUser, findUsers, createTeam} from './TeamTestUtils'
|
||||
|
||||
describe('team', () => {
|
||||
|
||||
@ -8,10 +8,12 @@ describe('team', () => {
|
||||
|
||||
let cookie!: string
|
||||
let token!: string
|
||||
let mainUserId: number
|
||||
beforeEach(async () => {
|
||||
const session = await test.registerAccount()
|
||||
cookie = session.cookie
|
||||
token = session.token
|
||||
mainUserId = session.userId
|
||||
t.setHeaders({ cookie, 'x-csrf-token': token })
|
||||
})
|
||||
|
||||
@ -78,6 +80,49 @@ describe('team', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /teams/:teamId/users/:userId', () => {
|
||||
it('adds a user to the team', async () => {
|
||||
const team = await createTeam(t, 'test')
|
||||
const teamId = team.id
|
||||
const {userId} = await test.registerAccount('test2@user.com')
|
||||
await addUser(t, {userId, teamId})
|
||||
})
|
||||
})
|
||||
|
||||
describe('DELETE /teams/:teamId/users/:userId', () => {
|
||||
it('removes the user from the team', async () => {
|
||||
const team = await createTeam(t, 'test')
|
||||
const teamId = team.id
|
||||
const {userId} = await test.registerAccount('test2@user.com')
|
||||
await addUser(t, {userId, teamId})
|
||||
await removeUser(t, {userId, teamId})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /teams/:teamId/users', () => {
|
||||
it('fetches team members user info', async () => {
|
||||
const team = await createTeam(t, 'test')
|
||||
const teamId = team.id
|
||||
const {userId} = await test.registerAccount('test2@user.com')
|
||||
await addUser(t, {userId, teamId})
|
||||
const users = await findUsers(t, {teamId})
|
||||
expect(users.length).toBe(2)
|
||||
expect(users).toEqual([{
|
||||
teamId,
|
||||
userId: mainUserId,
|
||||
displayName: jasmine.any(String),
|
||||
roleId: 1,
|
||||
roleName: 'ADMIN',
|
||||
}, {
|
||||
teamId,
|
||||
userId,
|
||||
displayName: jasmine.any(String),
|
||||
roleId: 1,
|
||||
roleName: 'ADMIN',
|
||||
}])
|
||||
})
|
||||
})
|
||||
|
||||
// describe('GET /my/teams', () => {
|
||||
|
||||
// })
|
||||
|
||||
@ -64,6 +64,49 @@ export class TeamRoutes extends BaseRoute<IAPIDef> {
|
||||
})
|
||||
})
|
||||
|
||||
t.get('/teams/:teamId/users', async req => {
|
||||
const teamId = Number(req.params.teamId)
|
||||
|
||||
await this.permissions.belongsToTeam({
|
||||
teamId,
|
||||
userId: req.user!.id,
|
||||
})
|
||||
|
||||
return this.teamService.findUsers(teamId)
|
||||
})
|
||||
|
||||
t.post('/teams/:teamId/users/:userId', async req => {
|
||||
const teamId = Number(req.params.teamId)
|
||||
const userId = Number(req.params.userId)
|
||||
|
||||
await this.permissions.belongsToTeam({
|
||||
teamId,
|
||||
userId: req.user!.id,
|
||||
})
|
||||
|
||||
await this.teamService.addUser({
|
||||
userId,
|
||||
teamId,
|
||||
roleId: 1, // TODO customize roles
|
||||
})
|
||||
})
|
||||
|
||||
t.delete('/teams/:teamId/users/:userId', async req => {
|
||||
const teamId = Number(req.params.teamId)
|
||||
const userId = Number(req.params.userId)
|
||||
|
||||
await this.permissions.belongsToTeam({
|
||||
teamId,
|
||||
userId: req.user!.id,
|
||||
})
|
||||
|
||||
await this.teamService.removeUser({
|
||||
teamId,
|
||||
userId,
|
||||
roleId: 1, // TODO customzie roles
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -49,10 +49,31 @@ export class TeamService extends BaseService implements ITeamService {
|
||||
}
|
||||
|
||||
async removeUser({teamId, userId, roleId}: IUserTeamParams) {
|
||||
// TODO check if this is the last admin team member
|
||||
await this.getRepository(UserTeam)
|
||||
.delete({userId, teamId, roleId})
|
||||
}
|
||||
|
||||
async findUsers(teamId: number) {
|
||||
const userTeams = await this.getRepository(UserTeam)
|
||||
.createQueryBuilder('ut')
|
||||
.select('ut')
|
||||
.innerJoinAndSelect('ut.user', 'user')
|
||||
.innerJoinAndSelect('ut.role', 'role')
|
||||
.where('ut.teamId = :teamId', {
|
||||
teamId,
|
||||
})
|
||||
.getMany()
|
||||
|
||||
return userTeams.map(ut => ({
|
||||
teamId,
|
||||
userId: ut.userId,
|
||||
displayName: `${ut.user.firstName} ${ut.user.lastName}`,
|
||||
roleId: ut.role!.id,
|
||||
roleName: ut.role!.name,
|
||||
}))
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
return this.getRepository(Team).findOne(id)
|
||||
}
|
||||
|
||||
@ -11,3 +11,44 @@ export async function createTeam(t: RequestTester<IAPIDef>, name: string) {
|
||||
expect(response.body.id).toBeTruthy()
|
||||
return response.body
|
||||
}
|
||||
|
||||
export async function addUser(t: RequestTester<IAPIDef>, params: {
|
||||
teamId: number,
|
||||
userId: number,
|
||||
}) {
|
||||
await t
|
||||
.post('/teams/:teamId/users/:userId', {
|
||||
params: {
|
||||
teamId: params.teamId,
|
||||
userId: params.userId,
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
}
|
||||
|
||||
export async function removeUser(t: RequestTester<IAPIDef>, params: {
|
||||
teamId: number,
|
||||
userId: number,
|
||||
}) {
|
||||
await t
|
||||
.delete('/teams/:teamId/users/:userId', {
|
||||
params: {
|
||||
teamId: params.teamId,
|
||||
userId: params.userId,
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
}
|
||||
|
||||
export async function findUsers(t: RequestTester<IAPIDef>, params: {
|
||||
teamId: number,
|
||||
}) {
|
||||
const response = await t
|
||||
.get('/teams/:teamId/users', {
|
||||
params: {
|
||||
teamId: params.teamId,
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
return response.body
|
||||
}
|
||||
|
||||
@ -89,12 +89,16 @@ export class TestUtils<T extends IRoutes> {
|
||||
return match![1]
|
||||
}
|
||||
|
||||
getLoginBody(csrfToken: string) {
|
||||
const {username, password} = this
|
||||
return {username, password, _csrf: csrfToken}
|
||||
getLoginBody(csrfToken: string, username?: string) {
|
||||
const {password} = this
|
||||
return {
|
||||
username: username || this.username,
|
||||
password,
|
||||
_csrf: csrfToken,
|
||||
}
|
||||
}
|
||||
|
||||
async registerAccount() {
|
||||
async registerAccount(username?: string) {
|
||||
const {context} = this
|
||||
const {cookie, token} = await this.getCsrf()
|
||||
|
||||
@ -104,7 +108,7 @@ export class TestUtils<T extends IRoutes> {
|
||||
.send({
|
||||
firstName: 'test',
|
||||
lastName: 'test',
|
||||
...this.getLoginBody(token),
|
||||
...this.getLoginBody(token, username),
|
||||
})
|
||||
.expect(200)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user