Remove unused routes

TBD: fix comments-server
This commit is contained in:
Jerko Steiner 2019-09-11 12:18:10 +07:00
parent 270b28dd68
commit ae2ed21f05
24 changed files with 12 additions and 667 deletions

View File

@ -1,8 +1,6 @@
import {ICredentials} from './ICredentials' import { ICredentials } from './ICredentials'
import {INewUser} from './INewUser' import { INewUser } from './INewUser'
import {ITeam} from './ITeam' import { IUser } from './IUser'
import {IUser} from './IUser'
import {IUserInTeam} from './IUserInTeam'
export interface IAPIDef { export interface IAPIDef {
'/auth/register': { '/auth/register': {
@ -28,98 +26,4 @@ export interface IAPIDef {
} }
} }
} }
'/users/profile': {
'get': {
response: {
id: number
}
}
}
'/users/emails/:email': {
// TODO exposing search by email might be a security concern
'get': {
params: {
email: string
}
response: IUser | undefined
}
}
// TEAM
'/teams': {
post: {
body: {
name: string
}
response: ITeam
}
}
'/teams/:id': {
get: {
params: {
id: number
}
response: ITeam | undefined
}
put: {
params: {
id: number
}
body: {
name: string
}
response: ITeam
}
delete: {
params: {
id: number
}
response: {id: number}
}
}
'/teams/:teamId/users': {
get: {
params: {
teamId: number
}
response: IUserInTeam[] // TODO
}
}
'/teams/:teamId/users/:userId': {
post: {
params: {
teamId: number
userId: number
}
// body: {
// roleId: number
// }
response: IUserInTeam
}
delete: {
params: {
teamId: number
userId: number
}
// body: {
// roleId: number
// }
response: {
teamId: number
userId: number
// roleId: number
}
}
}
'/my/teams': {
get: {
response: ITeam[]
}
}
} }

View File

@ -15,6 +15,7 @@ export interface ICreateUserParams extends ICredentials {
export interface IUserService { export interface IUserService {
getProfile(): Promise<IUser> getProfile(): Promise<IUser>
// TODO exposing search by email might be a security concern
findUserByEmail(email: string): Promise<IUser | undefined> findUserByEmail(email: string): Promise<IUser | undefined>
} }

View File

@ -1,9 +1,6 @@
import {IAuthService} from '../services' import { IAuthService, IUserPermissions } from '../services'
import {ITeamService} from '../team'
import {IUserPermissions} from '../user'
export interface IServices { export interface IServices {
authService: IAuthService authService: IAuthService
teamService: ITeamService
userPermissions: IUserPermissions userPermissions: IUserPermissions
} }

View File

@ -10,8 +10,6 @@ import { TransactionalRouter } from '../router'
import * as routes from '../routes' import * as routes from '../routes'
import * as rpc from '../rpc' import * as rpc from '../rpc'
import * as Services from '../services' import * as Services from '../services'
import * as Team from '../team'
import * as User from '../user'
import { IConfig } from './IConfig' import { IConfig } from './IConfig'
import { IServerConfig } from './IServerConfig' import { IServerConfig } from './IServerConfig'
import { IServices } from './IServices' import { IServices } from './IServices'
@ -29,8 +27,7 @@ export const configureServer: ServerConfigurator = (config, database) => {
const services: IServices = { const services: IServices = {
authService: new Services.AuthService(database), authService: new Services.AuthService(database),
teamService: new Team.TeamService(database), userPermissions: new Services.UserPermissions(database),
userPermissions: new User.UserPermissions(database),
} }
const rpcServices = { const rpcServices = {
@ -95,15 +92,6 @@ export const configureServer: ServerConfigurator = (config, database) => {
authenticator, authenticator,
createTransactionalRouter(), createTransactionalRouter(),
).handle, ).handle,
new routes.UserRoutes(
services.authService,
createTransactionalRouter(),
).handle,
new Team.TeamRoutes(
services.teamService,
services.userPermissions,
createTransactionalRouter(),
).handle,
], ],
error: new Middleware.ErrorApiHandler(logger).handle, error: new Middleware.ErrorApiHandler(logger).handle,
}, },

View File

@ -13,8 +13,6 @@ export * from './router'
export * from './routes' export * from './routes'
export * from './services' export * from './services'
export * from './session' export * from './session'
export * from './user'
export * from './team'
export * from './validator' export * from './validator'
import * as rpc from './rpc' import * as rpc from './rpc'

View File

@ -1,5 +0,0 @@
import {IRole} from '@rondo.dev/common'
export interface IRoleService {
create(name: string): Promise<IRole>
}

View File

@ -1,12 +0,0 @@
import {BaseService} from '../services/BaseService'
import {IRoleService} from './IRoleService'
import {Role} from '../entities/Role'
export class RoleService extends BaseService implements IRoleService {
create(name: string) {
return this.getRepository(Role)
.save({
name,
})
}
}

View File

@ -1,2 +0,0 @@
export * from './IRoleService'
export * from './RoleService'

View File

@ -1,51 +0,0 @@
import {test} from '../test'
describe('user', () => {
test.withDatabase()
const t = test.request('/api')
let cookie!: string
beforeEach(async () => {
await test.registerAccount()
const session = await test.login()
cookie = session.headers.cookie
t.setHeaders(session.headers)
})
describe('GET /users/profile', () => {
it('fetches user profile', async () => {
t.setHeaders({ cookie })
await t
.get('/users/profile')
.expect(200)
})
})
describe('GET /users/emails/:email', () => {
it('fetches user by email', async () => {
t.setHeaders({cookie})
const response = await t
.get('/users/emails/:email', {
params: {
email: test.username,
},
})
.expect(200)
expect(response.body!.firstName).toEqual('test')
})
it('returns an empty body when email is not found', async () => {
t.setHeaders({cookie})
await t
.get('/users/emails/:email', {
params: {
email: 'non-existing@address.com',
},
})
.expect(200)
.expect(/^$/g)
// TODO use status code 404 when an entity is not found
})
})
})

View File

@ -1,26 +0,0 @@
import {AsyncRouter} from '../router'
import {BaseRoute} from './BaseRoute'
import {IAPIDef} from '@rondo.dev/common'
import {IAuthService} from '../services'
import {ensureLoggedInApi} from '../middleware'
export class UserRoutes extends BaseRoute<IAPIDef> {
constructor(
protected readonly userService: IAuthService,
protected readonly t: AsyncRouter<IAPIDef>,
) {
super(t)
}
setup(t: AsyncRouter<IAPIDef>) {
t.use('/users', ensureLoggedInApi)
t.get('/users/emails/:email', async req => {
return this.userService.findUserByEmail(req.params.email)
})
t.get('/users/profile', async req => {
return (await this.userService.findOne(req.user!.id))!
})
}
}

View File

@ -1,4 +1,3 @@
export * from './application' export * from './application'
export * from './AuthRoutes' export * from './AuthRoutes'
export * from './BaseRoute' export * from './BaseRoute'
export * from './UserRoutes'

View File

@ -101,9 +101,9 @@ describe('team', () => {
const teamId = team.id const teamId = team.id
const {userId} = await test.registerAccount('test2@user.com') const {userId} = await test.registerAccount('test2@user.com')
await client.addUser({userId, teamId, roleId: 1}) await client.addUser({userId, teamId, roleId: 1})
const users = await client.findUsers(teamId) const {usersInTeam} = await client.findUsers(teamId)
expect(users.length).toBe(2) expect(usersInTeam.length).toBe(2)
expect(users).toEqual([{ expect(usersInTeam).toEqual([{
teamId, teamId,
userId: mainUserId, userId: mainUserId,
displayName: jasmine.any(String), displayName: jasmine.any(String),

View File

@ -2,7 +2,7 @@ import {IDatabase} from '../database/IDatabase'
import {Validator} from '../validator' import {Validator} from '../validator'
import {Team} from '../entities/Team' import {Team} from '../entities/Team'
import {UserTeam} from '../entities/UserTeam' import {UserTeam} from '../entities/UserTeam'
import {IUserPermissions} from '../user/IUserPermissions' import {IUserPermissions} from '../services/IUserPermissions'
import { import {
trim, trim,
entities as e, entities as e,

View File

@ -1,3 +1,5 @@
export * from './BaseService' export * from './BaseService'
export * from './IAuthService' export * from './IAuthService'
export * from './AuthService' export * from './AuthService'
export * from './IUserPermissions'
export * from './UserPermissions'

View File

@ -1,23 +0,0 @@
import {Team} from '../entities/Team'
import {IUserTeamParams} from './IUserTeamParams'
import {IUserInTeam} from '@rondo.dev/common'
export interface ITeamService {
create(params: {name: string, userId: number}): Promise<Team>
remove(params: {id: number, userId: number}): Promise<{id: number}>
update(params: {id: number, name: string, userId: number}): Promise<Team>
addUser(params: IUserTeamParams): Promise<IUserInTeam>
removeUser(params: IUserTeamParams): Promise<void>
findOne(id: number): Promise<Team | undefined>
find(userId: number): Promise<Team[]>
findUsers(teamId: number): Promise<IUserInTeam[]>
// TODO add other methods
}

View File

@ -1,5 +0,0 @@
export interface IUserTeamParams {
teamId: number
userId: number
roleId: number
}

View File

@ -1,126 +0,0 @@
import {test} from '../test'
import {addUser, removeUser, findUsers, createTeam} from './TeamTestUtils'
describe('team', () => {
test.withDatabase()
const t = test.request('/api')
let mainUserId: number
beforeEach(async () => {
const session = await test.registerAccount()
mainUserId = session.userId
t.setHeaders(session.headers)
})
describe('POST /teams', () => {
it('creates a new team', async () => {
const team = await createTeam(t, 'test')
expect(team.name).toEqual('test')
})
})
describe('GET /teams/:id', () => {
it('retrieves a team by id', async () => {
const team = await createTeam(t, 'test')
const response = await t
.get('/teams/:id', {
params: {
id: team.id,
},
})
.expect(200)
expect(response.body).toEqual(team)
})
})
describe('PUT /teams/:id', () => {
it('updates a team name', async () => {
const team = await createTeam(t, 'test')
const response = await t
.put('/teams/:id', {
params: {
id: team.id,
},
})
.send({
name: team.name + '2',
})
expect(response.body.name).toEqual(team.name + '2')
})
})
describe('DELETE /teams/:id', () => {
it('removes a team by id', async () => {
const team = await createTeam(t, 'test')
await t
.delete('/teams/:id', {
params: {
id: team.id,
},
})
.expect(200)
})
})
describe('GET /my/teams', () => {
it('retrieves all teams belonging to current user', async () => {
const team = await createTeam(t, 'test')
const response = await t
.get('/my/teams')
.expect(200)
expect(response.body.map(myTeam => ({teamId: myTeam.id})))
.toContainEqual({
teamId: team.id,
})
})
})
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', () => {
// })
})

View File

@ -1,114 +0,0 @@
import {AsyncRouter} from '../router'
import {BaseRoute} from '../routes/BaseRoute'
import {IAPIDef} from '@rondo.dev/common'
import {ITeamService} from './ITeamService'
import {IUserPermissions} from '../user/IUserPermissions'
import {ensureLoggedInApi} from '../middleware'
export class TeamRoutes extends BaseRoute<IAPIDef> {
constructor(
protected readonly teamService: ITeamService,
protected readonly permissions: IUserPermissions,
protected readonly t: AsyncRouter<IAPIDef>,
) {
super(t)
}
setup(t: AsyncRouter<IAPIDef>) {
const ensureLoggedIn = [ensureLoggedInApi]
t.get('/teams/:id', ensureLoggedIn, async req => {
const {id} = req.params
return this.teamService.findOne(id)
})
t.get('/my/teams', ensureLoggedIn, async req => {
return this.teamService.find(req.user!.id)
})
t.post('/teams', ensureLoggedIn, async req => {
const {name} = req.body
return this.teamService.create({
name,
userId: req.user!.id,
})
})
t.put('/teams/:id', ensureLoggedIn, async req => {
const id = Number(req.params.id)
await this.permissions.belongsToTeam({
teamId: id,
userId: req.user!.id,
})
return this.teamService.update({
id,
name: req.body.name,
userId: req.user!.id,
})
})
t.delete('/teams/:id', ensureLoggedIn, async req => {
const id = Number(req.params.id)
await this.permissions.belongsToTeam({
teamId: id,
userId: req.user!.id,
})
return this.teamService.remove({
id,
userId: req.user!.id,
})
})
t.get('/teams/:teamId/users', ensureLoggedIn, 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', ensureLoggedIn, async req => {
const teamId = Number(req.params.teamId)
const userId = Number(req.params.userId)
await this.permissions.belongsToTeam({
teamId,
userId: req.user!.id,
})
return this.teamService.addUser({
userId,
teamId,
roleId: 1, // TODO customize roles
})
})
t.delete('/teams/:teamId/users/:userId', ensureLoggedIn, 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
})
return {teamId, userId}
})
}
}

View File

@ -1,121 +0,0 @@
import {IDatabase} from '../database/IDatabase'
import {ITeamService} from './ITeamService'
import {IUserInTeam, trim} from '@rondo.dev/common'
import {IUserTeamParams} from './IUserTeamParams'
import {Team} from '../entities/Team'
import {UserTeam} from '../entities/UserTeam'
import {Validator} from '../validator'
export class TeamService implements ITeamService {
constructor(protected readonly db: IDatabase) {}
// TODO check team limit per user
async create({name, userId}: {name: string, userId: number}) {
name = trim(name)
new Validator({name, userId})
.ensure('name')
.ensure('userId')
.throw()
const team = await this.db.getRepository(Team).save({
name,
userId,
})
await this.addUser({
teamId: team.id,
userId,
// ADMIN role
roleId: 1,
})
return (await this.findOne(team.id))!
}
async remove({id, userId}: {id: number, userId: number}) {
await this.db.getRepository(UserTeam)
.delete({teamId: id, userId})
await this.db.getRepository(Team)
.delete(id)
return {id}
}
async update({id, name, userId}: {id: number, name: string, userId: number}) {
await this.db.getRepository(Team)
.update({
id,
}, {
name,
})
return (await this.findOne(id))!
}
async addUser(params: IUserTeamParams) {
const {userId, teamId, roleId} = params
await this.db.getRepository(UserTeam)
.save({userId, teamId, roleId})
const userTeam = await this.createFindUserInTeamQuery()
.where({
userId,
teamId,
roleId,
})
.getOne()
return this.mapUserInTeam(userTeam!)
}
async removeUser({teamId, userId, roleId}: IUserTeamParams) {
// TODO check if this is the last admin team member
await this.db.getRepository(UserTeam)
.delete({userId, teamId, roleId})
}
async findUsers(teamId: number) {
const userTeams = await this.createFindUserInTeamQuery()
.where('ut.teamId = :teamId', {
teamId,
})
.getMany()
return userTeams.map(this.mapUserInTeam)
}
async findOne(id: number) {
return this.db.getRepository(Team).findOne(id)
}
async find(userId: number) {
return this.db.getRepository(Team)
.createQueryBuilder('team')
.select('team')
.innerJoin('team.userTeams', 'ut')
.where('ut.userId = :userId', {userId})
.getMany()
}
protected createFindUserInTeamQuery() {
return this.db.getRepository(UserTeam)
.createQueryBuilder('ut')
.select('ut')
.innerJoinAndSelect('ut.user', 'user')
.innerJoinAndSelect('ut.role', 'role')
}
protected mapUserInTeam(ut: UserTeam): IUserInTeam {
return {
teamId: ut.teamId,
userId: ut.userId,
displayName: `${ut.user.firstName} ${ut.user.lastName}`,
roleId: ut.role!.id,
roleName: ut.role!.name,
}
}
}

View File

@ -1,54 +0,0 @@
import {RequestTester} from '../test-utils'
import {IAPIDef} from '@rondo.dev/common'
export async function createTeam(t: RequestTester<IAPIDef>, name: string) {
const response = await t
.post('/teams')
.send({
name: 'test',
})
.expect(200)
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
}

View File

@ -1,3 +0,0 @@
export * from './ITeamService'
export * from './TeamRoutes'
export * from './TeamService'

View File

@ -1,2 +0,0 @@
export * from './IUserPermissions'
export * from './UserPermissions'