mirror of
https://github.com/sasjs/server.git
synced 2026-01-05 05:40:06 +00:00
feat: Groups are added + docs
This commit is contained in:
@@ -147,6 +147,63 @@ 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:
|
||||||
|
properties:
|
||||||
|
groupId:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
isActive:
|
||||||
|
type: boolean
|
||||||
|
users:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserResponse'
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- groupId
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
- isActive
|
||||||
|
- users
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
GroupPayload:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 'Name of the group'
|
||||||
|
example: DCGroup
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: 'Description of the group'
|
||||||
|
example: 'This group represents Data Controller Users'
|
||||||
|
isActive:
|
||||||
|
type: boolean
|
||||||
|
description: 'Group should be active or not, defaults to true'
|
||||||
|
example: 'true'
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
ClientPayload:
|
ClientPayload:
|
||||||
properties:
|
properties:
|
||||||
clientId:
|
clientId:
|
||||||
@@ -177,7 +234,7 @@ components:
|
|||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
description: 'Username for user'
|
description: 'Username for user'
|
||||||
example: johnSnow01
|
example: secretuser
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
description: 'Password for user'
|
description: 'Password for user'
|
||||||
@@ -185,7 +242,7 @@ components:
|
|||||||
clientId:
|
clientId:
|
||||||
type: string
|
type: string
|
||||||
description: 'Client ID'
|
description: 'Client ID'
|
||||||
example: someFormattedClientID1234
|
example: clientID1
|
||||||
required:
|
required:
|
||||||
- username
|
- username
|
||||||
- password
|
- password
|
||||||
@@ -212,7 +269,7 @@ components:
|
|||||||
clientId:
|
clientId:
|
||||||
type: string
|
type: string
|
||||||
description: 'Client ID'
|
description: 'Client ID'
|
||||||
example: someFormattedClientID1234
|
example: clientID1
|
||||||
code:
|
code:
|
||||||
type: string
|
type: string
|
||||||
description: 'Authorization code'
|
description: 'Authorization code'
|
||||||
@@ -428,6 +485,175 @@ paths:
|
|||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
/SASjsApi/group:
|
||||||
|
get:
|
||||||
|
operationId: GetAllGroups
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/GroupResponse'
|
||||||
|
type: array
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: [{groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users'}]
|
||||||
|
description: 'Get list of all groups (groupName and groupDescription). All users can request this.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
post:
|
||||||
|
operationId: CreateGroup
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||||
|
description: 'Create a new group. Admin only.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/GroupPayload'
|
||||||
|
'/SASjsApi/group/{groupId}':
|
||||||
|
get:
|
||||||
|
operationId: GetGroup
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
|
description: 'Get list of members of a group (userName). All users can request this.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The group''s identifier'
|
||||||
|
in: path
|
||||||
|
name: groupId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: 1234
|
||||||
|
delete:
|
||||||
|
operationId: DeleteGroup
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 'No content'
|
||||||
|
description: 'Delete a group. Admin task only.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The group''s identifier'
|
||||||
|
in: path
|
||||||
|
name: groupId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: 1234
|
||||||
|
'/SASjsApi/group/{groupId}/{userId}':
|
||||||
|
post:
|
||||||
|
operationId: AddUserToGroup
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||||
|
description: 'Add a user to a group. Admin task only.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The group''s identifier'
|
||||||
|
in: path
|
||||||
|
name: groupId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: '1234'
|
||||||
|
-
|
||||||
|
description: 'The user''s identifier'
|
||||||
|
in: path
|
||||||
|
name: userId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: '6789'
|
||||||
|
delete:
|
||||||
|
operationId: RemoveUserFromGroup
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||||
|
description: 'Remove a user to a group. Admin task only.'
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The group''s identifier'
|
||||||
|
in: path
|
||||||
|
name: groupId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: '1234'
|
||||||
|
-
|
||||||
|
description: 'The user''s identifier'
|
||||||
|
in: path
|
||||||
|
name: userId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: '6789'
|
||||||
/SASjsApi/client:
|
/SASjsApi/client:
|
||||||
post:
|
post:
|
||||||
operationId: CreateClient
|
operationId: CreateClient
|
||||||
@@ -551,3 +777,6 @@ tags:
|
|||||||
-
|
-
|
||||||
name: Drive
|
name: Drive
|
||||||
description: 'Operations about drive'
|
description: 'Operations about drive'
|
||||||
|
-
|
||||||
|
name: Group
|
||||||
|
description: 'Operations about group'
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ const logout = async (userInfo: InfoJWT) => {
|
|||||||
interface AuthorizePayload {
|
interface AuthorizePayload {
|
||||||
/**
|
/**
|
||||||
* Username for user
|
* Username for user
|
||||||
* @example "johnSnow01"
|
* @example "secretuser"
|
||||||
*/
|
*/
|
||||||
username: string
|
username: string
|
||||||
/**
|
/**
|
||||||
@@ -147,7 +147,7 @@ interface AuthorizePayload {
|
|||||||
password: string
|
password: string
|
||||||
/**
|
/**
|
||||||
* Client ID
|
* Client ID
|
||||||
* @example "someFormattedClientID1234"
|
* @example "clientID1"
|
||||||
*/
|
*/
|
||||||
clientId: string
|
clientId: string
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ interface AuthorizeResponse {
|
|||||||
interface TokenPayload {
|
interface TokenPayload {
|
||||||
/**
|
/**
|
||||||
* Client ID
|
* Client ID
|
||||||
* @example "someFormattedClientID1234"
|
* @example "clientID1"
|
||||||
*/
|
*/
|
||||||
clientId: string
|
clientId: string
|
||||||
/**
|
/**
|
||||||
|
|||||||
215
src/controllers/group.ts
Normal file
215
src/controllers/group.ts
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import {
|
||||||
|
Security,
|
||||||
|
Route,
|
||||||
|
Tags,
|
||||||
|
Path,
|
||||||
|
Example,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Delete,
|
||||||
|
Body
|
||||||
|
} from 'tsoa'
|
||||||
|
|
||||||
|
import Group, { GroupPayload } from '../model/Group'
|
||||||
|
import User from '../model/User'
|
||||||
|
import { UserResponse } from './user'
|
||||||
|
|
||||||
|
interface GroupResponse {
|
||||||
|
groupId: number
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GroupDetailsResponse {
|
||||||
|
groupId: number
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
isActive: boolean
|
||||||
|
users: UserResponse[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Security('bearerAuth')
|
||||||
|
@Route('SASjsApi/group')
|
||||||
|
@Tags('Group')
|
||||||
|
export default class GroupController {
|
||||||
|
/**
|
||||||
|
* Get list of all groups (groupName and groupDescription). All users can request this.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Example<GroupResponse[]>([
|
||||||
|
{
|
||||||
|
groupId: 123,
|
||||||
|
name: 'DCGroup',
|
||||||
|
description: 'This group represents Data Controller Users'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
@Get('/')
|
||||||
|
public async getAllGroups(): Promise<GroupResponse[]> {
|
||||||
|
return getAllGroups()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new group. Admin only.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Example<GroupDetailsResponse>({
|
||||||
|
groupId: 123,
|
||||||
|
name: 'DCGroup',
|
||||||
|
description: 'This group represents Data Controller Users',
|
||||||
|
isActive: true,
|
||||||
|
users: []
|
||||||
|
})
|
||||||
|
@Post('/')
|
||||||
|
public async createGroup(
|
||||||
|
@Body() body: GroupPayload
|
||||||
|
): Promise<GroupDetailsResponse> {
|
||||||
|
return createGroup(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of members of a group (userName). All users can request this.
|
||||||
|
* @param groupId The group's identifier
|
||||||
|
* @example groupId 1234
|
||||||
|
*/
|
||||||
|
@Get('{groupId}')
|
||||||
|
public async getGroup(
|
||||||
|
@Path() groupId: number
|
||||||
|
): Promise<GroupDetailsResponse> {
|
||||||
|
return getGroup(groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a user to a group. Admin task only.
|
||||||
|
* @param groupId The group's identifier
|
||||||
|
* @example groupId "1234"
|
||||||
|
* @param userId The user's identifier
|
||||||
|
* @example userId "6789"
|
||||||
|
*/
|
||||||
|
@Example<GroupDetailsResponse>({
|
||||||
|
groupId: 123,
|
||||||
|
name: 'DCGroup',
|
||||||
|
description: 'This group represents Data Controller Users',
|
||||||
|
isActive: true,
|
||||||
|
users: []
|
||||||
|
})
|
||||||
|
@Post('{groupId}/{userId}')
|
||||||
|
public async addUserToGroup(
|
||||||
|
@Path() groupId: number,
|
||||||
|
@Path() userId: number
|
||||||
|
): Promise<GroupDetailsResponse> {
|
||||||
|
return addUserToGroup(groupId, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a user to a group. Admin task only.
|
||||||
|
* @param groupId The group's identifier
|
||||||
|
* @example groupId "1234"
|
||||||
|
* @param userId The user's identifier
|
||||||
|
* @example userId "6789"
|
||||||
|
*/
|
||||||
|
@Example<GroupDetailsResponse>({
|
||||||
|
groupId: 123,
|
||||||
|
name: 'DCGroup',
|
||||||
|
description: 'This group represents Data Controller Users',
|
||||||
|
isActive: true,
|
||||||
|
users: []
|
||||||
|
})
|
||||||
|
@Delete('{groupId}/{userId}')
|
||||||
|
public async removeUserFromGroup(
|
||||||
|
@Path() groupId: number,
|
||||||
|
@Path() userId: number
|
||||||
|
): Promise<GroupDetailsResponse> {
|
||||||
|
return removeUserFromGroup(groupId, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a group. Admin task only.
|
||||||
|
* @param groupId The group's identifier
|
||||||
|
* @example groupId 1234
|
||||||
|
*/
|
||||||
|
@Delete('{groupId}')
|
||||||
|
public async deleteGroup(@Path() groupId: number) {
|
||||||
|
const { deletedCount } = await Group.deleteOne({ groupId })
|
||||||
|
if (deletedCount) return
|
||||||
|
throw new Error('No Group deleted!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAllGroups = async (): Promise<GroupResponse[]> =>
|
||||||
|
await Group.find({})
|
||||||
|
.select({ _id: 0, groupId: 1, name: 1, description: 1 })
|
||||||
|
.exec()
|
||||||
|
|
||||||
|
const createGroup = async ({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
isActive
|
||||||
|
}: GroupPayload): Promise<GroupDetailsResponse> => {
|
||||||
|
const group = new Group({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
isActive
|
||||||
|
})
|
||||||
|
|
||||||
|
const savedGroup = await group.save()
|
||||||
|
|
||||||
|
return {
|
||||||
|
groupId: savedGroup.groupId,
|
||||||
|
name: savedGroup.name,
|
||||||
|
description: savedGroup.description,
|
||||||
|
isActive: savedGroup.isActive,
|
||||||
|
users: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGroup = async (groupId: number): Promise<GroupDetailsResponse> => {
|
||||||
|
const group = (await Group.findOne({ groupId }).populate(
|
||||||
|
'users',
|
||||||
|
'id username displayName -_id'
|
||||||
|
)) as unknown as GroupDetailsResponse
|
||||||
|
if (!group) throw new Error('Group is not found.')
|
||||||
|
|
||||||
|
return {
|
||||||
|
groupId: group.groupId,
|
||||||
|
name: group.name,
|
||||||
|
description: group.description,
|
||||||
|
isActive: group.isActive,
|
||||||
|
users: group.users
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addUserToGroup = async (
|
||||||
|
groupId: number,
|
||||||
|
userId: number
|
||||||
|
): Promise<GroupDetailsResponse> => {
|
||||||
|
const group = await Group.findOne({ groupId })
|
||||||
|
if (!group) throw new Error('Group not found')
|
||||||
|
|
||||||
|
const user = await User.findOne({ id: userId })
|
||||||
|
if (!user) throw new Error('User not found')
|
||||||
|
|
||||||
|
const updatedGroup = (await group.addUser(
|
||||||
|
user._id
|
||||||
|
)) as unknown as GroupDetailsResponse
|
||||||
|
if (!updatedGroup) throw new Error('Unable to update group')
|
||||||
|
|
||||||
|
return updatedGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeUserFromGroup = async (
|
||||||
|
groupId: number,
|
||||||
|
userId: number
|
||||||
|
): Promise<GroupDetailsResponse> => {
|
||||||
|
const group = await Group.findOne({ groupId })
|
||||||
|
if (!group) throw new Error('Group not found')
|
||||||
|
|
||||||
|
const user = await User.findOne({ id: userId })
|
||||||
|
if (!user) throw new Error('User not found')
|
||||||
|
|
||||||
|
const updatedGroup = (await group.removeUser(
|
||||||
|
user._id
|
||||||
|
)) as unknown as GroupDetailsResponse
|
||||||
|
if (!updatedGroup) throw new Error('Unable to update group')
|
||||||
|
|
||||||
|
return updatedGroup
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import bcrypt from 'bcryptjs'
|
|||||||
|
|
||||||
import User, { UserPayload } from '../model/User'
|
import User, { UserPayload } from '../model/User'
|
||||||
|
|
||||||
interface UserResponse {
|
export interface UserResponse {
|
||||||
id: number
|
id: number
|
||||||
username: string
|
username: string
|
||||||
displayName: string
|
displayName: string
|
||||||
@@ -123,7 +123,7 @@ const getAllUsers = async (): Promise<UserResponse[]> =>
|
|||||||
.select({ _id: 0, id: 1, username: 1, displayName: 1 })
|
.select({ _id: 0, id: 1, username: 1, displayName: 1 })
|
||||||
.exec()
|
.exec()
|
||||||
|
|
||||||
const createUser = async (data: any): Promise<UserDetailsResponse> => {
|
const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
|
||||||
const { displayName, username, password, isAdmin, isActive } = data
|
const { displayName, username, password, isAdmin, isActive } = data
|
||||||
|
|
||||||
// Checking if user is already in the database
|
// Checking if user is already in the database
|
||||||
@@ -154,7 +154,7 @@ const createUser = async (data: any): Promise<UserDetailsResponse> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUser = async (id: number) => {
|
const getUser = async (id: number): Promise<UserDetailsResponse> => {
|
||||||
const user = await User.findOne({ id })
|
const user = await User.findOne({ id })
|
||||||
.select({
|
.select({
|
||||||
_id: 0,
|
_id: 0,
|
||||||
@@ -170,7 +170,10 @@ const getUser = async (id: number) => {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateUser = async (id: number, data: any) => {
|
const updateUser = async (
|
||||||
|
id: number,
|
||||||
|
data: UserPayload
|
||||||
|
): Promise<UserDetailsResponse> => {
|
||||||
const { displayName, username, password, isAdmin, isActive } = data
|
const { displayName, username, password, isAdmin, isActive } = data
|
||||||
|
|
||||||
const params: any = { displayName, username, isAdmin, isActive }
|
const params: any = { displayName, username, isAdmin, isActive }
|
||||||
@@ -196,14 +199,16 @@ const updateUser = async (id: number, data: any) => {
|
|||||||
return updatedUser
|
return updatedUser
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteUser = async (id: number, isAdmin: boolean, data: any) => {
|
const deleteUser = async (
|
||||||
const { password } = data
|
id: number,
|
||||||
|
isAdmin: boolean,
|
||||||
|
{ password }: { password?: string }
|
||||||
|
) => {
|
||||||
const user = await User.findOne({ id })
|
const user = await User.findOne({ id })
|
||||||
if (!user) throw new Error('User is not found.')
|
if (!user) throw new Error('User is not found.')
|
||||||
|
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
const validPass = await bcrypt.compare(password, user.password)
|
const validPass = await bcrypt.compare(password!, user.password)
|
||||||
if (!validPass) throw new Error('Invalid password.')
|
if (!validPass) throw new Error('Invalid password.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
src/model/Group.ts
Normal file
87
src/model/Group.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import mongoose, { Schema, model, Document, Model } from 'mongoose'
|
||||||
|
const AutoIncrement = require('mongoose-sequence')(mongoose)
|
||||||
|
|
||||||
|
export interface GroupPayload {
|
||||||
|
/**
|
||||||
|
* Name of the group
|
||||||
|
* @example "DCGroup"
|
||||||
|
*/
|
||||||
|
name: string
|
||||||
|
/**
|
||||||
|
* Description of the group
|
||||||
|
* @example "This group represents Data Controller Users"
|
||||||
|
*/
|
||||||
|
description: string
|
||||||
|
/**
|
||||||
|
* Group should be active or not, defaults to true
|
||||||
|
* @example "true"
|
||||||
|
*/
|
||||||
|
isActive?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGroupDocument extends GroupPayload, Document {
|
||||||
|
groupId: number
|
||||||
|
isActive: boolean
|
||||||
|
users: Schema.Types.ObjectId[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGroup extends IGroupDocument {
|
||||||
|
addUser(userObjectId: Schema.Types.ObjectId): Promise<IGroup>
|
||||||
|
removeUser(userObjectId: Schema.Types.ObjectId): Promise<IGroup>
|
||||||
|
}
|
||||||
|
interface IGroupModel extends Model<IGroup> {}
|
||||||
|
|
||||||
|
const groupSchema = new Schema({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: 'Group description.'
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
users: [{ type: Schema.Types.ObjectId, ref: 'User' }]
|
||||||
|
})
|
||||||
|
groupSchema.plugin(AutoIncrement, { inc_field: 'groupId' })
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
groupSchema.post('save', function (group: IGroup, next: Function) {
|
||||||
|
group.populate('users', 'id username displayName -_id').then(function () {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Instance Methods
|
||||||
|
groupSchema.method(
|
||||||
|
'addUser',
|
||||||
|
async function (userObjectId: Schema.Types.ObjectId) {
|
||||||
|
const userIdIndex = this.users.indexOf(userObjectId)
|
||||||
|
if (userIdIndex === -1) {
|
||||||
|
this.users.push(userObjectId)
|
||||||
|
}
|
||||||
|
this.markModified('users')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
groupSchema.method(
|
||||||
|
'removeUser',
|
||||||
|
async function (userObjectId: Schema.Types.ObjectId) {
|
||||||
|
const userIdIndex = this.users.indexOf(userObjectId)
|
||||||
|
if (userIdIndex > -1) {
|
||||||
|
this.users.splice(userIdIndex, 1)
|
||||||
|
}
|
||||||
|
this.markModified('users')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const Group: IGroupModel = model<IGroup, IGroupModel>(
|
||||||
|
'Group',
|
||||||
|
groupSchema
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Group
|
||||||
@@ -32,6 +32,7 @@ interface User extends UserPayload {
|
|||||||
id: number
|
id: number
|
||||||
isAdmin: boolean
|
isAdmin: boolean
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
|
groups: Schema.Types.ObjectId[]
|
||||||
tokens: [{ [key: string]: string }]
|
tokens: [{ [key: string]: string }]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ const UserSchema = new Schema<User>({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }],
|
||||||
tokens: [
|
tokens: [
|
||||||
{
|
{
|
||||||
clientId: {
|
clientId: {
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ driveRouter.post('/deploy', async (req, res) => {
|
|||||||
res.send(response)
|
res.send(response)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const statusCode = err.code
|
const statusCode = err.code
|
||||||
|
|
||||||
delete err.code
|
delete err.code
|
||||||
|
|
||||||
res.status(statusCode).send(err)
|
res.status(statusCode).send(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
97
src/routes/api/group.ts
Normal file
97
src/routes/api/group.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import express from 'express'
|
||||||
|
import GroupController from '../../controllers/group'
|
||||||
|
import { authenticateAccessToken, verifyAdmin } from '../../middlewares'
|
||||||
|
import { registerGroupValidation } from '../../utils'
|
||||||
|
import userRouter from './user'
|
||||||
|
|
||||||
|
const groupRouter = express.Router()
|
||||||
|
|
||||||
|
groupRouter.post(
|
||||||
|
'/',
|
||||||
|
authenticateAccessToken,
|
||||||
|
verifyAdmin,
|
||||||
|
async (req, res) => {
|
||||||
|
const { error, value: body } = registerGroupValidation(req.body)
|
||||||
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
const response = await controller.createGroup(body)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
groupRouter.get('/', authenticateAccessToken, async (req, res) => {
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
const response = await controller.getAllGroups()
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
groupRouter.get('/:groupId', authenticateAccessToken, async (req: any, res) => {
|
||||||
|
const { groupId } = req.params
|
||||||
|
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
const response = await controller.getGroup(groupId)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
groupRouter.post(
|
||||||
|
'/:groupId/:userId',
|
||||||
|
authenticateAccessToken,
|
||||||
|
async (req: any, res) => {
|
||||||
|
const { groupId, userId } = req.params
|
||||||
|
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
const response = await controller.addUserToGroup(groupId, userId)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
groupRouter.delete(
|
||||||
|
'/:groupId/:userId',
|
||||||
|
authenticateAccessToken,
|
||||||
|
async (req: any, res) => {
|
||||||
|
const { groupId, userId } = req.params
|
||||||
|
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
const response = await controller.removeUserFromGroup(groupId, userId)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
groupRouter.delete(
|
||||||
|
'/:groupId',
|
||||||
|
authenticateAccessToken,
|
||||||
|
async (req: any, res) => {
|
||||||
|
const { groupId } = req.params
|
||||||
|
|
||||||
|
const controller = new GroupController()
|
||||||
|
try {
|
||||||
|
await controller.deleteGroup(groupId)
|
||||||
|
res.status(200).send('Group Deleted!')
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default groupRouter
|
||||||
@@ -7,6 +7,7 @@ import { authenticateAccessToken, verifyAdmin } from '../../middlewares'
|
|||||||
import driveRouter from './drive'
|
import driveRouter from './drive'
|
||||||
import stpRouter from './stp'
|
import stpRouter from './stp'
|
||||||
import userRouter from './user'
|
import userRouter from './user'
|
||||||
|
import groupRouter from './group'
|
||||||
import clientRouter from './client'
|
import clientRouter from './client'
|
||||||
import authRouter, { connectDB } from './auth'
|
import authRouter, { connectDB } from './auth'
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ const router = express.Router()
|
|||||||
router.use('/drive', authenticateAccessToken, driveRouter)
|
router.use('/drive', authenticateAccessToken, driveRouter)
|
||||||
router.use('/stp', authenticateAccessToken, stpRouter)
|
router.use('/stp', authenticateAccessToken, stpRouter)
|
||||||
router.use('/user', userRouter)
|
router.use('/user', userRouter)
|
||||||
|
router.use('/group', groupRouter)
|
||||||
router.use('/client', authenticateAccessToken, verifyAdmin, clientRouter)
|
router.use('/client', authenticateAccessToken, verifyAdmin, clientRouter)
|
||||||
router.use('/auth', authRouter)
|
router.use('/auth', authRouter)
|
||||||
router.use(
|
router.use(
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ export const tokenValidation = (data: any): Joi.ValidationResult =>
|
|||||||
code: Joi.string().required()
|
code: Joi.string().required()
|
||||||
}).validate(data)
|
}).validate(data)
|
||||||
|
|
||||||
|
export const registerGroupValidation = (data: any): Joi.ValidationResult =>
|
||||||
|
Joi.object({
|
||||||
|
name: Joi.string().min(6).required(),
|
||||||
|
description: Joi.string(),
|
||||||
|
isActive: Joi.boolean()
|
||||||
|
}).validate(data)
|
||||||
|
|
||||||
export const registerUserValidation = (data: any): Joi.ValidationResult =>
|
export const registerUserValidation = (data: any): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
displayName: Joi.string().min(6).required(),
|
displayName: Joi.string().min(6).required(),
|
||||||
|
|||||||
Reference in New Issue
Block a user