mirror of
https://github.com/sasjs/server.git
synced 2025-12-11 03:34:35 +00:00
Merge pull request #193 from sasjs/issue-192
fix: add/remove group to User when adding/removing user from group
This commit is contained in:
@@ -310,6 +310,21 @@ components:
|
|||||||
- displayName
|
- displayName
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
GroupResponse:
|
||||||
|
properties:
|
||||||
|
groupId:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- groupId
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
UserDetailsResponse:
|
UserDetailsResponse:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@@ -325,6 +340,10 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
autoExec:
|
autoExec:
|
||||||
type: string
|
type: string
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/GroupResponse'
|
||||||
|
type: array
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- displayName
|
- displayName
|
||||||
@@ -364,21 +383,6 @@ components:
|
|||||||
- password
|
- password
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
GroupResponse:
|
|
||||||
properties:
|
|
||||||
groupId:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
description:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- groupId
|
|
||||||
- name
|
|
||||||
- description
|
|
||||||
type: object
|
|
||||||
additionalProperties: false
|
|
||||||
GroupDetailsResponse:
|
GroupDetailsResponse:
|
||||||
properties:
|
properties:
|
||||||
groupId:
|
groupId:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import Group, { GroupPayload } from '../model/Group'
|
|||||||
import User from '../model/User'
|
import User from '../model/User'
|
||||||
import { UserResponse } from './user'
|
import { UserResponse } from './user'
|
||||||
|
|
||||||
interface GroupResponse {
|
export interface GroupResponse {
|
||||||
groupId: number
|
groupId: number
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
@@ -210,6 +210,9 @@ const updateUsersListInGroup = async (
|
|||||||
|
|
||||||
if (!updatedGroup) throw new Error('Unable to update group')
|
if (!updatedGroup) throw new Error('Unable to update group')
|
||||||
|
|
||||||
|
if (action === 'addUser') user.addGroup(group._id)
|
||||||
|
else user.removeGroup(group._id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
groupId: updatedGroup.groupId,
|
groupId: updatedGroup.groupId,
|
||||||
name: updatedGroup.name,
|
name: updatedGroup.name,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { desktopUser } from '../middlewares'
|
|||||||
|
|
||||||
import User, { UserPayload } from '../model/User'
|
import User, { UserPayload } from '../model/User'
|
||||||
import { getUserAutoExec, updateUserAutoExec, ModeType } from '../utils'
|
import { getUserAutoExec, updateUserAutoExec, ModeType } from '../utils'
|
||||||
|
import { GroupResponse } from './group'
|
||||||
|
|
||||||
export interface UserResponse {
|
export interface UserResponse {
|
||||||
id: number
|
id: number
|
||||||
@@ -32,6 +33,7 @@ interface UserDetailsResponse {
|
|||||||
isActive: boolean
|
isActive: boolean
|
||||||
isAdmin: boolean
|
isAdmin: boolean
|
||||||
autoExec?: string
|
autoExec?: string
|
||||||
|
groups?: GroupResponse[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Security('bearerAuth')
|
@Security('bearerAuth')
|
||||||
@@ -242,7 +244,13 @@ const getUser = async (
|
|||||||
findBy: GetUserBy,
|
findBy: GetUserBy,
|
||||||
getAutoExec: boolean
|
getAutoExec: boolean
|
||||||
): Promise<UserDetailsResponse> => {
|
): Promise<UserDetailsResponse> => {
|
||||||
const user = await User.findOne(findBy)
|
const user = (await User.findOne(
|
||||||
|
findBy,
|
||||||
|
`id displayName username isActive isAdmin autoExec -_id`
|
||||||
|
).populate(
|
||||||
|
'groups',
|
||||||
|
'groupId name description -_id'
|
||||||
|
)) as unknown as UserDetailsResponse
|
||||||
|
|
||||||
if (!user) throw new Error('User is not found.')
|
if (!user) throw new Error('User is not found.')
|
||||||
|
|
||||||
@@ -252,7 +260,8 @@ const getUser = async (
|
|||||||
username: user.username,
|
username: user.username,
|
||||||
isActive: user.isActive,
|
isActive: user.isActive,
|
||||||
isAdmin: user.isAdmin,
|
isAdmin: user.isAdmin,
|
||||||
autoExec: getAutoExec ? user.autoExec ?? '' : undefined
|
autoExec: getAutoExec ? user.autoExec ?? '' : undefined,
|
||||||
|
groups: user.groups
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ interface IUserDocument extends UserPayload, Document {
|
|||||||
|
|
||||||
interface IUser extends IUserDocument {
|
interface IUser extends IUserDocument {
|
||||||
comparePassword(password: string): boolean
|
comparePassword(password: string): boolean
|
||||||
|
addGroup(groupObjectId: Schema.Types.ObjectId): Promise<IUser>
|
||||||
|
removeGroup(groupObjectId: Schema.Types.ObjectId): Promise<IUser>
|
||||||
}
|
}
|
||||||
interface IUserModel extends Model<IUser> {
|
interface IUserModel extends Model<IUser> {
|
||||||
hashPassword(password: string): string
|
hashPassword(password: string): string
|
||||||
@@ -106,6 +108,28 @@ userSchema.method('comparePassword', function (password: string): boolean {
|
|||||||
if (bcrypt.compareSync(password, this.password)) return true
|
if (bcrypt.compareSync(password, this.password)) return true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
userSchema.method(
|
||||||
|
'addGroup',
|
||||||
|
async function (groupObjectId: Schema.Types.ObjectId) {
|
||||||
|
const groupIdIndex = this.groups.indexOf(groupObjectId)
|
||||||
|
if (groupIdIndex === -1) {
|
||||||
|
this.groups.push(groupObjectId)
|
||||||
|
}
|
||||||
|
this.markModified('groups')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
userSchema.method(
|
||||||
|
'removeGroup',
|
||||||
|
async function (groupObjectId: Schema.Types.ObjectId) {
|
||||||
|
const groupIdIndex = this.groups.indexOf(groupObjectId)
|
||||||
|
if (groupIdIndex > -1) {
|
||||||
|
this.groups.splice(groupIdIndex, 1)
|
||||||
|
}
|
||||||
|
this.markModified('groups')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export const User: IUserModel = model<IUser, IUserModel>('User', userSchema)
|
export const User: IUserModel = model<IUser, IUserModel>('User', userSchema)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import mongoose, { Mongoose } from 'mongoose'
|
|||||||
import { MongoMemoryServer } from 'mongodb-memory-server'
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||||
import request from 'supertest'
|
import request from 'supertest'
|
||||||
import appPromise from '../../../app'
|
import appPromise from '../../../app'
|
||||||
import { UserController } from '../../../controllers/'
|
import { UserController, GroupController } from '../../../controllers/'
|
||||||
import { generateAccessToken, saveTokensInDB } from '../../../utils'
|
import { generateAccessToken, saveTokensInDB } from '../../../utils'
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
@@ -571,6 +571,7 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toEqual(user.autoExec)
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with user autoExec when admin user requests', async () => {
|
it('should respond with user autoExec when admin user requests', async () => {
|
||||||
@@ -588,6 +589,7 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toEqual(user.autoExec)
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with user when access token is not of an admin account', async () => {
|
it('should respond with user when access token is not of an admin account', async () => {
|
||||||
@@ -610,6 +612,34 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toBeUndefined()
|
expect(res.body.autoExec).toBeUndefined()
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with user along with associated groups', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const userId = dbUser.id
|
||||||
|
const accessToken = await generateAndSaveToken(userId)
|
||||||
|
|
||||||
|
const group = {
|
||||||
|
name: 'DCGroup1',
|
||||||
|
description: 'DC group for testing purposes.'
|
||||||
|
}
|
||||||
|
const groupController = new GroupController()
|
||||||
|
const dbGroup = await groupController.createGroup(group)
|
||||||
|
await groupController.addUserToGroup(dbGroup.groupId, dbUser.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get(`/SASjsApi/user/${userId}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups.length).toBeGreaterThan(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with Unauthorized if access token is not present', async () => {
|
it('should respond with Unauthorized if access token is not present', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user