1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 11:24:35 +00:00

feat: replace ID with UID

BREAKING CHANGE: remove auto incremental ids from user, group and permissions and add a virtual uid property that returns string value of documents object id
This commit is contained in:
2023-05-09 15:01:56 +05:00
parent d2239f75c2
commit 093fe90589
36 changed files with 461 additions and 483 deletions

View File

@@ -40,8 +40,7 @@ components:
clientId:
type: string
userId:
type: number
format: double
type: string
required:
- clientId
- userId
@@ -285,9 +284,8 @@ components:
additionalProperties: false
UserResponse:
properties:
id:
type: number
format: double
uid:
type: string
username:
type: string
displayName:
@@ -295,7 +293,7 @@ components:
isAdmin:
type: boolean
required:
- id
- uid
- username
- displayName
- isAdmin
@@ -303,32 +301,30 @@ components:
additionalProperties: false
GroupResponse:
properties:
groupId:
type: number
format: double
uid:
type: string
name:
type: string
description:
type: string
required:
- groupId
- uid
- name
- description
type: object
additionalProperties: false
UserDetailsResponse:
properties:
id:
type: number
format: double
displayName:
uid:
type: string
username:
type: string
isActive:
type: boolean
displayName:
type: string
isAdmin:
type: boolean
isActive:
type: boolean
autoExec:
type: string
groups:
@@ -336,11 +332,11 @@ components:
$ref: '#/components/schemas/GroupResponse'
type: array
required:
- id
- displayName
- uid
- username
- isActive
- displayName
- isAdmin
- isActive
type: object
additionalProperties: false
UserPayload:
@@ -376,9 +372,8 @@ components:
additionalProperties: false
GroupDetailsResponse:
properties:
groupId:
type: number
format: double
uid:
type: string
name:
type: string
description:
@@ -390,7 +385,7 @@ components:
$ref: '#/components/schemas/UserResponse'
type: array
required:
- groupId
- uid
- name
- description
- isActive
@@ -459,9 +454,8 @@ components:
additionalProperties: false
PermissionDetailsResponse:
properties:
permissionId:
type: number
format: double
uid:
type: string
path:
type: string
type:
@@ -473,7 +467,7 @@ components:
group:
$ref: '#/components/schemas/GroupDetailsResponse'
required:
- permissionId
- uid
- path
- type
- setting
@@ -512,10 +506,8 @@ components:
description: 'Indicates the type of principal'
example: user
principalId:
type: number
format: double
type: string
description: 'The id of user or group to which a rule is assigned.'
example: 123
required:
- path
- type
@@ -534,25 +526,37 @@ components:
- setting
type: object
additionalProperties: false
SessionResponse:
Pick_UserResponse.Exclude_keyofUserResponse.uid__:
properties:
id:
type: number
format: double
username:
type: string
displayName:
type: string
isAdmin:
type: boolean
needsToUpdatePassword:
type: boolean
required:
- id
- username
- displayName
- isAdmin
- needsToUpdatePassword
type: object
description: 'From T, pick a set of properties whose keys are in the union K'
SessionResponse:
properties:
username:
type: string
displayName:
type: string
isAdmin:
type: boolean
id:
type: string
needsToUpdatePassword:
type: boolean
required:
- username
- displayName
- isAdmin
- id
type: object
additionalProperties: false
ExecutePostRequestPayload:
@@ -1206,7 +1210,7 @@ paths:
type: array
examples:
'Example 1':
value: [{id: 123, username: johnusername, displayName: John, isAdmin: false}, {id: 456, username: starkusername, displayName: Stark, isAdmin: true}]
value: [{uid: userIdString, username: johnusername, displayName: John, isAdmin: false}, {uid: anotherUserIdString, username: starkusername, displayName: Stark, isAdmin: true}]
summary: 'Get list of all users (username, displayname). All users can request this.'
tags:
- User
@@ -1225,7 +1229,7 @@ paths:
$ref: '#/components/schemas/UserDetailsResponse'
examples:
'Example 1':
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
value: {uid: userIdString, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
summary: 'Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.'
tags:
- User
@@ -1276,7 +1280,7 @@ paths:
$ref: '#/components/schemas/UserDetailsResponse'
examples:
'Example 1':
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
value: {uid: userIdString, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
summary: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
tags:
- User
@@ -1327,7 +1331,7 @@ paths:
password:
type: string
type: object
'/SASjsApi/user/{userId}':
'/SASjsApi/user/{uid}':
get:
operationId: GetUser
responses:
@@ -1346,14 +1350,12 @@ paths:
bearerAuth: []
parameters:
-
description: 'The user''s identifier'
in: path
name: userId
name: uid
required: true
schema:
format: double
type: number
example: 1234
type: string
'/SASjsApi/user/{userId}':
patch:
operationId: UpdateUser
responses:
@@ -1365,7 +1367,7 @@ paths:
$ref: '#/components/schemas/UserDetailsResponse'
examples:
'Example 1':
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
value: {uid: userIdString, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
summary: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
tags:
- User
@@ -1379,8 +1381,7 @@ paths:
name: userId
required: true
schema:
format: double
type: number
type: string
example: '1234'
requestBody:
required: true
@@ -1406,8 +1407,7 @@ paths:
name: userId
required: true
schema:
format: double
type: number
type: string
example: 1234
requestBody:
required: true
@@ -1432,7 +1432,7 @@ paths:
type: array
examples:
'Example 1':
value: [{groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users'}]
value: [{uid: groupIdString, name: DCGroup, description: 'This group represents Data Controller Users'}]
summary: 'Get list of all groups (groupName and groupDescription). All users can request this.'
tags:
- Group
@@ -1451,7 +1451,7 @@ paths:
$ref: '#/components/schemas/GroupDetailsResponse'
examples:
'Example 1':
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
value: {uid: groupIdString, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
summary: 'Create a new group. Admin only.'
tags:
- Group
@@ -1467,7 +1467,7 @@ paths:
$ref: '#/components/schemas/GroupPayload'
'/SASjsApi/group/by/groupname/{name}':
get:
operationId: GetGroupByGroupName
operationId: GetGroupByName
responses:
'200':
description: Ok
@@ -1489,7 +1489,7 @@ paths:
required: true
schema:
type: string
'/SASjsApi/group/{groupId}':
'/SASjsApi/group/{uid}':
get:
operationId: GetGroup
responses:
@@ -1509,12 +1509,11 @@ paths:
-
description: 'The group''s identifier'
in: path
name: groupId
name: uid
required: true
schema:
format: double
type: number
example: 1234
type: string
example: 12ByteString
delete:
operationId: DeleteGroup
responses:
@@ -1536,13 +1535,12 @@ paths:
-
description: 'The group''s identifier'
in: path
name: groupId
name: uid
required: true
schema:
format: double
type: number
example: 1234
'/SASjsApi/group/{groupId}/{userId}':
type: string
example: 12ByteString
'/SASjsApi/group/{groupUid}/{userUid}':
post:
operationId: AddUserToGroup
responses:
@@ -1554,7 +1552,7 @@ paths:
$ref: '#/components/schemas/GroupDetailsResponse'
examples:
'Example 1':
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
value: {uid: groupIdString, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
summary: 'Add a user to a group. Admin task only.'
tags:
- Group
@@ -1565,21 +1563,18 @@ paths:
-
description: 'The group''s identifier'
in: path
name: groupId
name: groupUid
required: true
schema:
format: double
type: number
example: '1234'
type: string
example: 12ByteString
-
description: 'The user''s identifier'
in: path
name: userId
name: userUid
required: true
schema:
format: double
type: number
example: '6789'
type: string
delete:
operationId: RemoveUserFromGroup
responses:
@@ -1591,8 +1586,8 @@ paths:
$ref: '#/components/schemas/GroupDetailsResponse'
examples:
'Example 1':
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
summary: 'Remove a user to a group. Admin task only.'
value: {uid: groupIdString, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
summary: 'Remove a user from a group. Admin task only.'
tags:
- Group
security:
@@ -1602,21 +1597,19 @@ paths:
-
description: 'The group''s identifier'
in: path
name: groupId
name: groupUid
required: true
schema:
format: double
type: number
example: '1234'
type: string
example: 12ByteString
-
description: 'The user''s identifier'
in: path
name: userId
name: userUid
required: true
schema:
format: double
type: number
example: '6789'
type: string
example: 12ByteString
/SASjsApi/info:
get:
operationId: Info
@@ -1667,7 +1660,7 @@ paths:
type: array
examples:
'Example 1':
value: [{permissionId: 123, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}, {permissionId: 124, path: /SASjsApi/code/execute, type: Route, setting: Grant, group: {groupId: 1, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}}]
value: [{uid: permissionId1String, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {uid: user1-id, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}, {uid: permissionId2String, path: /SASjsApi/code/execute, type: Route, setting: Grant, group: {uid: group1-id, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}}]
description: "Get the list of permission rules applicable the authenticated user.\nIf the user is an admin, all rules are returned."
summary: 'Get the list of permission rules. If the user is admin, all rules are returned.'
tags:
@@ -1687,7 +1680,7 @@ paths:
$ref: '#/components/schemas/PermissionDetailsResponse'
examples:
'Example 1':
value: {permissionId: 123, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
value: {uid: permissionIdString, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {uid: userIdString, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
summary: 'Create a new permission. Admin only.'
tags:
- Permission
@@ -1701,7 +1694,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/RegisterPermissionPayload'
'/SASjsApi/permission/{permissionId}':
'/SASjsApi/permission/{uid}':
patch:
operationId: UpdatePermission
responses:
@@ -1713,7 +1706,7 @@ paths:
$ref: '#/components/schemas/PermissionDetailsResponse'
examples:
'Example 1':
value: {permissionId: 123, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
value: {uid: permissionIdString, path: /SASjsApi/code/execute, type: Route, setting: Grant, user: {uid: userIdString, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
summary: 'Update permission setting. Admin only'
tags:
- Permission
@@ -1722,14 +1715,11 @@ paths:
bearerAuth: []
parameters:
-
description: 'The permission''s identifier'
in: path
name: permissionId
name: uid
required: true
schema:
format: double
type: number
example: 1234
type: string
requestBody:
required: true
content:
@@ -1749,14 +1739,11 @@ paths:
bearerAuth: []
parameters:
-
description: 'The user''s identifier'
in: path
name: permissionId
name: uid
required: true
schema:
format: double
type: number
example: 1234
type: string
/SASjsApi/session:
get:
operationId: Session
@@ -1769,7 +1756,7 @@ paths:
$ref: '#/components/schemas/SessionResponse'
examples:
'Example 1':
value: {id: 123, username: johnusername, displayName: John, isAdmin: false}
value: {id: userIdString, username: johnusername, displayName: John, isAdmin: false, needsToUpdatePassword: false}
summary: 'Get session info (username).'
tags:
- Session
@@ -1863,7 +1850,7 @@ paths:
application/json:
schema:
properties:
user: {properties: {needsToUpdatePassword: {type: boolean}, isAdmin: {type: boolean}, displayName: {type: string}, username: {type: string}, id: {type: number, format: double}}, required: [needsToUpdatePassword, isAdmin, displayName, username, id], type: object}
user: {properties: {needsToUpdatePassword: {type: boolean}, isAdmin: {type: boolean}, displayName: {type: string}, username: {type: string}, id: {}}, required: [needsToUpdatePassword, isAdmin, displayName, username, id], type: object}
loggedIn: {type: boolean}
required:
- user

View File

@@ -27,14 +27,14 @@ import User from '../model/User'
@Tags('Auth')
export class AuthController {
static authCodes: { [key: string]: { [key: string]: string } } = {}
static saveCode = (userId: number, clientId: string, code: string) => {
static saveCode = (userId: string, clientId: string, code: string) => {
if (AuthController.authCodes[userId])
return (AuthController.authCodes[userId][clientId] = code)
AuthController.authCodes[userId] = { [clientId]: code }
return AuthController.authCodes[userId][clientId]
}
static deleteCode = (userId: number, clientId: string) =>
static deleteCode = (userId: string, clientId: string) =>
delete AuthController.authCodes[userId][clientId]
/**
@@ -159,7 +159,7 @@ const updatePassword = async (
) => {
const { currentPassword, newPassword } = data
const userId = req.user?.userId
const dbUser = await User.findOne({ id: userId })
const dbUser = await User.findOne({ _id: userId })
if (!dbUser)
throw {

View File

@@ -12,28 +12,29 @@ import {
import Group, { GroupPayload, PUBLIC_GROUP_NAME } from '../model/Group'
import User from '../model/User'
import { AuthProviderType } from '../utils'
import { UserResponse } from './user'
import { GetUserBy, UserResponse } from './user'
export interface GroupResponse {
groupId: number
uid: string
name: string
description: string
}
export interface GroupDetailsResponse {
groupId: number
name: string
description: string
export interface GroupDetailsResponse extends GroupResponse {
isActive: boolean
users: UserResponse[]
}
interface GetGroupBy {
groupId?: number
_id?: string
name?: string
}
enum GroupAction {
AddUser = 'addUser',
RemoveUser = 'removeUser'
}
@Security('bearerAuth')
@Route('SASjsApi/group')
@Tags('Group')
@@ -44,7 +45,7 @@ export class GroupController {
*/
@Example<GroupResponse[]>([
{
groupId: 123,
uid: 'groupIdString',
name: 'DCGroup',
description: 'This group represents Data Controller Users'
}
@@ -59,7 +60,7 @@ export class GroupController {
*
*/
@Example<GroupDetailsResponse>({
groupId: 123,
uid: 'groupIdString',
name: 'DCGroup',
description: 'This group represents Data Controller Users',
isActive: true,
@@ -78,7 +79,7 @@ export class GroupController {
* @example dcgroup
*/
@Get('by/groupname/{name}')
public async getGroupByGroupName(
public async getGroupByName(
@Path() name: string
): Promise<GroupDetailsResponse> {
return getGroup({ name })
@@ -86,68 +87,66 @@ export class GroupController {
/**
* @summary Get list of members of a group (userName). All users can request this.
* @param groupId The group's identifier
* @example groupId 1234
* @param uid The group's identifier
* @example uid "12ByteString"
*/
@Get('{groupId}')
public async getGroup(
@Path() groupId: number
): Promise<GroupDetailsResponse> {
return getGroup({ groupId })
@Get('{uid}')
public async getGroup(@Path() uid: string): Promise<GroupDetailsResponse> {
return getGroup({ _id: uid })
}
/**
* @summary 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"
* @param groupUid The group's identifier
* @example groupUid "12ByteString"
* @param userUid The user's identifier
* @example userId "12ByteString"
*/
@Example<GroupDetailsResponse>({
groupId: 123,
uid: 'groupIdString',
name: 'DCGroup',
description: 'This group represents Data Controller Users',
isActive: true,
users: []
})
@Post('{groupId}/{userId}')
@Post('{groupUid}/{userUid}')
public async addUserToGroup(
@Path() groupId: number,
@Path() userId: number
@Path() groupUid: string,
@Path() userUid: string
): Promise<GroupDetailsResponse> {
return addUserToGroup(groupId, userId)
return addUserToGroup(groupUid, userUid)
}
/**
* @summary 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"
* @summary Remove a user from a group. Admin task only.
* @param groupUid The group's identifier
* @example groupUid "12ByteString"
* @param userUid The user's identifier
* @example userUid "12ByteString"
*/
@Example<GroupDetailsResponse>({
groupId: 123,
uid: 'groupIdString',
name: 'DCGroup',
description: 'This group represents Data Controller Users',
isActive: true,
users: []
})
@Delete('{groupId}/{userId}')
@Delete('{groupUid}/{userUid}')
public async removeUserFromGroup(
@Path() groupId: number,
@Path() userId: number
@Path() groupUid: string,
@Path() userUid: string
): Promise<GroupDetailsResponse> {
return removeUserFromGroup(groupId, userId)
return removeUserFromGroup(groupUid, userUid)
}
/**
* @summary Delete a group. Admin task only.
* @param groupId The group's identifier
* @example groupId 1234
* @param uid The group's identifier
* @example uid "12ByteString"
*/
@Delete('{groupId}')
public async deleteGroup(@Path() groupId: number) {
const group = await Group.findOne({ groupId })
@Delete('{uid}')
public async deleteGroup(@Path() uid: string) {
const group = await Group.findOne({ _id: uid })
if (!group)
throw {
code: 404,
@@ -160,9 +159,7 @@ export class GroupController {
}
const getAllGroups = async (): Promise<GroupResponse[]> =>
await Group.find({})
.select({ _id: 0, groupId: 1, name: 1, description: 1 })
.exec()
await Group.find({}).select('uid name description').exec()
const createGroup = async ({
name,
@@ -187,7 +184,7 @@ const createGroup = async ({
const savedGroup = await group.save()
return {
groupId: savedGroup.groupId,
uid: savedGroup.uid,
name: savedGroup.name,
description: savedGroup.description,
isActive: savedGroup.isActive,
@@ -198,11 +195,12 @@ const createGroup = async ({
const getGroup = async (findBy: GetGroupBy): Promise<GroupDetailsResponse> => {
const group = (await Group.findOne(
findBy,
'groupId name description isActive users -_id'
'uid name description isActive users'
).populate(
'users',
'id username displayName isAdmin -_id'
'uid username displayName isAdmin'
)) as unknown as GroupDetailsResponse
if (!group)
throw {
code: 404,
@@ -211,7 +209,7 @@ const getGroup = async (findBy: GetGroupBy): Promise<GroupDetailsResponse> => {
}
return {
groupId: group.groupId,
uid: group.uid,
name: group.name,
description: group.description,
isActive: group.isActive,
@@ -220,23 +218,23 @@ const getGroup = async (findBy: GetGroupBy): Promise<GroupDetailsResponse> => {
}
const addUserToGroup = async (
groupId: number,
userId: number
groupUid: string,
userUid: string
): Promise<GroupDetailsResponse> =>
updateUsersListInGroup(groupId, userId, 'addUser')
updateUsersListInGroup(groupUid, userUid, GroupAction.AddUser)
const removeUserFromGroup = async (
groupId: number,
userId: number
groupUid: string,
userUid: string
): Promise<GroupDetailsResponse> =>
updateUsersListInGroup(groupId, userId, 'removeUser')
updateUsersListInGroup(groupUid, userUid, GroupAction.RemoveUser)
const updateUsersListInGroup = async (
groupId: number,
userId: number,
action: 'addUser' | 'removeUser'
groupUid: string,
userUid: string,
action: GroupAction
): Promise<GroupDetailsResponse> => {
const group = await Group.findOne({ groupId })
const group = await Group.findOne({ _id: groupUid })
if (!group)
throw {
code: 404,
@@ -258,7 +256,7 @@ const updateUsersListInGroup = async (
message: `Can't add/remove user to group created by external auth provider.`
}
const user = await User.findOne({ id: userId })
const user = await User.findOne({ _id: userUid })
if (!user)
throw {
code: 404,
@@ -274,7 +272,7 @@ const updateUsersListInGroup = async (
}
const updatedGroup =
action === 'addUser'
action === GroupAction.AddUser
? await group.addUser(user)
: await group.removeUser(user)
@@ -286,7 +284,7 @@ const updateUsersListInGroup = async (
}
return {
groupId: updatedGroup.groupId,
uid: updatedGroup.uid,
name: updatedGroup.name,
description: updatedGroup.description,
isActive: updatedGroup.isActive,

View File

@@ -56,9 +56,9 @@ interface RegisterPermissionPayload {
principalType: PrincipalType
/**
* The id of user or group to which a rule is assigned.
* @example 123
* @example 'groupIdString'
*/
principalId: number
principalId: string
}
interface UpdatePermissionPayload {
@@ -70,7 +70,7 @@ interface UpdatePermissionPayload {
}
export interface PermissionDetailsResponse {
permissionId: number
uid: string
path: string
type: string
setting: string
@@ -91,24 +91,24 @@ export class PermissionController {
*/
@Example<PermissionDetailsResponse[]>([
{
permissionId: 123,
uid: 'permissionId1String',
path: '/SASjsApi/code/execute',
type: 'Route',
setting: 'Grant',
user: {
id: 1,
uid: 'user1-id',
username: 'johnSnow01',
displayName: 'John Snow',
isAdmin: false
}
},
{
permissionId: 124,
uid: 'permissionId2String',
path: '/SASjsApi/code/execute',
type: 'Route',
setting: 'Grant',
group: {
groupId: 1,
uid: 'group1-id',
name: 'DCGroup',
description: 'This group represents Data Controller Users',
isActive: true,
@@ -128,12 +128,12 @@ export class PermissionController {
*
*/
@Example<PermissionDetailsResponse>({
permissionId: 123,
uid: 'permissionIdString',
path: '/SASjsApi/code/execute',
type: 'Route',
setting: 'Grant',
user: {
id: 1,
uid: 'userIdString',
username: 'johnSnow01',
displayName: 'John Snow',
isAdmin: false
@@ -149,36 +149,36 @@ export class PermissionController {
/**
* @summary Update permission setting. Admin only
* @param permissionId The permission's identifier
* @example permissionId 1234
* @example permissionId "permissionIdString"
*/
@Example<PermissionDetailsResponse>({
permissionId: 123,
uid: 'permissionIdString',
path: '/SASjsApi/code/execute',
type: 'Route',
setting: 'Grant',
user: {
id: 1,
uid: 'userIdString',
username: 'johnSnow01',
displayName: 'John Snow',
isAdmin: false
}
})
@Patch('{permissionId}')
@Patch('{uid}')
public async updatePermission(
@Path() permissionId: number,
@Path() uid: string,
@Body() body: UpdatePermissionPayload
): Promise<PermissionDetailsResponse> {
return updatePermission(permissionId, body)
return updatePermission(uid, body)
}
/**
* @summary Delete a permission. Admin only.
* @param permissionId The user's identifier
* @example permissionId 1234
* @example permissionId "permissionIdString"
*/
@Delete('{permissionId}')
public async deletePermission(@Path() permissionId: number) {
return deletePermission(permissionId)
@Delete('{uid}')
public async deletePermission(@Path() uid: string) {
return deletePermission(uid)
}
}
@@ -191,7 +191,7 @@ const getAllPermissions = async (
else {
const permissions: PermissionDetailsResponse[] = []
const dbUser = await User.findOne({ id: user?.userId })
const dbUser = await User.findOne({ _id: user?.userId })
if (!dbUser)
throw {
code: 404,
@@ -227,7 +227,7 @@ const createPermission = async ({
switch (principalType) {
case PrincipalType.user: {
const userInDB = await User.findOne({ id: principalId })
const userInDB = await User.findOne({ _id: principalId })
if (!userInDB)
throw {
code: 404,
@@ -259,7 +259,7 @@ const createPermission = async ({
permission.user = userInDB._id
user = {
id: userInDB.id,
uid: userInDB.uid,
username: userInDB.username,
displayName: userInDB.displayName,
isAdmin: userInDB.isAdmin
@@ -267,7 +267,7 @@ const createPermission = async ({
break
}
case PrincipalType.group: {
const groupInDB = await Group.findOne({ groupId: principalId })
const groupInDB = await Group.findOne({ _id: principalId })
if (!groupInDB)
throw {
code: 404,
@@ -291,13 +291,13 @@ const createPermission = async ({
permission.group = groupInDB._id
group = {
groupId: groupInDB.groupId,
uid: groupInDB.uid,
name: groupInDB.name,
description: groupInDB.description,
isActive: groupInDB.isActive,
users: groupInDB.populate({
path: 'users',
select: 'id username displayName isAdmin -_id',
select: 'uid username displayName isAdmin -_id',
options: { limit: 15 }
}) as unknown as UserResponse[]
}
@@ -314,7 +314,7 @@ const createPermission = async ({
const savedPermission = await permission.save()
return {
permissionId: savedPermission.permissionId,
uid: savedPermission.uid,
path: savedPermission.path,
type: savedPermission.type,
setting: savedPermission.setting,
@@ -324,27 +324,21 @@ const createPermission = async ({
}
const updatePermission = async (
id: number,
uid: string,
data: UpdatePermissionPayload
): Promise<PermissionDetailsResponse> => {
const { setting } = data
const updatedPermission = (await Permission.findOneAndUpdate(
{ permissionId: id },
{ _id: uid },
{ setting },
{ new: true }
)
.select({
_id: 0,
permissionId: 1,
path: 1,
type: 1,
setting: 1
})
.populate({ path: 'user', select: 'id username displayName isAdmin -_id' })
.select('uid path type setting')
.populate({ path: 'user', select: 'uid username displayName isAdmin' })
.populate({
path: 'group',
select: 'groupId name description -_id'
select: 'groupId name description'
})) as unknown as PermissionDetailsResponse
if (!updatedPermission)
throw {
@@ -356,13 +350,13 @@ const updatePermission = async (
return updatedPermission
}
const deletePermission = async (id: number) => {
const permission = await Permission.findOne({ permissionId: id })
const deletePermission = async (uid: string) => {
const permission = await Permission.findOne({ _id: uid })
if (!permission)
throw {
code: 404,
status: 'Not Found',
message: 'Permission not found.'
}
await Permission.deleteOne({ permissionId: id })
await Permission.deleteOne({ _id: uid })
}

View File

@@ -2,8 +2,9 @@ import express from 'express'
import { Request, Security, Route, Tags, Example, Get } from 'tsoa'
import { UserResponse } from './user'
interface SessionResponse extends UserResponse {
needsToUpdatePassword: boolean
interface SessionResponse extends Omit<UserResponse, 'uid'> {
id: string
needsToUpdatePassword?: boolean
}
@Security('bearerAuth')
@@ -14,11 +15,12 @@ export class SessionController {
* @summary Get session info (username).
*
*/
@Example<UserResponse>({
id: 123,
@Example<SessionResponse>({
id: 'userIdString',
username: 'johnusername',
displayName: 'John',
isAdmin: false
isAdmin: false,
needsToUpdatePassword: false
})
@Get('/')
public async session(

View File

@@ -26,18 +26,14 @@ import {
import { GroupController, GroupResponse } from './group'
export interface UserResponse {
id: number
uid: string
username: string
displayName: string
isAdmin: boolean
}
export interface UserDetailsResponse {
id: number
displayName: string
username: string
export interface UserDetailsResponse extends UserResponse {
isActive: boolean
isAdmin: boolean
autoExec?: string
groups?: GroupResponse[]
}
@@ -52,13 +48,13 @@ export class UserController {
*/
@Example<UserResponse[]>([
{
id: 123,
uid: 'userIdString',
username: 'johnusername',
displayName: 'John',
isAdmin: false
},
{
id: 456,
uid: 'anotherUserIdString',
username: 'starkusername',
displayName: 'Stark',
isAdmin: true
@@ -74,7 +70,7 @@ export class UserController {
*
*/
@Example<UserDetailsResponse>({
id: 1234,
uid: 'userIdString',
displayName: 'John Snow',
username: 'johnSnow01',
isAdmin: false,
@@ -111,20 +107,20 @@ export class UserController {
* Only Admin or user itself will get user autoExec code.
* @summary Get user properties - such as group memberships, userName, displayName.
* @param userId The user's identifier
* @example userId 1234
* @example userId "userIdString"
*/
@Get('{userId}')
@Get('{uid}')
public async getUser(
@Request() req: express.Request,
@Path() userId: number
@Path() uid: string
): Promise<UserDetailsResponse> {
const { MODE } = process.env
if (MODE === ModeType.Desktop) return getDesktopAutoExec()
const { user } = req
const getAutoExec = user!.isAdmin || user!.userId == userId
return getUser({ id: userId }, getAutoExec)
const getAutoExec = user!.isAdmin || user!.userId === uid
return getUser({ _id: uid }, getAutoExec)
}
/**
@@ -133,7 +129,7 @@ export class UserController {
* @example username "johnSnow01"
*/
@Example<UserDetailsResponse>({
id: 1234,
uid: 'userIdString',
displayName: 'John Snow',
username: 'johnSnow01',
isAdmin: false,
@@ -158,7 +154,7 @@ export class UserController {
* @example userId "1234"
*/
@Example<UserDetailsResponse>({
id: 1234,
uid: 'userIdString',
displayName: 'John Snow',
username: 'johnSnow01',
isAdmin: false,
@@ -166,7 +162,7 @@ export class UserController {
})
@Patch('{userId}')
public async updateUser(
@Path() userId: number,
@Path() userId: string,
@Body() body: UserPayload
): Promise<UserDetailsResponse> {
const { MODE } = process.env
@@ -174,7 +170,7 @@ export class UserController {
if (MODE === ModeType.Desktop)
return updateDesktopAutoExec(body.autoExec ?? '')
return updateUser({ id: userId }, body)
return updateUser({ _id: userId }, body)
}
/**
@@ -198,18 +194,16 @@ export class UserController {
*/
@Delete('{userId}')
public async deleteUser(
@Path() userId: number,
@Path() userId: string,
@Body() body: { password?: string },
@Query() @Hidden() isAdmin: boolean = false
) {
return deleteUser({ id: userId }, isAdmin, body)
return deleteUser({ _id: userId }, isAdmin, body)
}
}
const getAllUsers = async (): Promise<UserResponse[]> =>
await User.find({})
.select({ _id: 0, id: 1, username: 1, displayName: 1, isAdmin: 1 })
.exec()
await User.find({}).select('uid username displayName isAdmin').exec()
const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
const { displayName, username, password, isAdmin, isActive, autoExec } = data
@@ -239,15 +233,15 @@ const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
const groupController = new GroupController()
const allUsersGroup = await groupController
.getGroupByGroupName(ALL_USERS_GROUP.name)
.getGroupByName(ALL_USERS_GROUP.name)
.catch(() => {})
if (allUsersGroup) {
await groupController.addUserToGroup(allUsersGroup.groupId, savedUser.id)
await groupController.addUserToGroup(allUsersGroup.uid, savedUser.uid)
}
return {
id: savedUser.id,
uid: savedUser.uid,
displayName: savedUser.displayName,
username: savedUser.username,
isActive: savedUser.isActive,
@@ -256,8 +250,8 @@ const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
}
}
interface GetUserBy {
id?: number
export interface GetUserBy {
_id?: string
username?: string
}
@@ -267,10 +261,10 @@ const getUser = async (
): Promise<UserDetailsResponse> => {
const user = (await User.findOne(
findBy,
`id displayName username isActive isAdmin autoExec -_id`
`uid displayName username isActive isAdmin autoExec`
).populate(
'groups',
'groupId name description -_id'
'uid name description'
)) as unknown as UserDetailsResponse
if (!user)
@@ -280,7 +274,7 @@ const getUser = async (
}
return {
id: user.id,
uid: user.uid,
displayName: user.displayName,
username: user.username,
isActive: user.isActive,
@@ -293,7 +287,7 @@ const getUser = async (
const getDesktopAutoExec = async () => {
return {
...desktopUser,
id: desktopUser.userId,
uid: desktopUser.userId,
autoExec: await getUserAutoExec()
}
}
@@ -329,8 +323,8 @@ const updateUser = async (
const usernameExist = await User.findOne({ username })
if (usernameExist) {
if (
(findBy.id && usernameExist.id != findBy.id) ||
(findBy.username && usernameExist.username != findBy.username)
(findBy._id && usernameExist.uid !== findBy._id) ||
(findBy.username && usernameExist.username !== findBy.username)
)
throw {
code: 409,
@@ -350,11 +344,11 @@ const updateUser = async (
if (!updatedUser)
throw {
code: 404,
message: `Unable to find user with ${findBy.id || findBy.username}`
message: `Unable to find user with ${findBy._id || findBy.username}`
}
return {
id: updatedUser.id,
uid: updatedUser.uid,
username: updatedUser.username,
displayName: updatedUser.displayName,
isAdmin: updatedUser.isAdmin,
@@ -367,7 +361,7 @@ const updateDesktopAutoExec = async (autoExec: string) => {
await updateUserAutoExec(autoExec)
return {
...desktopUser,
id: desktopUser.userId,
uid: desktopUser.userId,
autoExec
}
}

View File

@@ -76,7 +76,7 @@ const authenticateToken = async (
const { MODE } = process.env
if (MODE === ModeType.Desktop) {
req.user = {
userId: 1234,
userId: '1234',
clientId: 'desktopModeClientId',
username: 'desktopModeUsername',
displayName: 'desktopModeDisplayName',

View File

@@ -18,7 +18,7 @@ export const authorize: RequestHandler = async (req, res, next) => {
// no need to check for permissions when route is Public
if (await isPublicRoute(req)) return next()
const dbUser = await User.findOne({ id: user.userId })
const dbUser = await User.findOne({ _id: user.userId })
if (!dbUser) return res.sendStatus(401)
const path = getPath(req)

View File

@@ -28,7 +28,7 @@ export const desktopRestrict: RequestHandler = (req, res, next) => {
}
export const desktopUser: RequestUser = {
userId: 12345,
userId: '12345',
clientId: 'desktop_app',
username: userInfo().username,
displayName: userInfo().username,

View File

@@ -9,7 +9,7 @@ export const verifyAdminIfNeeded: RequestHandler = (req, res, next) => {
let adminAccountRequired: boolean = true
if (req.params.userId) {
adminAccountRequired = user?.userId !== parseInt(req.params.userId)
adminAccountRequired = user?.userId !== req.params.userId
} else if (req.params.username) {
adminAccountRequired = user?.username !== req.params.username
}

View File

@@ -1,9 +1,9 @@
import { Schema, model, Document, Model } from 'mongoose'
import { GroupDetailsResponse } from '../controllers'
import User, { IUser } from './User'
import { AuthProviderType, getSequenceNextValue } from '../utils'
import { AuthProviderType } from '../utils'
export const PUBLIC_GROUP_NAME = 'Public'
export const PUBLIC_GROUP_NAME = 'public'
export interface GroupPayload {
/**
@@ -24,10 +24,12 @@ export interface GroupPayload {
}
interface IGroupDocument extends GroupPayload, Document {
groupId: number
isActive: boolean
users: Schema.Types.ObjectId[]
authProvider?: AuthProviderType
// Declare virtual properties as read-only properties
readonly uid: string
}
interface IGroup extends IGroupDocument {
@@ -37,40 +39,46 @@ interface IGroup extends IGroupDocument {
}
interface IGroupModel extends Model<IGroup> {}
const groupSchema = new Schema<IGroupDocument>({
name: {
type: String,
required: true,
unique: true
},
groupId: {
type: Number,
unique: true
},
description: {
type: String,
default: 'Group description.'
},
authProvider: {
type: String,
enum: AuthProviderType
},
isActive: {
type: Boolean,
default: true
},
users: [{ type: Schema.Types.ObjectId, ref: 'User' }]
})
// Hooks
groupSchema.pre('save', async function () {
if (this.isNew) {
this.groupId = await getSequenceNextValue('groupId')
const opts = {
toJSON: {
virtuals: true,
transform: function (doc: any, ret: any, options: any) {
delete ret._id
delete ret.id
return ret
}
}
}
const groupSchema = new Schema<IGroupDocument>(
{
name: {
type: String,
required: true,
unique: true
},
description: {
type: String,
default: 'Group description.'
},
authProvider: {
type: String,
enum: AuthProviderType
},
isActive: {
type: Boolean,
default: true
},
users: [{ type: Schema.Types.ObjectId, ref: 'User' }]
},
opts
)
groupSchema.virtual('uid').get(function () {
return this._id.toString()
})
groupSchema.post('save', function (group: IGroup, next: Function) {
group.populate('users', 'id username displayName -_id').then(function () {
group.populate('users', 'uid username displayName').then(function () {
next()
})
})

View File

@@ -1,6 +1,5 @@
import { Schema, model, Document, Model } from 'mongoose'
import { PermissionDetailsResponse } from '../controllers'
import { getSequenceNextValue } from '../utils'
interface GetPermissionBy {
user?: Schema.Types.ObjectId
@@ -11,9 +10,11 @@ interface IPermissionDocument extends Document {
path: string
type: string
setting: string
permissionId: number
user: Schema.Types.ObjectId
group: Schema.Types.ObjectId
// Declare virtual properties as read-only properties
readonly uid: string
}
interface IPermission extends IPermissionDocument {}
@@ -22,32 +23,39 @@ interface IPermissionModel extends Model<IPermission> {
get(getBy: GetPermissionBy): Promise<PermissionDetailsResponse[]>
}
const permissionSchema = new Schema<IPermissionDocument>({
permissionId: {
type: Number,
unique: true
},
path: {
type: String,
required: true
},
type: {
type: String,
required: true
},
setting: {
type: String,
required: true
},
user: { type: Schema.Types.ObjectId, ref: 'User' },
group: { type: Schema.Types.ObjectId, ref: 'Group' }
})
// Hooks
permissionSchema.pre('save', async function () {
if (this.isNew) {
this.permissionId = await getSequenceNextValue('permissionId')
const opts = {
toJSON: {
virtuals: true,
transform: function (doc: any, ret: any, options: any) {
delete ret._id
delete ret.id
return ret
}
}
}
const permissionSchema = new Schema<IPermissionDocument>(
{
path: {
type: String,
required: true
},
type: {
type: String,
required: true
},
setting: {
type: String,
required: true
},
user: { type: Schema.Types.ObjectId, ref: 'User' },
group: { type: Schema.Types.ObjectId, ref: 'Group' }
},
opts
)
permissionSchema.virtual('uid').get(function () {
return this._id.toString()
})
// Static Methods
@@ -55,20 +63,14 @@ permissionSchema.static('get', async function (getBy: GetPermissionBy): Promise<
PermissionDetailsResponse[]
> {
return (await this.find(getBy)
.select({
_id: 0,
permissionId: 1,
path: 1,
type: 1,
setting: 1
})
.populate({ path: 'user', select: 'id username displayName isAdmin -_id' })
.select('uid path type setting')
.populate({ path: 'user', select: 'uid username displayName isAdmin' })
.populate({
path: 'group',
select: 'groupId name description -_id',
select: 'uid name description',
populate: {
path: 'users',
select: 'id username displayName isAdmin -_id',
select: 'uid username displayName isAdmin',
options: { limit: 15 }
}
})) as unknown as PermissionDetailsResponse[]

View File

@@ -1,4 +1,4 @@
import { Schema, model, Document, Model } from 'mongoose'
import { Schema, model, Document, Model, ObjectId } from 'mongoose'
import bcrypt from 'bcryptjs'
import { AuthProviderType, getSequenceNextValue } from '../utils'
@@ -36,7 +36,6 @@ export interface UserPayload {
interface IUserDocument extends UserPayload, Document {
_id: Schema.Types.ObjectId
id: number
isAdmin: boolean
isActive: boolean
needsToUpdatePassword: boolean
@@ -44,6 +43,9 @@ interface IUserDocument extends UserPayload, Document {
groups: Schema.Types.ObjectId[]
tokens: [{ [key: string]: string }]
authProvider?: AuthProviderType
// Declare virtual properties as read-only properties
readonly uid: string
}
export interface IUser extends IUserDocument {
@@ -54,70 +56,74 @@ export interface IUser extends IUserDocument {
interface IUserModel extends Model<IUser> {
hashPassword(password: string): string
}
const userSchema = new Schema<IUserDocument>({
displayName: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
id: {
type: Number,
unique: true
},
password: {
type: String,
required: true
},
authProvider: {
type: String,
enum: AuthProviderType
},
isAdmin: {
type: Boolean,
default: false
},
isActive: {
type: Boolean,
default: true
},
needsToUpdatePassword: {
type: Boolean,
default: true
},
autoExec: {
type: String
},
groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }],
tokens: [
{
clientId: {
type: String,
required: true
},
accessToken: {
type: String,
required: true
},
refreshToken: {
type: String,
required: true
}
const opts = {
toJSON: {
virtuals: true,
transform: function (doc: any, ret: any, options: any) {
delete ret._id
delete ret.id
return ret
}
]
})
// Hooks
userSchema.pre('save', async function (next) {
if (this.isNew) {
this.id = await getSequenceNextValue('id')
}
}
next()
const userSchema = new Schema<IUserDocument>(
{
displayName: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
authProvider: {
type: String,
enum: AuthProviderType
},
isAdmin: {
type: Boolean,
default: false
},
isActive: {
type: Boolean,
default: true
},
needsToUpdatePassword: {
type: Boolean,
default: true
},
autoExec: {
type: String
},
groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }],
tokens: [
{
clientId: {
type: String,
required: true
},
accessToken: {
type: String,
required: true
},
refreshToken: {
type: String,
required: true
}
}
]
},
opts
)
userSchema.virtual('uid').get(function () {
return this._id.toString()
})
// Static Methods

View File

@@ -33,12 +33,12 @@ groupRouter.get('/', authenticateAccessToken, async (req, res) => {
}
})
groupRouter.get('/:groupId', authenticateAccessToken, async (req, res) => {
const { groupId } = req.params
groupRouter.get('/:uid', authenticateAccessToken, async (req, res) => {
const { uid } = req.params
const controller = new GroupController()
try {
const response = await controller.getGroup(parseInt(groupId))
const response = await controller.getGroup(uid)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
@@ -56,7 +56,7 @@ groupRouter.get(
const controller = new GroupController()
try {
const response = await controller.getGroupByGroupName(name)
const response = await controller.getGroupByName(name)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
@@ -65,18 +65,33 @@ groupRouter.get(
)
groupRouter.post(
'/:groupId/:userId',
'/:groupUid/:userUid',
authenticateAccessToken,
verifyAdmin,
async (req, res) => {
const { groupId, userId } = req.params
const { groupUid, userUid } = req.params
const controller = new GroupController()
try {
const response = await controller.addUserToGroup(
parseInt(groupId),
parseInt(userId)
)
const response = await controller.addUserToGroup(groupUid, userUid)
res.send(response)
} catch (err: any) {
console.log('err :>> ', err)
res.status(err.code).send(err.message)
}
}
)
groupRouter.delete(
'/:groupUid/:userUid',
authenticateAccessToken,
verifyAdmin,
async (req, res) => {
const { groupUid, userUid } = req.params
const controller = new GroupController()
try {
const response = await controller.removeUserFromGroup(groupUid, userUid)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
@@ -85,35 +100,15 @@ groupRouter.post(
)
groupRouter.delete(
'/:groupId/:userId',
'/:uid',
authenticateAccessToken,
verifyAdmin,
async (req, res) => {
const { groupId, userId } = req.params
const { uid } = req.params
const controller = new GroupController()
try {
const response = await controller.removeUserFromGroup(
parseInt(groupId),
parseInt(userId)
)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
}
}
)
groupRouter.delete(
'/:groupId',
authenticateAccessToken,
verifyAdmin,
async (req, res) => {
const { groupId } = req.params
const controller = new GroupController()
try {
await controller.deleteGroup(parseInt(groupId))
await controller.deleteGroup(uid)
res.status(200).send('Group Deleted!')
} catch (err: any) {
res.status(err.code).send(err.message)

View File

@@ -34,14 +34,14 @@ permissionRouter.post('/', verifyAdmin, async (req, res) => {
}
})
permissionRouter.patch('/:permissionId', verifyAdmin, async (req: any, res) => {
const { permissionId } = req.params
permissionRouter.patch('/:uid', verifyAdmin, async (req: any, res) => {
const { uid } = req.params
const { error, value: body } = updatePermissionValidation(req.body)
if (error) return res.status(400).send(error.details[0].message)
try {
const response = await controller.updatePermission(permissionId, body)
const response = await controller.updatePermission(uid, body)
res.send(response)
} catch (err: any) {
const statusCode = err.code
@@ -50,20 +50,16 @@ permissionRouter.patch('/:permissionId', verifyAdmin, async (req: any, res) => {
}
})
permissionRouter.delete(
'/:permissionId',
verifyAdmin,
async (req: any, res) => {
const { permissionId } = req.params
permissionRouter.delete('/:uid', verifyAdmin, async (req: any, res) => {
const { uid } = req.params
try {
await controller.deletePermission(permissionId)
res.status(200).send('Permission Deleted!')
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err.message)
}
try {
await controller.deletePermission(uid)
res.status(200).send('Permission Deleted!')
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err.message)
}
)
})
export default permissionRouter

View File

@@ -56,12 +56,12 @@ userRouter.get(
}
)
userRouter.get('/:userId', authenticateAccessToken, async (req, res) => {
const { userId } = req.params
userRouter.get('/:uid', authenticateAccessToken, async (req, res) => {
const { uid } = req.params
const controller = new UserController()
try {
const response = await controller.getUser(req, parseInt(userId))
const response = await controller.getUser(req, uid)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
@@ -97,12 +97,12 @@ userRouter.patch(
)
userRouter.patch(
'/:userId',
'/:uid',
authenticateAccessToken,
verifyAdminIfNeeded,
async (req, res) => {
const { user } = req
const { userId } = req.params
const { uid } = req.params
// only an admin can update `isActive` and `isAdmin` fields
const { error, value: body } = updateUserValidation(req.body, user!.isAdmin)
@@ -110,7 +110,7 @@ userRouter.patch(
const controller = new UserController()
try {
const response = await controller.updateUser(parseInt(userId), body)
const response = await controller.updateUser(uid, body)
res.send(response)
} catch (err: any) {
res.status(err.code).send(err.message)
@@ -147,12 +147,12 @@ userRouter.delete(
)
userRouter.delete(
'/:userId',
'/:uid',
authenticateAccessToken,
verifyAdminIfNeeded,
async (req, res) => {
const { user } = req
const { userId } = req.params
const { uid } = req.params
// only an admin can delete user without providing password
const { error, value: data } = deleteUserValidation(req.body, user!.isAdmin)
@@ -160,7 +160,7 @@ userRouter.delete(
const controller = new UserController()
try {
await controller.deleteUser(parseInt(userId), data, user!.isAdmin)
await controller.deleteUser(uid, data, user!.isAdmin)
res.status(200).send('Account Deleted!')
} catch (err: any) {
res.status(err.code).send(err.message)

View File

@@ -1,4 +1,4 @@
export interface InfoJWT {
clientId: string
userId: number
userId: string
}

View File

@@ -1,6 +1,6 @@
export interface PreProgramVars {
username: string
userId: number
userId: string
displayName: string
serverUrl: string
httpHeaders: string[]

View File

@@ -1,5 +1,5 @@
export interface RequestUser {
userId: number
userId: string
clientId: string
username: string
displayName: string

View File

@@ -22,7 +22,7 @@ export const getPreProgramVariables = (req: Request): PreProgramVars => {
//So this is workaround.
return {
username: user ? user.username : 'demo',
userId: user ? user.userId : 0,
userId: user ? user.userId : 'demoId',
displayName: user ? user.displayName : 'demo',
serverUrl: protocol + host,
httpHeaders

View File

@@ -4,7 +4,7 @@ import User from '../model/User'
const isValidToken = async (
token: string,
key: string,
userId: number,
userId: string,
clientId: string
) => {
const promise = new Promise<boolean>((resolve, reject) =>
@@ -22,8 +22,8 @@ const isValidToken = async (
return await promise.then(() => true).catch(() => false)
}
export const getTokensFromDB = async (userId: number, clientId: string) => {
const user = await User.findOne({ id: userId })
export const getTokensFromDB = async (userId: string, clientId: string) => {
const user = await User.findOne({ _id: userId })
if (!user) return
const currentTokenObj = user.tokens.find(

View File

@@ -22,7 +22,7 @@ export const isPublicRoute = async (req: Request): Promise<boolean> => {
}
export const publicUser: RequestUser = {
userId: 0,
userId: 'public_user_id',
clientId: 'public_app',
username: 'publicUser',
displayName: 'Public User',

View File

@@ -1,7 +1,7 @@
import User from '../model/User'
export const removeTokensInDB = async (userId: number, clientId: string) => {
const user = await User.findOne({ id: userId })
export const removeTokensInDB = async (userId: string, clientId: string) => {
const user = await User.findOne({ _id: userId })
if (!user) return
const tokenObjIndex = user.tokens.findIndex(

View File

@@ -1,12 +1,12 @@
import User from '../model/User'
export const saveTokensInDB = async (
userId: number,
userId: string,
clientId: string,
accessToken: string,
refreshToken: string
) => {
const user = await User.findOne({ id: userId })
const user = await User.findOne({ _id: userId })
if (!user) return
const currentTokenObj = user.tokens.find(

View File

@@ -82,7 +82,7 @@ export const seedDB = async (): Promise<ConfigurationType> => {
}
export const ALL_USERS_GROUP = {
name: 'AllUsers',
name: 'all-users',
description: 'Group contains all users'
}

View File

@@ -113,7 +113,7 @@ export const registerPermissionValidation = (data: any): Joi.ValidationResult =>
principalType: Joi.string()
.required()
.valid(...Object.values(PrincipalType)),
principalId: Joi.number().required()
principalId: Joi.string().required()
}).validate(data)
export const updatePermissionValidation = (data: any): Joi.ValidationResult =>

View File

@@ -4,7 +4,7 @@ import { RequestUser } from '../types'
export const fetchLatestAutoExec = async (
reqUser: RequestUser
): Promise<RequestUser | undefined> => {
const dbUser = await User.findOne({ id: reqUser.userId })
const dbUser = await User.findOne({ _id: reqUser.userId })
if (!dbUser) return undefined
@@ -26,7 +26,7 @@ export const verifyTokenInDB = async (
token: string,
tokenType: 'accessToken' | 'refreshToken'
): Promise<RequestUser | undefined> => {
const dbUser = await User.findOne({ id: userId })
const dbUser = await User.findOne({ _id: userId })
if (!dbUser) return undefined

View File

@@ -99,8 +99,8 @@ const AddPermissionModal = ({
principalType: principalType.toLowerCase(),
principalId:
principalType.toLowerCase() === 'user'
? userPrincipal?.id
: groupPrincipal?.groupId
? userPrincipal?.uid
: groupPrincipal?.uid
}
permissions.push(addPermissionPayload)

View File

@@ -61,7 +61,7 @@ const PermissionTable = ({
</TableHead>
<TableBody>
{permissions.map((permission) => (
<TableRow key={permission.permissionId}>
<TableRow key={permission.uid}>
<BootstrapTableCell>{permission.path}</BootstrapTableCell>
<BootstrapTableCell>{permission.type}</BootstrapTableCell>
<BootstrapTableCell>

View File

@@ -69,7 +69,7 @@ const useAddPermission = () => {
for (const permission of updatingPermissions) {
await axios
.patch(`/SASjsApi/permission/${permission.permissionId}`, {
.patch(`/SASjsApi/permission/${permission.uid}`, {
setting: permission.setting === 'Grant' ? 'Deny' : 'Grant'
})
.then((res) => {

View File

@@ -24,7 +24,7 @@ const useDeletePermissionModal = () => {
setDeleteConfirmationModalOpen(false)
setIsLoading(true)
axios
.delete(`/SASjsApi/permission/${selectedPermission?.permissionId}`)
.delete(`/SASjsApi/permission/${selectedPermission?.uid}`)
.then((res: any) => {
fetchPermissions()
setSnackbarMessage('Permission deleted!')

View File

@@ -62,21 +62,17 @@ const useFilterPermissions = () => {
: permissions
let filteredArray = uriFilteredPermissions.filter((permission) =>
principalFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
)
principalFilteredPermissions.some((item) => item.uid === permission.uid)
)
filteredArray = filteredArray.filter((permission) =>
principalTypeFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
(item) => item.uid === permission.uid
)
)
filteredArray = filteredArray.filter((permission) =>
settingFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
)
settingFilteredPermissions.some((item) => item.uid === permission.uid)
)
setFilteredPermissions(filteredArray)

View File

@@ -24,7 +24,7 @@ const useUpdatePermissionModal = () => {
setUpdatePermissionModalOpen(false)
setIsLoading(true)
axios
.patch(`/SASjsApi/permission/${selectedPermission?.permissionId}`, {
.patch(`/SASjsApi/permission/${selectedPermission?.uid}`, {
setting
})
.then((res: any) => {

View File

@@ -27,8 +27,8 @@ interface AppContextProps {
setLoggedIn: Dispatch<SetStateAction<boolean>> | null
needsToUpdatePassword: boolean
setNeedsToUpdatePassword: Dispatch<SetStateAction<boolean>> | null
userId: number
setUserId: Dispatch<SetStateAction<number>> | null
userId: string
setUserId: Dispatch<SetStateAction<string>> | null
username: string
setUsername: Dispatch<SetStateAction<string>> | null
displayName: string
@@ -46,7 +46,7 @@ export const AppContext = createContext<AppContextProps>({
setLoggedIn: null,
needsToUpdatePassword: false,
setNeedsToUpdatePassword: null,
userId: 0,
userId: '',
setUserId: null,
username: '',
setUsername: null,
@@ -64,7 +64,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
const [checkingSession, setCheckingSession] = useState(false)
const [loggedIn, setLoggedIn] = useState(false)
const [needsToUpdatePassword, setNeedsToUpdatePassword] = useState(false)
const [userId, setUserId] = useState(0)
const [userId, setUserId] = useState('')
const [username, setUsername] = useState('')
const [displayName, setDisplayName] = useState('')
const [isAdmin, setIsAdmin] = useState(false)

View File

@@ -6,13 +6,13 @@ export const findExistingPermission = (
) => {
for (const permission of existingPermissions) {
if (
permission.user?.id === newPermission.principalId &&
permission.user?.uid === newPermission.principalId &&
hasSameCombination(permission, newPermission)
)
return permission
if (
permission.group?.groupId === newPermission.principalId &&
permission.group?.uid === newPermission.principalId &&
hasSameCombination(permission, newPermission)
)
return permission
@@ -27,13 +27,13 @@ export const findUpdatingPermission = (
) => {
for (const permission of existingPermissions) {
if (
permission.user?.id === newPermission.principalId &&
permission.user?.uid === newPermission.principalId &&
hasDifferentSetting(permission, newPermission)
)
return permission
if (
permission.group?.groupId === newPermission.principalId &&
permission.group?.uid === newPermission.principalId &&
hasDifferentSetting(permission, newPermission)
)
return permission

View File

@@ -1,12 +1,12 @@
export interface UserResponse {
id: number
uid: number
username: string
displayName: string
isAdmin: boolean
}
export interface GroupResponse {
groupId: number
uid: number
name: string
description: string
}
@@ -17,7 +17,7 @@ export interface GroupDetailsResponse extends GroupResponse {
}
export interface PermissionResponse {
permissionId: number
uid: number
path: string
type: string
setting: string