Skip to content

Commit

Permalink
feat(user-tenant-service): add idp controller to manage users
Browse files Browse the repository at this point in the history
add idp controller to manage users

GH-38
  • Loading branch information
Surbhi-sharma1 committed Dec 12, 2024
1 parent 9909468 commit 1dd9c3e
Show file tree
Hide file tree
Showing 28 changed files with 2,124 additions and 31 deletions.
4 changes: 3 additions & 1 deletion facades/tenant-mgmt-facade/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ AUTH0_CLIENT_SECRET=
# payment gateway id of payment gateway used for payment
GATEWAY_ACCOUNT_ID=
WEBHOOK_USERNAME=
WEBHOOK_PASSWORD=
WEBHOOK_PASSWORD=

USER_TENANT_SERVICE_URL=
174 changes: 174 additions & 0 deletions facades/tenant-mgmt-facade/src/controllers/tenant-user.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import {
RestBindings,
Request,
get,
getModelSchemaRef,
getFilterSchemaFor,
param,
del,
post,
requestBody,
patch,
getWhereSchemaFor,
} from '@loopback/rest';

import {inject} from '@loopback/context';
import {authenticate, STRATEGY} from 'loopback4-authentication';
import {authorize} from 'loopback4-authorization';

import {
CONTENT_TYPE,
ErrorCodes,
OPERATION_SECURITY_SPEC,
STATUS_CODE,
} from '@sourceloop/core';
import {AnyObject, Filter, Where} from '@loopback/repository';

import {
TenantMgmtProxyService,
UserTenantServiceProxy,
} from '../services/proxies';
import {PermissionKey} from '../enum/permission-key.enum';

import {UserView} from '../models/user-view.model';
import {UserDto} from '../models/user-dto.model';
import {User} from '../models/user.model';
import {IdpDetailsDTO} from '../models/idp-details-dto.model';
import {TenantHelperService} from '../services';
import {service} from '@loopback/core';

const basePath = '/tenants/{id}/users';
export class TenantUserController {
private readonly currentUserToken;
constructor(
@inject(RestBindings.Http.REQUEST)
private readonly request: Request,
@inject('services.TenantMgmtProxyService')
private readonly tenantMgmtProxyService: TenantMgmtProxyService,
@inject('services.UserTenantServiceProxy')
private readonly utService: UserTenantServiceProxy,
@service(TenantHelperService)
private readonly tenantHelper: TenantHelperService,
) {
this.currentUserToken = this.request.headers.authorization;
}

@authenticate(STRATEGY.BEARER, {
passReqToCallback: true,
})
@authorize({
permissions: [
PermissionKey.ViewTenantUser,
PermissionKey.ViewTenantUserNum,
],
})
@get(basePath, {
security: OPERATION_SECURITY_SPEC,
responses: {
...ErrorCodes,
[STATUS_CODE.OK]: {
description: 'Array of Tenant has many Users',
content: {
[CONTENT_TYPE.JSON]: {
schema: {type: 'array', items: getModelSchemaRef(User)},
},
},
},
},
})
async find(
@param.path.string('id') id: string,
@param.query.object('filter', getFilterSchemaFor(UserView))
filter?: Filter<UserView>,
): Promise<UserView[]> {
return this.utService.findTenantUser(
id,
this.currentUserToken,
JSON.stringify(filter),
);
}

@authenticate(STRATEGY.BEARER, {
passReqToCallback: true,
})
@authorize({
permissions: [
PermissionKey.ViewTenant,
PermissionKey.CreateTenantUser,
PermissionKey.CreateTenantUserNum,
],
})
@post(basePath, {
security: OPERATION_SECURITY_SPEC,
responses: {
...ErrorCodes,
[STATUS_CODE.OK]: {
description: 'tenant user model instance',
content: {
[CONTENT_TYPE.JSON]: {schema:Object},
},
},
},
})
async create(
@param.path.string('id') id: string,
@requestBody({
[CONTENT_TYPE.JSON]: {
schema: getModelSchemaRef(IdpDetailsDTO, {
title: 'NewUserInTenant',
}),
},
})
userData: IdpDetailsDTO,
): Promise<AnyObject> {
return this.tenantHelper.createTenantUser(id,userData,this.currentUserToken);
const authId=this.utService.configureIdpDetails(userData,this.currentUserToken)
// const userDataPayload = {
// firstName: userData.firstName,
// middleName: userData.middleName,
// lastname: userData.last_name,
// username: userData.username,
// email: userData.email,
// designation: userData.designation,
// phone: userData.phone,
// authClientIds: userData.authClientIds,
// photoUrl: userData.photoUrl,
// gender: userData.gender,
// dob: userData.dob,
// roleId: userData.roleId ,
// locale: userData.locale,
// } as Partial<UserDto>;

// this.utService.createTenantUser(id, userDataPayload, this.currentUserToken);
// return {};
}

@authenticate(STRATEGY.BEARER, {
passReqToCallback: true,
})
@authorize({
permissions: [
PermissionKey.DeleteTenantUser,
PermissionKey.DeleteTenantUserNum,
],
})
@del(`${basePath}/{userId}`, {
security: OPERATION_SECURITY_SPEC,
responses: {
[STATUS_CODE.NO_CONTENT]: {
description: 'User DELETE success',
},
},
})
async deleteById(
@param.path.string('id') id: string,
@param.path.string('userId') userId: string,
): Promise<void> {
return this.utService.deleteTenantUserById(
id,
userId,
this.currentUserToken,
);
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './subscription-proxy.datasource';
export * from './tenant-mgmt-proxy.datasource';
export * from './notification-proxy.datasource';
export * from './user-tenant-service.datasource'
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';
import {CONTENT_TYPE} from '@sourceloop/core';

const tokenKey = '{token}';
const config = {
name: 'UserTenantService',
connector: 'rest',
baseUrl: process.env.USER_TENANT_SERVICE_URL as string,
crud: true,
options: {
baseUrl: process.env.USER_TENANT_SERVICE_URL as string,
headers: {
accept: CONTENT_TYPE.JSON,
['content-type']: CONTENT_TYPE.JSON,
},
},
operations: [
{
template: {
method: 'POST',
url: '/idp/users',
headers: {
Authorization: '{token}',
},
body: '{body}',
},
functions: {
configureIdpDetails: [ 'body', 'token'],
},
},
{
template: {
method: 'POST',
url: '/tenants/{id}/users',
headers: {
Authorization: '{token}',
},
body: '{body}',
},
functions: {
createTenantUser: ['id', 'body', 'token'],
},
},
{
template: {
method: 'DELETE',
url: `/tenants/{id}/users/{userId}`,
headers: {
Authorization: '{token}',
},
},
functions: {
deleteTenantUserById: ['id', 'userId', 'token'],
},
},
{
template: {
method: 'GET',
url: '/tenants/{id}/users',
headers: {
Authorization: tokenKey,
},
query: {
filter: '{filter}',
},
options: {
useQuerystring: true,
},
},
functions: {
findTenantUser: ['id', 'token', 'filter'],
},
},
],
};

@lifeCycleObserver('datasource')
export class UserTenantServiceDataSource
extends juggler.DataSource
implements LifeCycleObserver
{
static dataSourceName = 'UserTenantService';
static readonly defaultConfig = config;

constructor(
@inject('datasources.config.UserTenantService', {optional: true})
dsConfig: object = config,
) {
const dsConfigJson = {
...dsConfig,
options: {
baseUrl: process.env.USER_SERVICE_URL,
headers: {
accept: 'application/json',
'content-type': 'application/json',
},
},
};
super(dsConfigJson);
}
}
3 changes: 3 additions & 0 deletions facades/tenant-mgmt-facade/src/enum/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ export * from './invoice-status.enum';
export * from './webhook-types.enum';
export * from './subscription-status.enum';
export * from './notification-type.enum';
export * from './status-codes.enum';
export * from './permission-key.enum';
export * from './user-config-key.enum';
15 changes: 15 additions & 0 deletions facades/tenant-mgmt-facade/src/enum/permission-key.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const enum PermissionKey {
ViewTenantUser = 'ViewTenantUser',
CreateTenantUser = 'CreateTenantUser',
UpdateTenantUser = 'UpdateTenantUser',
UpdateTenantUserRestricted = 'UpdateTenantUserRestricted',
DeleteTenantUser = 'DeleteTenantUser',
CreateTenant = 'CreateTenant',
ViewTenant = 'ViewTenant',
ViewTenantUserNum = '12',
CreateTenantUserNum = '13',
UpdateTenantUserNum = '14',
DeleteTenantUserNum = '15',
CreateTenantNum = '16',
ViewTenantNum = '17',
}
68 changes: 68 additions & 0 deletions facades/tenant-mgmt-facade/src/enum/status-codes.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable-next-line @typescript-eslint/naming-convention */
export const enum STATUS_CODE {
// sonarignore:start
CONTINUE = 100,
SWITCHING_PROTOCOLS = 101,
PROCESSING = 102,
EARLYHINTS = 103,
OK = 200,
CREATED = 201,
ACCEPTED = 202,
NON_AUTHORITATIVE_INFORMATION = 203,
NO_CONTENT = 204,
RESET_CONTENT = 205,
PARTIAL_CONTENT = 206,
AMBIGUOUS = 300,
MOVED_PERMANENTLY = 301,
FOUND = 302,
SEE_OTHER = 303,
NOT_MODIFIED = 304,
TEMPORARY_REDIRECT = 307,
PERMANENT_REDIRECT = 308,
BAD_REQUEST = 400,
UNAUTHORISED = 401,
PAYMENT_REQUIRED = 402,
FORBIDDEN = 403,
NOT_FOUND = 404,
METHOD_NOT_ALLOWED = 405,
NOT_ACCEPTABLE = 406,
PROXY_AUTHENTICATION_REQUIRED = 407,
REQUEST_TIMEOUT = 408,
CONFLICT = 409,
GONE = 410,
LENGTH_REQUIRED = 411,
PRECONDITION_FAILED = 412,
PAYLOAD_TOO_LARGE = 413,
URI_TOO_LONG = 414,
UNSUPPORTED_MEDIA_TYPE = 415,
REQUESTED_RANGE_NOT_SATISFIABLE = 416,
EXPECTATION_FAILED = 417,
I_AM_A_TEAPOT = 418,
MISDIRECTED = 421,
UNPROCESSED_ENTITY = 422,
FAILED_DEPENDENCY = 424,
PRECONDITION_REQUIRED = 428,
TOO_MANY_REQUESTS = 429,
INTERNAL_SERVER_ERROR = 500,
NOT_IMPLEMENTED = 501,
BAD_GATEWAY = 502,
SERVICE_UNAVAILABLE = 503,
GATEWAY_TIMEOUT = 504,
HTTP_VERSION_NOT_SUPPORTED = 505,
// sonarignore:end
}

export const ErrorCodes = {
[STATUS_CODE.UNAUTHORISED]: {
description: 'Invalid Credentials.',
},
[STATUS_CODE.BAD_REQUEST]: {
description: 'The syntax of the request entity is incorrect.',
},
[STATUS_CODE.UNPROCESSED_ENTITY]: {
description: 'The syntax of the request entity is incorrect',
},
[STATUS_CODE.NOT_FOUND]: {
description: 'The entity requested does not exist.',
},
};
3 changes: 3 additions & 0 deletions facades/tenant-mgmt-facade/src/enum/user-config-key.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const enum UserConfigKey {
LastAccessedUrl = 'last-accessed-url',
}
Loading

0 comments on commit 1dd9c3e

Please sign in to comment.