mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 23:44:53 +00:00
Merge branch 'dev'
This commit is contained in:
14
.env.example
14
.env.example
@ -1,3 +1,5 @@
|
||||
NODE_ENV=
|
||||
|
||||
ACCESS_KEY=
|
||||
|
||||
AZURE_POSTGRESQL_DATABASE=
|
||||
@ -52,6 +54,18 @@ SMTP_SECURE=
|
||||
|
||||
SMTP_USER=
|
||||
|
||||
MAILTRAP_API_TOKEN=
|
||||
|
||||
MAILTRAP_INVITATION_TEMPLATE_UUID=
|
||||
|
||||
MAILTRAP_EDIT_USER_TEMPLATE_UUID=
|
||||
|
||||
MAILTRAP_DISABLE_TEMPLATE_UUID=
|
||||
|
||||
MAILTRAP_ENABLE_TEMPLATE_UUID=
|
||||
|
||||
MAILTRAP_DELETE_USER_TEMPLATE_UUID=
|
||||
|
||||
WEBSITES_ENABLE_APP_SERVICE_STORAGE=
|
||||
|
||||
PORT=
|
||||
|
||||
@ -22,4 +22,11 @@ module.exports = {
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
node: {
|
||||
caseSensitive: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,5 +4,5 @@ export class AuthInterface {
|
||||
uuid: string;
|
||||
sessionId: string;
|
||||
id: number;
|
||||
roles?: string[];
|
||||
role?: object;
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ import { UserSessionRepository } from '../../../../common/src/modules/session/re
|
||||
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { OAuth2Client } from 'google-auth-library';
|
||||
import { PlatformType } from '@app/common/constants/platform-type.enum';
|
||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@ -29,33 +31,46 @@ export class AuthService {
|
||||
email: string,
|
||||
pass: string,
|
||||
regionUuid?: string,
|
||||
platform?: PlatformType,
|
||||
): Promise<any> {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
email,
|
||||
region: regionUuid
|
||||
? {
|
||||
uuid: regionUuid,
|
||||
}
|
||||
: undefined,
|
||||
region: regionUuid ? { uuid: regionUuid } : undefined,
|
||||
},
|
||||
relations: ['roles.roleType'],
|
||||
relations: ['roleType'],
|
||||
});
|
||||
if (
|
||||
platform === PlatformType.WEB &&
|
||||
(user.roleType.type === RoleType.SPACE_OWNER ||
|
||||
user.roleType.type === RoleType.SPACE_MEMBER)
|
||||
) {
|
||||
throw new UnauthorizedException('Access denied for web platform');
|
||||
}
|
||||
if (!user) {
|
||||
throw new BadRequestException('Invalid credentials');
|
||||
}
|
||||
|
||||
if (!user.isUserVerified) {
|
||||
throw new BadRequestException('User is not verified');
|
||||
}
|
||||
if (user) {
|
||||
const passwordMatch = this.helperHashService.bcryptCompare(
|
||||
pass,
|
||||
user.password,
|
||||
);
|
||||
if (passwordMatch) {
|
||||
const { ...result } = user;
|
||||
return result;
|
||||
}
|
||||
if (!user.isActive) {
|
||||
throw new BadRequestException('User is not active');
|
||||
}
|
||||
return null;
|
||||
if (!user.hasAcceptedAppAgreement) {
|
||||
throw new BadRequestException('User has not accepted app agreement');
|
||||
}
|
||||
const passwordMatch = await this.helperHashService.bcryptCompare(
|
||||
pass,
|
||||
user.password,
|
||||
);
|
||||
if (!passwordMatch) {
|
||||
throw new BadRequestException('Invalid credentials');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { password, ...result } = user;
|
||||
return result;
|
||||
}
|
||||
|
||||
async createSession(data): Promise<UserSessionEntity> {
|
||||
@ -85,10 +100,11 @@ export class AuthService {
|
||||
email: user.email,
|
||||
userId: user.userId,
|
||||
uuid: user.uuid,
|
||||
type: user.type,
|
||||
sessionId: user.sessionId,
|
||||
roles: user?.roles,
|
||||
role: user?.role,
|
||||
googleCode: user.googleCode,
|
||||
hasAcceptedWebAgreement: user.hasAcceptedWebAgreement,
|
||||
hasAcceptedAppAgreement: user.hasAcceptedAppAgreement,
|
||||
};
|
||||
if (payload.googleCode) {
|
||||
const profile = await this.getProfile(payload.googleCode);
|
||||
|
||||
@ -31,7 +31,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
userUuid: payload.uuid,
|
||||
uuid: payload.uuid,
|
||||
sessionId: payload.sessionId,
|
||||
roles: payload?.roles,
|
||||
role: payload?.role,
|
||||
};
|
||||
} else {
|
||||
throw new BadRequestException('Unauthorized');
|
||||
|
||||
@ -34,7 +34,7 @@ export class RefreshTokenStrategy extends PassportStrategy(
|
||||
userUuid: payload.uuid,
|
||||
uuid: payload.uuid,
|
||||
sessionId: payload.sessionId,
|
||||
roles: payload?.roles,
|
||||
role: payload?.role,
|
||||
};
|
||||
} else {
|
||||
throw new BadRequestException('Unauthorized');
|
||||
|
||||
@ -9,6 +9,12 @@ import { EmailService } from './util/email.service';
|
||||
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||
import { TuyaService } from './integrations/tuya/services/tuya.service';
|
||||
import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
import { SpaceRepository } from './modules/space';
|
||||
import {
|
||||
SpaceModelRepository,
|
||||
SubspaceModelRepository,
|
||||
} from './modules/space-model';
|
||||
import { SubspaceRepository } from './modules/space/repositories/subspace.repository';
|
||||
@Module({
|
||||
providers: [
|
||||
CommonService,
|
||||
@ -16,6 +22,10 @@ import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
ErrorMessageService,
|
||||
TuyaService,
|
||||
SceneDeviceRepository,
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
SubspaceModelRepository,
|
||||
SpaceModelRepository,
|
||||
],
|
||||
exports: [
|
||||
CommonService,
|
||||
@ -25,6 +35,10 @@ import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
EmailService,
|
||||
ErrorMessageService,
|
||||
SceneDeviceRepository,
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
SubspaceModelRepository,
|
||||
SpaceModelRepository,
|
||||
],
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
|
||||
@ -10,5 +10,14 @@ export default registerAs(
|
||||
SMTP_USER: process.env.SMTP_USER,
|
||||
SMTP_SENDER: process.env.SMTP_SENDER,
|
||||
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
||||
MAILTRAP_API_TOKEN: process.env.MAILTRAP_API_TOKEN,
|
||||
MAILTRAP_INVITATION_TEMPLATE_UUID:
|
||||
process.env.MAILTRAP_INVITATION_TEMPLATE_UUID,
|
||||
MAILTRAP_DISABLE_TEMPLATE_UUID: process.env.MAILTRAP_DISABLE_TEMPLATE_UUID,
|
||||
MAILTRAP_ENABLE_TEMPLATE_UUID: process.env.MAILTRAP_ENABLE_TEMPLATE_UUID,
|
||||
MAILTRAP_DELETE_USER_TEMPLATE_UUID:
|
||||
process.env.MAILTRAP_DELETE_USER_TEMPLATE_UUID,
|
||||
MAILTRAP_EDIT_USER_TEMPLATE_UUID:
|
||||
process.env.MAILTRAP_EDIT_USER_TEMPLATE_UUID,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -2,6 +2,8 @@ export enum ActionExecutorEnum {
|
||||
DEVICE_ISSUE = 'device_issue',
|
||||
DELAY = 'delay',
|
||||
RULE_TRIGGER = 'rule_trigger',
|
||||
RULE_DISABLE = 'rule_disable',
|
||||
RULE_ENABLE = 'rule_enable',
|
||||
}
|
||||
|
||||
export enum EntityTypeEnum {
|
||||
|
||||
@ -1,4 +1,47 @@
|
||||
export class ControllerRoute {
|
||||
static PROJECT = class {
|
||||
public static readonly ROUTE = 'projects';
|
||||
static ACTIONS = class {
|
||||
public static readonly CREATE_PROJECT_SUMMARY = 'Create a new project';
|
||||
public static readonly CREATE_PROJECT_DESCRIPTION =
|
||||
'This endpoint allows you to create a new project by providing the required project details.';
|
||||
|
||||
public static readonly GET_PROJECT_SUMMARY = 'Retrieve project details';
|
||||
public static readonly GET_PROJECT_DESCRIPTION =
|
||||
'This endpoint retrieves the details of a project by its unique identifier (UUID).';
|
||||
|
||||
public static readonly UPDATE_PROJECT_SUMMARY = 'Update project details';
|
||||
public static readonly UPDATE_PROJECT_DESCRIPTION =
|
||||
'This endpoint updates the details of an existing project using its unique identifier (UUID).';
|
||||
|
||||
public static readonly LIST_PROJECTS_SUMMARY = 'List all projects';
|
||||
public static readonly LIST_PROJECTS_DESCRIPTION =
|
||||
'This endpoint retrieves a list of all existing projects, including their details.';
|
||||
|
||||
public static readonly DELETE_PROJECT_SUMMARY = 'Delete a project';
|
||||
public static readonly DELETE_PROJECT_DESCRIPTION =
|
||||
'This endpoint deletes an existing project by its unique identifier (UUID).';
|
||||
|
||||
public static readonly GET_USERS_BY_PROJECT_SUMMARY =
|
||||
'Get users by project';
|
||||
public static readonly GET_USERS_BY_PROJECT_DESCRIPTION =
|
||||
'This endpoint retrieves all users associated with a specific project.';
|
||||
public static readonly GET_USER_BY_UUID_IN_PROJECT_SUMMARY =
|
||||
'Get user by uuid in project';
|
||||
public static readonly GET_USER_BY_UUID_IN_PROJECT_DESCRIPTION =
|
||||
'This endpoint retrieves a user by their unique identifier (UUID) associated with a specific project.';
|
||||
};
|
||||
};
|
||||
static PROJECT_USER = class {
|
||||
public static readonly ROUTE = '/projects/:projectUuid/user';
|
||||
static ACTIONS = class {
|
||||
public static readonly GET_USERS_BY_PROJECT_SUMMARY =
|
||||
'Get users by project';
|
||||
public static readonly GET_USERS_BY_PROJECT_DESCRIPTION =
|
||||
'This endpoint retrieves all users associated with a specific project.';
|
||||
};
|
||||
};
|
||||
|
||||
static REGION = class {
|
||||
public static readonly ROUTE = 'region';
|
||||
static ACTIONS = class {
|
||||
@ -10,7 +53,7 @@ export class ControllerRoute {
|
||||
};
|
||||
|
||||
static COMMUNITY = class {
|
||||
public static readonly ROUTE = 'communities';
|
||||
public static readonly ROUTE = '/projects/:projectUuid/communities';
|
||||
static ACTIONS = class {
|
||||
public static readonly GET_COMMUNITY_BY_ID_SUMMARY =
|
||||
'Get community by community community uuid';
|
||||
@ -115,7 +158,8 @@ export class ControllerRoute {
|
||||
};
|
||||
|
||||
static SPACE = class {
|
||||
public static readonly ROUTE = '/communities/:communityUuid/spaces';
|
||||
public static readonly ROUTE =
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces';
|
||||
static ACTIONS = class {
|
||||
public static readonly CREATE_SPACE_SUMMARY = 'Create a new space';
|
||||
public static readonly CREATE_SPACE_DESCRIPTION =
|
||||
@ -156,7 +200,7 @@ export class ControllerRoute {
|
||||
|
||||
static SPACE_SCENE = class {
|
||||
public static readonly ROUTE =
|
||||
'/communities/:communityUuid/spaces/:spaceUuid/scenes';
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/scenes';
|
||||
static ACTIONS = class {
|
||||
public static readonly GET_TAP_TO_RUN_SCENE_BY_SPACE_SUMMARY =
|
||||
'Retrieve Tap-to-Run Scenes by Space';
|
||||
@ -167,7 +211,7 @@ export class ControllerRoute {
|
||||
|
||||
static SPACE_USER = class {
|
||||
public static readonly ROUTE =
|
||||
'/communities/:communityUuid/spaces/:spaceUuid/user';
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/user';
|
||||
static ACTIONS = class {
|
||||
public static readonly ASSOCIATE_SPACE_USER_SUMMARY =
|
||||
'Associate a user to a space';
|
||||
@ -183,7 +227,7 @@ export class ControllerRoute {
|
||||
|
||||
static SPACE_DEVICES = class {
|
||||
public static readonly ROUTE =
|
||||
'/communities/:communityUuid/spaces/:spaceUuid/devices';
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/devices';
|
||||
static ACTIONS = class {
|
||||
public static readonly LIST_SPACE_DEVICE_SUMMARY =
|
||||
'List devices in a space';
|
||||
@ -194,7 +238,7 @@ export class ControllerRoute {
|
||||
|
||||
static SUBSPACE = class {
|
||||
public static readonly ROUTE =
|
||||
'/communities/:communityUuid/spaces/:spaceUuid/subspaces';
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/subspaces';
|
||||
static ACTIONS = class {
|
||||
public static readonly CREATE_SUBSPACE_SUMMARY = 'Create Subspace';
|
||||
public static readonly CREATE_SUBSPACE_DESCRIPTION =
|
||||
@ -220,7 +264,7 @@ export class ControllerRoute {
|
||||
|
||||
static SUBSPACE_DEVICE = class {
|
||||
public static readonly ROUTE =
|
||||
'/communities/:communityUuid/spaces/:spaceUuid/subspaces/:subSpaceUuid/devices';
|
||||
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/subspaces/:subSpaceUuid/devices';
|
||||
|
||||
static ACTIONS = class {
|
||||
public static readonly LIST_SUBSPACE_DEVICE_SUMMARY =
|
||||
@ -240,6 +284,32 @@ export class ControllerRoute {
|
||||
};
|
||||
};
|
||||
|
||||
static SPACE_MODEL = class {
|
||||
public static readonly ROUTE = '/projects/:projectUuid/space-models';
|
||||
static ACTIONS = class {
|
||||
public static readonly CREATE_SPACE_MODEL_SUMMARY =
|
||||
'Create a New Space Model';
|
||||
public static readonly CREATE_SPACE_MODEL_DESCRIPTION =
|
||||
'This endpoint allows you to create a new space model within a specified project. A space model defines the structure of spaces, including subspaces, products, and product items, and is uniquely identifiable within the project.';
|
||||
|
||||
public static readonly GET_SPACE_MODEL_SUMMARY = 'Get a New Space Model';
|
||||
public static readonly GET_SPACE_MODEL_DESCRIPTION =
|
||||
'Fetch a space model details';
|
||||
|
||||
public static readonly LIST_SPACE_MODEL_SUMMARY = 'List Space Models';
|
||||
public static readonly LIST_SPACE_MODEL_DESCRIPTION =
|
||||
'This endpoint allows you to retrieve a list of space models within a specified project. Each space model includes its structure, associated subspaces, products, and product items.';
|
||||
|
||||
public static readonly UPDATE_SPACE_MODEL_SUMMARY = 'Update Space Model';
|
||||
public static readonly UPDATE_SPACE_MODEL_DESCRIPTION =
|
||||
'This endpoint allows you to update a Space Model attributesas well as manage its associated Subspaces and Device';
|
||||
|
||||
public static readonly DELETE_SPACE_MODEL_SUMMARY = 'Delete Space Model';
|
||||
public static readonly DELETE_SPACE_MODEL_DESCRIPTION =
|
||||
'This endpoint allows you to delete a specified Space Model within a project. Deleting a Space Model disables the model and all its associated subspaces and tags, ensuring they are no longer active but remain in the system for auditing.';
|
||||
};
|
||||
};
|
||||
|
||||
static PRODUCT = class {
|
||||
public static readonly ROUTE = 'products';
|
||||
static ACTIONS = class {
|
||||
@ -279,6 +349,10 @@ export class ControllerRoute {
|
||||
public static readonly DELETE_USER_SUMMARY = 'Delete user by UUID';
|
||||
public static readonly DELETE_USER_DESCRIPTION =
|
||||
'This endpoint deletes a user identified by their UUID. Accessible only by users with the Super Admin role.';
|
||||
public static readonly UPDATE_USER_WEB_AGREEMENT_SUMMARY =
|
||||
'Update user web agreement by user UUID';
|
||||
public static readonly UPDATE_USER_WEB_AGREEMENT_DESCRIPTION =
|
||||
'This endpoint updates the web agreement for a user identified by their UUID.';
|
||||
};
|
||||
};
|
||||
static AUTHENTICATION = class {
|
||||
@ -334,6 +408,25 @@ export class ControllerRoute {
|
||||
'This endpoint adds a new user role to the system based on the provided role data.';
|
||||
};
|
||||
};
|
||||
static TERMS_AND_CONDITIONS = class {
|
||||
public static readonly ROUTE = 'terms';
|
||||
|
||||
static ACTIONS = class {
|
||||
public static readonly FETCH_TERMS_SUMMARY = 'Fetch Terms and Conditions';
|
||||
public static readonly FETCH_TERMS_DESCRIPTION =
|
||||
'This endpoint retrieves the terms and conditions for the application.';
|
||||
};
|
||||
};
|
||||
|
||||
static PRIVACY_POLICY = class {
|
||||
public static readonly ROUTE = 'policy';
|
||||
|
||||
static ACTIONS = class {
|
||||
public static readonly FETCH_POLICY_SUMMARY = 'Fetch Privacy Policy';
|
||||
public static readonly FETCH_POLICY_DESCRIPTION =
|
||||
'This endpoint retrieves the privacy policy for the application.';
|
||||
};
|
||||
};
|
||||
static GROUP = class {
|
||||
public static readonly ROUTE = 'group';
|
||||
|
||||
@ -685,4 +778,53 @@ export class ControllerRoute {
|
||||
'This endpoint deletes a user’s subscription for device messages.';
|
||||
};
|
||||
};
|
||||
static INVITE_USER = class {
|
||||
public static readonly ROUTE = 'invite-user';
|
||||
static ACTIONS = class {
|
||||
public static readonly CREATE_USER_INVITATION_SUMMARY =
|
||||
'Create user invitation';
|
||||
|
||||
public static readonly CREATE_USER_INVITATION_DESCRIPTION =
|
||||
'This endpoint creates an invitation for a user to assign to role and spaces.';
|
||||
|
||||
public static readonly UPDATE_USER_INVITATION_SUMMARY =
|
||||
'Update user invitation';
|
||||
|
||||
public static readonly UPDATE_USER_INVITATION_DESCRIPTION =
|
||||
'This endpoint updates an invitation for a user to assign to role and spaces.';
|
||||
|
||||
public static readonly DISABLE_USER_INVITATION_SUMMARY =
|
||||
'Disable user invitation';
|
||||
|
||||
public static readonly DISABLE_USER_INVITATION_DESCRIPTION =
|
||||
'This endpoint disables an invitation for a user to assign to role and spaces.';
|
||||
|
||||
public static readonly DELETE_USER_INVITATION_SUMMARY =
|
||||
'Delete user invitation';
|
||||
|
||||
public static readonly DELETE_USER_INVITATION_DESCRIPTION =
|
||||
'This endpoint deletes an invitation for a user to assign to role and spaces.';
|
||||
|
||||
public static readonly ACTIVATION_CODE_SUMMARY =
|
||||
'Activate Invitation Code';
|
||||
|
||||
public static readonly ACTIVATION_CODE_DESCRIPTION =
|
||||
'This endpoint activate invitation code';
|
||||
|
||||
public static readonly CHECK_EMAIL_SUMMARY = 'Check email';
|
||||
|
||||
public static readonly CHECK_EMAIL_DESCRIPTION =
|
||||
'This endpoint checks if an email already exists and have a project in the system.';
|
||||
};
|
||||
};
|
||||
static PERMISSION = class {
|
||||
public static readonly ROUTE = 'permission';
|
||||
static ACTIONS = class {
|
||||
public static readonly GET_PERMISSION_BY_ROLE_SUMMARY =
|
||||
'Get permissions by role';
|
||||
|
||||
public static readonly GET_PERMISSION_BY_ROLE_DESCRIPTION =
|
||||
'This endpoint retrieves the permissions associated with a specific role.';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
3
libs/common/src/constants/mail-trap.ts
Normal file
3
libs/common/src/constants/mail-trap.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const SEND_EMAIL_API_URL_PROD = 'https://send.api.mailtrap.io/api/send/';
|
||||
export const SEND_EMAIL_API_URL_DEV =
|
||||
'https://sandbox.api.mailtrap.io/api/send/2634012';
|
||||
5
libs/common/src/constants/modify-action.enum.ts
Normal file
5
libs/common/src/constants/modify-action.enum.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum ModifyAction {
|
||||
ADD = 'add',
|
||||
UPDATE = 'update',
|
||||
DELETE = 'delete',
|
||||
}
|
||||
4
libs/common/src/constants/orphan-constant.ts
Normal file
4
libs/common/src/constants/orphan-constant.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const ORPHAN_COMMUNITY_NAME = 'orphan-community';
|
||||
export const ORPHAN_COMMUNITY_DESCRIPTION =
|
||||
'Default community for orphan spaces';
|
||||
export const ORPHAN_SPACE_NAME = 'orphan-space';
|
||||
53
libs/common/src/constants/permissions-mapping.ts
Normal file
53
libs/common/src/constants/permissions-mapping.ts
Normal file
@ -0,0 +1,53 @@
|
||||
export const PermissionMapping = {
|
||||
DEVICE_MANAGEMENT: {
|
||||
DEVICE: [
|
||||
'SINGLE_CONTROL',
|
||||
'VIEW',
|
||||
'DELETE',
|
||||
'UPDATE',
|
||||
'BATCH_CONTROL',
|
||||
'LOCATION_VIEW',
|
||||
'LOCATION_UPDATE',
|
||||
],
|
||||
FIRMWARE: ['CONTROL', 'VIEW'],
|
||||
},
|
||||
COMMUNITY_MANAGEMENT: {
|
||||
COMMUNITY: ['VIEW', 'ADD', 'UPDATE', 'DELETE'],
|
||||
},
|
||||
SPACE_MANAGEMENT: {
|
||||
SPACE: [
|
||||
'VIEW',
|
||||
'ADD',
|
||||
'UPDATE',
|
||||
'DELETE',
|
||||
'MODEL_ADD',
|
||||
'MODEL_DELETE',
|
||||
'MODEL_VIEW',
|
||||
'ASSIGN_USER_TO_SPACE',
|
||||
'DELETE_USER_FROM_SPACE',
|
||||
],
|
||||
SUBSPACE: [
|
||||
'VIEW',
|
||||
'ADD',
|
||||
'UPDATE',
|
||||
'DELETE',
|
||||
'ASSIGN_DEVICE_TO_SUBSPACE',
|
||||
'DELETE_DEVICE_FROM_SUBSPACE',
|
||||
],
|
||||
},
|
||||
DEVICE_WIZARD: {
|
||||
DEVICE_WIZARD: ['VIEW_DEVICE_WIZARD'],
|
||||
SPACE_DEVICE: ['VIEW_DEVICE_IN_SPACE', 'ASSIGN_DEVICE_TO_SPACE'],
|
||||
SUBSPACE_DEVICE: ['VIEW_DEVICE_IN_SUBSPACE', 'UPDATE_DEVICE_IN_SUBSPACE'],
|
||||
},
|
||||
AUTOMATION_MANAGEMENT: {
|
||||
AUTOMATION: ['VIEW', 'ADD', 'UPDATE', 'DELETE', 'CONTROL'],
|
||||
SCENES: ['VIEW', 'ADD', 'UPDATE', 'DELETE', 'CONTROL'],
|
||||
},
|
||||
VISITOR_PASSWORD_MANAGEMENT: {
|
||||
VISITOR_PASSWORD: ['VIEW', 'ADD', 'UPDATE', 'DELETE'],
|
||||
},
|
||||
USER_MANAGEMENT: {
|
||||
USER: ['ADD'],
|
||||
},
|
||||
};
|
||||
4
libs/common/src/constants/platform-type.enum.ts
Normal file
4
libs/common/src/constants/platform-type.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum PlatformType {
|
||||
WEB = 'web',
|
||||
MOBILE = 'mobile',
|
||||
}
|
||||
37
libs/common/src/constants/privacy-policy.html
Normal file
37
libs/common/src/constants/privacy-policy.html
Normal file
@ -0,0 +1,37 @@
|
||||
<div>
|
||||
<p><strong>Syncrow Mobile Privacy Policy</strong></p>
|
||||
<p>
|
||||
Effective Date: 26/06/2022<br />
|
||||
Updated: 26/06/2022
|
||||
</p>
|
||||
<p>
|
||||
Syncrow and subsidiaries (“we”, “us”, “our”, “Syncrow”) are committed to
|
||||
protecting your privacy. This Privacy Policy (“Policy”) describes our
|
||||
practices in connection with information privacy on Personal Data we process
|
||||
through your individual use of the following services, products, and related
|
||||
mobile applications (collectively, the “Products”):
|
||||
</p>
|
||||
<ul>
|
||||
<li>Syncrow Mobile Application</li>
|
||||
</ul>
|
||||
<p>
|
||||
Before you use our Products, please carefully read through this Policy and
|
||||
understand our purposes and practices of collection, processing of your
|
||||
Personal Data, including how we use, store, share and transfer Personal
|
||||
Data. In the Policy you will also find ways to execute your rights of
|
||||
access, update, delete or protect your Personal Data.
|
||||
</p>
|
||||
<p>
|
||||
When you accept this Policy when you register with your Personal Data, or if
|
||||
you start to use our Products and does not expressly object to the contents
|
||||
of this Policy, we will consider that you fully understand and agree with
|
||||
this Policy. If you have any questions regarding this Policy, please do not
|
||||
hesitate to contact us via:
|
||||
</p>
|
||||
<p>
|
||||
For other branded mobile applications powered by Syncrow, our Clients
|
||||
control all the Personal Data collected through our Products. We collect the
|
||||
information under the direction of our Clients and the processing of such
|
||||
information.
|
||||
</p>
|
||||
</div>
|
||||
@ -18,4 +18,5 @@ export enum ProductType {
|
||||
PC = 'PC',
|
||||
FOUR_S = '4S',
|
||||
SIX_S = '6S',
|
||||
SOS = 'SOS',
|
||||
}
|
||||
|
||||
165
libs/common/src/constants/role-permissions.ts
Normal file
165
libs/common/src/constants/role-permissions.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { RoleType } from './role.type.enum';
|
||||
|
||||
export const RolePermissions = {
|
||||
[RoleType.SUPER_ADMIN]: [
|
||||
'DEVICE_SINGLE_CONTROL',
|
||||
'DEVICE_VIEW',
|
||||
'DEVICE_DELETE',
|
||||
'DEVICE_UPDATE',
|
||||
'DEVICE_BATCH_CONTROL',
|
||||
'DEVICE_LOCATION_VIEW',
|
||||
'DEVICE_LOCATION_UPDATE',
|
||||
'COMMUNITY_VIEW',
|
||||
'COMMUNITY_ADD',
|
||||
'COMMUNITY_UPDATE',
|
||||
'COMMUNITY_DELETE',
|
||||
'FIRMWARE_CONTROL',
|
||||
'FIRMWARE_VIEW',
|
||||
'SPACE_VIEW',
|
||||
'SPACE_ADD',
|
||||
'SPACE_UPDATE',
|
||||
'SPACE_DELETE',
|
||||
'SPACE_MODEL_ADD',
|
||||
'SPACE_MODEL_VIEW',
|
||||
'SPACE_MODEL_UPDATE',
|
||||
'SPACE_MODEL_DELETE',
|
||||
'SPACE_ASSIGN_USER_TO_SPACE',
|
||||
'SPACE_DELETE_USER_FROM_SPACE',
|
||||
'SUBSPACE_VIEW',
|
||||
'SUBSPACE_ADD',
|
||||
'SUBSPACE_UPDATE',
|
||||
'SUBSPACE_DELETE',
|
||||
'SUBSPACE_ASSIGN_DEVICE_TO_SUBSPACE',
|
||||
'SUBSPACE_DELETE_DEVICE_FROM_SUBSPACE',
|
||||
'DEVICE_WIZARD_VIEW_DEVICE_WIZARD',
|
||||
'SUBSPACE_DEVICE_VIEW_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_VIEW_DEVICE_IN_SPACE',
|
||||
'SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE',
|
||||
'AUTOMATION_VIEW',
|
||||
'AUTOMATION_ADD',
|
||||
'AUTOMATION_UPDATE',
|
||||
'AUTOMATION_DELETE',
|
||||
'AUTOMATION_CONTROL',
|
||||
'SCENES_VIEW',
|
||||
'SCENES_ADD',
|
||||
'SCENES_UPDATE',
|
||||
'SCENES_DELETE',
|
||||
'SCENES_CONTROL',
|
||||
'VISITOR_PASSWORD_VIEW',
|
||||
'VISITOR_PASSWORD_ADD',
|
||||
'VISITOR_PASSWORD_UPDATE',
|
||||
'VISITOR_PASSWORD_DELETE',
|
||||
'USER_ADD',
|
||||
'SPACE_MEMBER_ADD',
|
||||
],
|
||||
[RoleType.ADMIN]: [
|
||||
'DEVICE_SINGLE_CONTROL',
|
||||
'DEVICE_VIEW',
|
||||
'DEVICE_DELETE',
|
||||
'DEVICE_UPDATE',
|
||||
'DEVICE_BATCH_CONTROL',
|
||||
'DEVICE_LOCATION_VIEW',
|
||||
'DEVICE_LOCATION_UPDATE',
|
||||
'COMMUNITY_VIEW',
|
||||
'COMMUNITY_ADD',
|
||||
'COMMUNITY_UPDATE',
|
||||
'COMMUNITY_DELETE',
|
||||
'FIRMWARE_CONTROL',
|
||||
'FIRMWARE_VIEW',
|
||||
'SPACE_VIEW',
|
||||
'SPACE_ADD',
|
||||
'SPACE_UPDATE',
|
||||
'SPACE_DELETE',
|
||||
'SPACE_MODEL_ADD',
|
||||
'SPACE_MODEL_VIEW',
|
||||
'SPACE_MODEL_UPDATE',
|
||||
'SPACE_MODEL_DELETE',
|
||||
'SPACE_ASSIGN_USER_TO_SPACE',
|
||||
'SPACE_DELETE_USER_FROM_SPACE',
|
||||
'SUBSPACE_VIEW',
|
||||
'SUBSPACE_ADD',
|
||||
'SUBSPACE_UPDATE',
|
||||
'SUBSPACE_DELETE',
|
||||
'SUBSPACE_ASSIGN_DEVICE_TO_SUBSPACE',
|
||||
'SUBSPACE_DELETE_DEVICE_FROM_SUBSPACE',
|
||||
'DEVICE_WIZARD_VIEW_DEVICE_WIZARD',
|
||||
'SUBSPACE_DEVICE_VIEW_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_VIEW_DEVICE_IN_SPACE',
|
||||
'SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE',
|
||||
'AUTOMATION_VIEW',
|
||||
'AUTOMATION_ADD',
|
||||
'AUTOMATION_UPDATE',
|
||||
'AUTOMATION_DELETE',
|
||||
'AUTOMATION_CONTROL',
|
||||
'SCENES_VIEW',
|
||||
'SCENES_ADD',
|
||||
'SCENES_UPDATE',
|
||||
'SCENES_DELETE',
|
||||
'SCENES_CONTROL',
|
||||
'VISITOR_PASSWORD_VIEW',
|
||||
'VISITOR_PASSWORD_ADD',
|
||||
'VISITOR_PASSWORD_UPDATE',
|
||||
'VISITOR_PASSWORD_DELETE',
|
||||
'USER_ADD',
|
||||
'SPACE_MEMBER_ADD',
|
||||
],
|
||||
[RoleType.SPACE_MEMBER]: [
|
||||
'DEVICE_SINGLE_CONTROL',
|
||||
'DEVICE_VIEW',
|
||||
'SPACE_VIEW',
|
||||
'SUBSPACE_VIEW',
|
||||
'DEVICE_WIZARD_VIEW_DEVICE_WIZARD',
|
||||
'SUBSPACE_DEVICE_VIEW_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_VIEW_DEVICE_IN_SPACE',
|
||||
'AUTOMATION_VIEW',
|
||||
'AUTOMATION_CONTROL',
|
||||
'SCENES_VIEW',
|
||||
'SCENES_CONTROL',
|
||||
],
|
||||
[RoleType.SPACE_OWNER]: [
|
||||
'DEVICE_SINGLE_CONTROL',
|
||||
'DEVICE_VIEW',
|
||||
'DEVICE_DELETE',
|
||||
'DEVICE_UPDATE',
|
||||
'DEVICE_BATCH_CONTROL',
|
||||
'DEVICE_LOCATION_VIEW',
|
||||
'DEVICE_LOCATION_UPDATE',
|
||||
'FIRMWARE_CONTROL',
|
||||
'FIRMWARE_VIEW',
|
||||
'SPACE_VIEW',
|
||||
'SPACE_ADD',
|
||||
'SPACE_UPDATE',
|
||||
'SPACE_DELETE',
|
||||
'SPACE_ASSIGN_USER_TO_SPACE',
|
||||
'SPACE_DELETE_USER_FROM_SPACE',
|
||||
'SUBSPACE_VIEW',
|
||||
'SUBSPACE_ADD',
|
||||
'SUBSPACE_UPDATE',
|
||||
'SUBSPACE_DELETE',
|
||||
'SUBSPACE_ASSIGN_DEVICE_TO_SUBSPACE',
|
||||
'SUBSPACE_DELETE_DEVICE_FROM_SUBSPACE',
|
||||
'DEVICE_WIZARD_VIEW_DEVICE_WIZARD',
|
||||
'SUBSPACE_DEVICE_VIEW_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_VIEW_DEVICE_IN_SPACE',
|
||||
'SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE',
|
||||
'SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE',
|
||||
'AUTOMATION_VIEW',
|
||||
'AUTOMATION_ADD',
|
||||
'AUTOMATION_UPDATE',
|
||||
'AUTOMATION_DELETE',
|
||||
'AUTOMATION_CONTROL',
|
||||
'SCENES_VIEW',
|
||||
'SCENES_ADD',
|
||||
'SCENES_UPDATE',
|
||||
'SCENES_DELETE',
|
||||
'SCENES_CONTROL',
|
||||
'VISITOR_PASSWORD_VIEW',
|
||||
'VISITOR_PASSWORD_ADD',
|
||||
'VISITOR_PASSWORD_UPDATE',
|
||||
'VISITOR_PASSWORD_DELETE',
|
||||
'USER_ADD',
|
||||
'SPACE_MEMBER_ADD',
|
||||
],
|
||||
};
|
||||
@ -1,4 +1,6 @@
|
||||
export enum RoleType {
|
||||
SUPER_ADMIN = 'SUPER_ADMIN',
|
||||
ADMIN = 'ADMIN',
|
||||
SPACE_OWNER = 'SPACE_OWNER',
|
||||
SPACE_MEMBER = 'SPACE_MEMBER',
|
||||
}
|
||||
|
||||
44
libs/common/src/constants/terms-and-conditions.html
Normal file
44
libs/common/src/constants/terms-and-conditions.html
Normal file
@ -0,0 +1,44 @@
|
||||
<div>
|
||||
<p>User Agreement</p>
|
||||
<p>Terms and Conditions</p>
|
||||
<p><span>Last updated:</span> {{lastUpdated}}</p>
|
||||
<p>
|
||||
Please read these Terms and Conditions ("Terms", "Terms and Conditions")
|
||||
carefully before using the
|
||||
<a href="{{websiteUrl}}">{{websiteUrl}}</a> website and the {{mobileApp}}
|
||||
mobile application (the "Service") operated by {{companyName}}.
|
||||
</p>
|
||||
<p>
|
||||
Your access to and use of the Service is conditioned on your acceptance of
|
||||
and compliance with these Terms. These Terms apply to all visitors, users,
|
||||
and others who access or use the Service.
|
||||
</p>
|
||||
<p>Content</p>
|
||||
<p>
|
||||
Our Service allows you to post, link, store, share and otherwise make
|
||||
available certain information, text, graphics, videos, or other material
|
||||
("Content"). You are responsible for the Content you post.
|
||||
</p>
|
||||
<p>Links To Other Websites</p>
|
||||
<p>
|
||||
Our Service may contain links to third-party websites or services that are
|
||||
not owned or controlled by {{companyName}}.
|
||||
</p>
|
||||
<p>
|
||||
{{companyName}} has no control over, and assumes no responsibility for, the
|
||||
content, privacy policies, or practices of any third-party websites or
|
||||
services.
|
||||
</p>
|
||||
<p>Changes</p>
|
||||
<p>
|
||||
We reserve the right, at our sole discretion, to modify or replace these
|
||||
Terms at any time. If a revision is material, we will try to provide at
|
||||
least 30 days' notice prior to any new terms taking effect. What constitutes
|
||||
a material change will be determined at our sole discretion.
|
||||
</p>
|
||||
<p>Contact Us</p>
|
||||
<p>
|
||||
If you have any questions about these Terms, please
|
||||
<a href="mailto:{{contactEmail}}">contact us</a>.
|
||||
</p>
|
||||
</div>
|
||||
7
libs/common/src/constants/terms-condtions.ts
Normal file
7
libs/common/src/constants/terms-condtions.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const termsAndConditionsData = {
|
||||
lastUpdated: '25/01/2025',
|
||||
websiteUrl: 'https://www.Syncrow.ae',
|
||||
mobileApp: 'Syncrow Mobile App',
|
||||
companyName: 'Syncrow',
|
||||
contactEmail: 'contact@Syncrow.ae',
|
||||
};
|
||||
4
libs/common/src/constants/user-status.enum.ts
Normal file
4
libs/common/src/constants/user-status.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum UserStatusEnum {
|
||||
ACTIVE = 'active',
|
||||
INVITED = 'invited',
|
||||
}
|
||||
@ -12,10 +12,10 @@ import {
|
||||
SpaceEntity,
|
||||
SpaceLinkEntity,
|
||||
SubspaceEntity,
|
||||
TagEntity,
|
||||
} from '../modules/space/entities';
|
||||
import { UserSpaceEntity } from '../modules/user/entities';
|
||||
import { DeviceUserPermissionEntity } from '../modules/device/entities';
|
||||
import { UserRoleEntity } from '../modules/user/entities';
|
||||
import { RoleTypeEntity } from '../modules/role-type/entities';
|
||||
import { UserNotificationEntity } from '../modules/user/entities';
|
||||
import { DeviceNotificationEntity } from '../modules/device/entities';
|
||||
@ -26,8 +26,18 @@ import { CommunityEntity } from '../modules/community/entities';
|
||||
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
|
||||
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
|
||||
import { SceneDeviceEntity } from '../modules/scene-device/entities';
|
||||
import { SpaceProductEntity } from '../modules/space/entities/space-product.entity';
|
||||
|
||||
import { ProjectEntity } from '../modules/project/entities';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceModelEntity,
|
||||
TagModel,
|
||||
} from '../modules/space-model/entities';
|
||||
import {
|
||||
InviteUserEntity,
|
||||
InviteUserSpaceEntity,
|
||||
} from '../modules/Invite-user/entities';
|
||||
import { InviteSpaceEntity } from '../modules/space/entities/invite-space.entity';
|
||||
import { AutomationEntity } from '../modules/automation/entities';
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRootAsync({
|
||||
@ -42,6 +52,7 @@ import { SpaceProductEntity } from '../modules/space/entities/space-product.enti
|
||||
password: configService.get('DB_PASSWORD'),
|
||||
database: configService.get('DB_NAME'),
|
||||
entities: [
|
||||
ProjectEntity,
|
||||
UserEntity,
|
||||
UserSessionEntity,
|
||||
UserOtpEntity,
|
||||
@ -53,10 +64,9 @@ import { SpaceProductEntity } from '../modules/space/entities/space-product.enti
|
||||
SpaceEntity,
|
||||
SpaceLinkEntity,
|
||||
SubspaceEntity,
|
||||
SpaceProductEntity,
|
||||
TagEntity,
|
||||
UserSpaceEntity,
|
||||
DeviceUserPermissionEntity,
|
||||
UserRoleEntity,
|
||||
RoleTypeEntity,
|
||||
UserNotificationEntity,
|
||||
DeviceNotificationEntity,
|
||||
@ -67,6 +77,13 @@ import { SpaceProductEntity } from '../modules/space/entities/space-product.enti
|
||||
SceneEntity,
|
||||
SceneIconEntity,
|
||||
SceneDeviceEntity,
|
||||
SpaceModelEntity,
|
||||
SubspaceModelEntity,
|
||||
TagModel,
|
||||
InviteUserEntity,
|
||||
InviteUserSpaceEntity,
|
||||
InviteSpaceEntity,
|
||||
AutomationEntity,
|
||||
],
|
||||
namingStrategy: new SnakeNamingStrategy(),
|
||||
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
|
||||
|
||||
@ -187,19 +187,19 @@ export class DeviceStatusFirebaseService {
|
||||
code,
|
||||
value,
|
||||
}));
|
||||
const newLog = this.deviceStatusLogRepository.create({
|
||||
deviceId: addDeviceStatusDto.deviceUuid,
|
||||
deviceTuyaId: addDeviceStatusDto.deviceTuyaUuid,
|
||||
productId: addDeviceStatusDto.log.productId,
|
||||
log: addDeviceStatusDto.log,
|
||||
code: existingData.status[0].code,
|
||||
value: existingData.status[0].value,
|
||||
eventId: addDeviceStatusDto.log.dataId,
|
||||
eventTime: new Date(
|
||||
addDeviceStatusDto.log.properties[0].time,
|
||||
).toISOString(),
|
||||
const newLogs = addDeviceStatusDto.log.properties.map((property) => {
|
||||
return this.deviceStatusLogRepository.create({
|
||||
deviceId: addDeviceStatusDto.deviceUuid,
|
||||
deviceTuyaId: addDeviceStatusDto.deviceTuyaUuid,
|
||||
productId: addDeviceStatusDto.log.productId,
|
||||
log: addDeviceStatusDto.log,
|
||||
code: property.code,
|
||||
value: property.value,
|
||||
eventId: addDeviceStatusDto.log.dataId,
|
||||
eventTime: new Date(property.time).toISOString(),
|
||||
});
|
||||
});
|
||||
await this.deviceStatusLogRepository.save(newLog);
|
||||
await this.deviceStatusLogRepository.save(newLogs);
|
||||
// Save the updated data to Firebase
|
||||
await set(dataRef, existingData);
|
||||
|
||||
|
||||
12
libs/common/src/helper/removeCircularReferences.ts
Normal file
12
libs/common/src/helper/removeCircularReferences.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export function removeCircularReferences() {
|
||||
const seen = new WeakSet();
|
||||
return (key: string, value: any) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return undefined; // Skip circular reference
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {
|
||||
ConvertedAction,
|
||||
TuyaResponseInterface,
|
||||
} from '../interfaces';
|
||||
import { GetDeviceDetailsFunctionsStatusInterface } from 'src/device/interfaces/get.device.interface';
|
||||
|
||||
@Injectable()
|
||||
export class TuyaService {
|
||||
@ -284,4 +285,24 @@ export class TuyaService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async getDevicesInstructionStatusTuya(
|
||||
deviceUuid: string,
|
||||
): Promise<GetDeviceDetailsFunctionsStatusInterface> {
|
||||
try {
|
||||
const path = `/v1.0/iot-03/devices/status`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'GET',
|
||||
path,
|
||||
query: {
|
||||
device_ids: deviceUuid,
|
||||
},
|
||||
});
|
||||
return response as GetDeviceDetailsFunctionsStatusInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error fetching device functions status from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { FindManyOptions, Repository } from 'typeorm';
|
||||
import { FindManyOptions, Repository, SelectQueryBuilder } from 'typeorm';
|
||||
import { InternalServerErrorException } from '@nestjs/common';
|
||||
import { BaseResponseDto } from '../dto/base.response.dto';
|
||||
import { PageResponseDto } from '../dto/pagination.response.dto';
|
||||
@ -31,7 +31,7 @@ interface FindAllQueryWithDefaults extends CustomFindAllQuery {
|
||||
function getDefaultQueryOptions(
|
||||
query: Partial<TypeORMCustomModelFindAllQuery>,
|
||||
): FindManyOptions & FindAllQueryWithDefaults {
|
||||
const { page, size, includeDisable, modelName, ...rest } = query;
|
||||
const { page, size, includeDisable, include, modelName, ...rest } = query;
|
||||
|
||||
// Set default if undefined or null
|
||||
const returnPage = page ? Number(page) : 1;
|
||||
@ -48,7 +48,9 @@ function getDefaultQueryOptions(
|
||||
},
|
||||
page: returnPage,
|
||||
size: returnSize,
|
||||
include: include || undefined,
|
||||
includeDisable: returnIncludeDisable,
|
||||
|
||||
modelName: modelName || query.modelName, // Ensure modelName is passed through
|
||||
};
|
||||
}
|
||||
@ -68,8 +70,8 @@ export function TypeORMCustomModel(repository: Repository<any>) {
|
||||
return Object.assign(repository, {
|
||||
findAll: async function (
|
||||
query: Partial<TypeORMCustomModelFindAllQuery>,
|
||||
customQueryBuilder?: SelectQueryBuilder<any>,
|
||||
): Promise<TypeORMCustomModelFindAllResponse> {
|
||||
// Extract values from the query
|
||||
const {
|
||||
page = 1,
|
||||
size = 10,
|
||||
@ -80,12 +82,7 @@ export function TypeORMCustomModel(repository: Repository<any>) {
|
||||
select,
|
||||
} = getDefaultQueryOptions(query);
|
||||
|
||||
// Ensure modelName is set before proceeding
|
||||
if (!modelName) {
|
||||
console.error(
|
||||
'modelName is missing after getDefaultQueryOptions:',
|
||||
query,
|
||||
);
|
||||
throw new InternalServerErrorException(
|
||||
`[TypeORMCustomModel] Cannot findAll with unknown modelName`,
|
||||
);
|
||||
@ -94,20 +91,44 @@ export function TypeORMCustomModel(repository: Repository<any>) {
|
||||
const skip = (page - 1) * size;
|
||||
const order = buildTypeORMSortQuery(sort);
|
||||
const relations = buildTypeORMIncludeQuery(modelName, include);
|
||||
|
||||
// Use the where clause directly, without wrapping it under 'where'
|
||||
const whereClause = buildTypeORMWhereClause({ where });
|
||||
console.log('Final where clause:', whereClause);
|
||||
|
||||
// Ensure the whereClause is passed directly to findAndCount
|
||||
const [data, count] = await repository.findAndCount({
|
||||
where: whereClause,
|
||||
take: size,
|
||||
skip: skip,
|
||||
order: order,
|
||||
select: select,
|
||||
relations: relations,
|
||||
});
|
||||
let data: any[] = [];
|
||||
let count = 0;
|
||||
|
||||
if (customQueryBuilder) {
|
||||
const qb = customQueryBuilder.skip(skip).take(size);
|
||||
|
||||
if (order) {
|
||||
Object.keys(order).forEach((key) => {
|
||||
qb.addOrderBy(key, order[key]);
|
||||
});
|
||||
}
|
||||
|
||||
if (whereClause) {
|
||||
qb.andWhere(whereClause); // Use .andWhere instead of .where to avoid overwriting conditions
|
||||
}
|
||||
|
||||
if (select) {
|
||||
const selectColumns = Array.isArray(select)
|
||||
? select
|
||||
: Object.keys(select).map(
|
||||
(key) => `${customQueryBuilder.alias}.${key}`,
|
||||
);
|
||||
qb.select(selectColumns as string[]);
|
||||
}
|
||||
|
||||
[data, count] = await qb.getManyAndCount();
|
||||
} else {
|
||||
[data, count] = await repository.findAndCount({
|
||||
where: whereClause,
|
||||
take: size,
|
||||
skip: skip,
|
||||
order: order,
|
||||
select: select,
|
||||
relations: relations,
|
||||
});
|
||||
}
|
||||
|
||||
const paginationResponseDto = getPaginationResponseDto(count, page, size);
|
||||
const baseResponseDto: BaseResponseDto = {
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { InviteUserEntity, InviteUserSpaceEntity } from './entities';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([InviteUserEntity, InviteUserSpaceEntity]),
|
||||
],
|
||||
})
|
||||
export class InviteUserRepositoryModule {}
|
||||
50
libs/common/src/modules/Invite-user/dtos/Invite-user.dto.ts
Normal file
50
libs/common/src/modules/Invite-user/dtos/Invite-user.dto.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||
import { UserStatusEnum } from '@app/common/constants/user-status.enum';
|
||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class InviteUserDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public email: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public jobTitle: string;
|
||||
|
||||
@IsEnum(UserStatusEnum)
|
||||
@IsNotEmpty()
|
||||
public status: UserStatusEnum;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public firstName: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public lastName: string;
|
||||
|
||||
@IsEnum(RoleType)
|
||||
@IsNotEmpty()
|
||||
public invitedBy: RoleType;
|
||||
}
|
||||
export class InviteUserSpaceDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public inviteUserUuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public spaceUuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public invitationCode: string;
|
||||
}
|
||||
1
libs/common/src/modules/Invite-user/dtos/index.ts
Normal file
1
libs/common/src/modules/Invite-user/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Invite-user.dto';
|
||||
@ -0,0 +1,126 @@
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { RoleTypeEntity } from '../../role-type/entities';
|
||||
import { UserStatusEnum } from '@app/common/constants/user-status.enum';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||
import { InviteUserDto, InviteUserSpaceDto } from '../dtos';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
|
||||
@Entity({ name: 'invite-user' })
|
||||
@Unique(['email', 'project'])
|
||||
export class InviteUserEntity extends AbstractEntity<InviteUserDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
email: string;
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
jobTitle: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
enum: Object.values(UserStatusEnum),
|
||||
})
|
||||
status: string;
|
||||
|
||||
@Column()
|
||||
public firstName: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public lastName: string;
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
public phoneNumber: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: true,
|
||||
})
|
||||
public isActive: boolean;
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: true,
|
||||
})
|
||||
public isEnabled: boolean;
|
||||
@Column({
|
||||
nullable: false,
|
||||
unique: true,
|
||||
})
|
||||
public invitationCode: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
enum: Object.values(RoleType),
|
||||
})
|
||||
public invitedBy: string;
|
||||
|
||||
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.invitedUsers, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
public roleType: RoleTypeEntity;
|
||||
@OneToOne(() => UserEntity, (user) => user.inviteUser, { nullable: true })
|
||||
@JoinColumn({ name: 'user_uuid' })
|
||||
user: UserEntity;
|
||||
@OneToMany(
|
||||
() => InviteUserSpaceEntity,
|
||||
(inviteUserSpace) => inviteUserSpace.inviteUser,
|
||||
)
|
||||
spaces: InviteUserSpaceEntity[];
|
||||
|
||||
@ManyToOne(() => ProjectEntity, (project) => project.invitedUsers, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'project_uuid' })
|
||||
public project: ProjectEntity;
|
||||
|
||||
constructor(partial: Partial<InviteUserEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
@Entity({ name: 'invite-user-space' })
|
||||
@Unique(['inviteUser', 'space'])
|
||||
export class InviteUserSpaceEntity extends AbstractEntity<InviteUserSpaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@ManyToOne(() => InviteUserEntity, (inviteUser) => inviteUser.spaces)
|
||||
@JoinColumn({ name: 'invite_user_uuid' })
|
||||
public inviteUser: InviteUserEntity;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.invitedUsers)
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
public space: SpaceEntity;
|
||||
constructor(partial: Partial<InviteUserSpaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
1
libs/common/src/modules/Invite-user/entities/index.ts
Normal file
1
libs/common/src/modules/Invite-user/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Invite-user.entity';
|
||||
1
libs/common/src/modules/Invite-user/index.ts
Normal file
1
libs/common/src/modules/Invite-user/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Invite-user.repository.module';
|
||||
@ -0,0 +1 @@
|
||||
export * from './invite-user.repository';
|
||||
@ -0,0 +1,16 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InviteUserEntity, InviteUserSpaceEntity } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class InviteUserRepository extends Repository<InviteUserEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(InviteUserEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@Injectable()
|
||||
export class InviteUserSpaceRepository extends Repository<InviteUserSpaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(InviteUserSpaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AutomationEntity } from './entities';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([AutomationEntity])],
|
||||
})
|
||||
export class AutomationRepositoryModule {}
|
||||
14
libs/common/src/modules/automation/dtos/automation.dto.ts
Normal file
14
libs/common/src/modules/automation/dtos/automation.dto.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class AutomationDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public automationTuyaUuid: string;
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public spaceUuid: string;
|
||||
}
|
||||
1
libs/common/src/modules/automation/dtos/index.ts
Normal file
1
libs/common/src/modules/automation/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './automation.dto';
|
||||
@ -0,0 +1,37 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { AutomationDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
|
||||
@Entity({ name: 'automation' })
|
||||
export class AutomationEntity extends AbstractEntity<AutomationDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
automationTuyaUuid: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.scenes, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
constructor(partial: Partial<AutomationEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
1
libs/common/src/modules/automation/entities/index.ts
Normal file
1
libs/common/src/modules/automation/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './automation.entity';
|
||||
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AutomationEntity } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class AutomationRepository extends Repository<AutomationEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(AutomationEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
1
libs/common/src/modules/automation/repositories/index.ts
Normal file
1
libs/common/src/modules/automation/repositories/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './automation.repository';
|
||||
@ -1,7 +1,8 @@
|
||||
import { Column, Entity, OneToMany, Unique } from 'typeorm';
|
||||
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { CommunityDto } from '../dtos';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
|
||||
@Entity({ name: 'community' })
|
||||
@Unique(['name'])
|
||||
@ -31,4 +32,9 @@ export class CommunityEntity extends AbstractEntity<CommunityDto> {
|
||||
nullable: true,
|
||||
})
|
||||
externalId: string;
|
||||
|
||||
@ManyToOne(() => ProjectEntity, (project) => project.communities, {
|
||||
nullable: false,
|
||||
})
|
||||
project: ProjectEntity;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ export class DeviceStatusLogEntity {
|
||||
})
|
||||
eventFrom: SourceType;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
@Column({ type: 'uuid' })
|
||||
deviceId: string;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
|
||||
@ -6,10 +6,11 @@ import {
|
||||
Unique,
|
||||
Index,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
} from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto';
|
||||
import { SpaceEntity, SubspaceEntity } from '../../space/entities';
|
||||
import { SpaceEntity, SubspaceEntity, TagEntity } from '../../space/entities';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
import { DeviceNotificationDto } from '../dtos';
|
||||
@ -74,6 +75,11 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
||||
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
|
||||
sceneDevices: SceneDeviceEntity[];
|
||||
|
||||
@OneToOne(() => TagEntity, (tag) => tag.device, {
|
||||
nullable: true,
|
||||
})
|
||||
tag: TagEntity;
|
||||
|
||||
constructor(partial: Partial<DeviceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
@ -102,6 +108,7 @@ export class DeviceNotificationEntity extends AbstractEntity<DeviceNotificationD
|
||||
nullable: false,
|
||||
})
|
||||
user: UserEntity;
|
||||
|
||||
constructor(partial: Partial<DeviceNotificationEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
||||
@ -2,8 +2,8 @@ import { Column, Entity, OneToMany } from 'typeorm';
|
||||
import { ProductDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { SpaceProductEntity } from '../../space/entities/space-product.entity';
|
||||
|
||||
import { TagModel } from '../../space-model';
|
||||
import { TagEntity } from '../../space/entities/tag.entity';
|
||||
@Entity({ name: 'product' })
|
||||
export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||
@Column({
|
||||
@ -27,8 +27,11 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||
})
|
||||
public prodType: string;
|
||||
|
||||
@OneToMany(() => SpaceProductEntity, (spaceProduct) => spaceProduct.product)
|
||||
spaceProducts: SpaceProductEntity[];
|
||||
@OneToMany(() => TagModel, (tag) => tag.product)
|
||||
tagModels: TagModel[];
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.product)
|
||||
tags: TagEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => DeviceEntity,
|
||||
|
||||
1
libs/common/src/modules/project/dtos/index.ts
Normal file
1
libs/common/src/modules/project/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './project.dto';
|
||||
15
libs/common/src/modules/project/dtos/project.dto.ts
Normal file
15
libs/common/src/modules/project/dtos/project.dto.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class ProjectDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public description?: string;
|
||||
}
|
||||
1
libs/common/src/modules/project/entities/index.ts
Normal file
1
libs/common/src/modules/project/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './project.entity';
|
||||
43
libs/common/src/modules/project/entities/project.entity.ts
Normal file
43
libs/common/src/modules/project/entities/project.entity.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Entity, Column, Unique, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ProjectDto } from '../dtos';
|
||||
import { CommunityEntity } from '../../community/entities';
|
||||
import { SpaceModelEntity } from '../../space-model';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
import { InviteUserEntity } from '../../Invite-user/entities';
|
||||
|
||||
@Entity({ name: 'project' })
|
||||
@Unique(['name'])
|
||||
export class ProjectEntity extends AbstractEntity<ProjectDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public name: string;
|
||||
|
||||
@Column({ length: 255, nullable: true })
|
||||
description: string;
|
||||
|
||||
@OneToMany(() => SpaceModelEntity, (spaceModel) => spaceModel.project)
|
||||
public spaceModels: SpaceModelEntity[];
|
||||
|
||||
@OneToMany(() => CommunityEntity, (community) => community.project)
|
||||
communities: CommunityEntity[];
|
||||
|
||||
@OneToMany(() => UserEntity, (user) => user.project)
|
||||
public users: UserEntity[];
|
||||
|
||||
@OneToMany(() => InviteUserEntity, (inviteUser) => inviteUser.project)
|
||||
public invitedUsers: InviteUserEntity[];
|
||||
|
||||
constructor(partial: Partial<ProjectEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
1
libs/common/src/modules/project/index.ts
Normal file
1
libs/common/src/modules/project/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './project.repository.module';
|
||||
11
libs/common/src/modules/project/project.repository.module.ts
Normal file
11
libs/common/src/modules/project/project.repository.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ProjectEntity } from './entities';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([ProjectEntity])],
|
||||
})
|
||||
export class ProjectRepositoryModule {}
|
||||
1
libs/common/src/modules/project/repositiories/index.ts
Normal file
1
libs/common/src/modules/project/repositiories/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './project.repository';
|
||||
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { ProjectEntity } from '../entities';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ProjectRepository extends Repository<ProjectEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(ProjectEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,8 @@ import { Column, Entity, OneToMany, Unique } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { RoleTypeDto } from '../dtos/role.type.dto';
|
||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||
import { UserRoleEntity } from '../../user/entities';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
import { InviteUserEntity } from '../../Invite-user/entities';
|
||||
|
||||
@Entity({ name: 'role-type' })
|
||||
@Unique(['type'])
|
||||
@ -12,10 +13,14 @@ export class RoleTypeEntity extends AbstractEntity<RoleTypeDto> {
|
||||
enum: Object.values(RoleType),
|
||||
})
|
||||
type: string;
|
||||
@OneToMany(() => UserRoleEntity, (role) => role.roleType, {
|
||||
@OneToMany(() => UserEntity, (inviteUser) => inviteUser.roleType, {
|
||||
nullable: true,
|
||||
})
|
||||
roles: UserRoleEntity[];
|
||||
users: UserEntity[];
|
||||
@OneToMany(() => InviteUserEntity, (inviteUser) => inviteUser.roleType, {
|
||||
nullable: true,
|
||||
})
|
||||
invitedUsers: InviteUserEntity[];
|
||||
constructor(partial: Partial<RoleTypeEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
||||
@ -44,6 +44,12 @@ export class SceneDeviceEntity extends AbstractEntity<SceneDeviceDto> {
|
||||
@JoinColumn({ name: 'scene_uuid' })
|
||||
scene: SceneEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
constructor(partial: Partial<SceneDeviceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
||||
@ -59,6 +59,12 @@ export class SceneEntity extends AbstractEntity<SceneDto> {
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@ManyToOne(() => SceneIconEntity, (icon) => icon.scenesIconEntity, {
|
||||
nullable: false,
|
||||
})
|
||||
|
||||
2
libs/common/src/modules/space-model/dtos/index.ts
Normal file
2
libs/common/src/modules/space-model/dtos/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './subspace-model';
|
||||
export * from './space-model.dto';
|
||||
15
libs/common/src/modules/space-model/dtos/space-model.dto.ts
Normal file
15
libs/common/src/modules/space-model/dtos/space-model.dto.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { IsString, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class SpaceModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public spaceModelName: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
projectUuid: string;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export * from './subspace-model.dto';
|
||||
@ -0,0 +1,15 @@
|
||||
import { IsString, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class SubSpaceModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public subSpaceModelName: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
spaceModelUuid: string;
|
||||
}
|
||||
21
libs/common/src/modules/space-model/dtos/tag-model.dto.ts
Normal file
21
libs/common/src/modules/space-model/dtos/tag-model.dto.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class TagModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public name: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public productUuid: string;
|
||||
|
||||
@IsString()
|
||||
spaceModelUuid: string;
|
||||
|
||||
@IsString()
|
||||
subspaceModelUuid: string;
|
||||
}
|
||||
3
libs/common/src/modules/space-model/entities/index.ts
Normal file
3
libs/common/src/modules/space-model/entities/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './space-model.entity';
|
||||
export * from './subspace-model';
|
||||
export * from './tag-model.entity';
|
||||
@ -0,0 +1,58 @@
|
||||
import { Entity, Column, OneToMany, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceModelDto } from '../dtos';
|
||||
import { SubspaceModelEntity } from './subspace-model';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
import { TagModel } from './tag-model.entity';
|
||||
|
||||
@Entity({ name: 'space-model' })
|
||||
export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public modelName: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@ManyToOne(() => ProjectEntity, (project) => project.spaceModels, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'project_uuid' })
|
||||
public project: ProjectEntity;
|
||||
|
||||
@OneToMany(
|
||||
() => SubspaceModelEntity,
|
||||
(subspaceModel) => subspaceModel.spaceModel,
|
||||
{
|
||||
cascade: true,
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public subspaceModels: SubspaceModelEntity[];
|
||||
|
||||
@OneToMany(() => SpaceEntity, (space) => space.spaceModel, {
|
||||
cascade: true,
|
||||
})
|
||||
public spaces: SpaceEntity[];
|
||||
|
||||
@OneToMany(() => TagModel, (tag) => tag.spaceModel)
|
||||
tags: TagModel[];
|
||||
|
||||
constructor(partial: Partial<SpaceModelEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
export * from './subspace-model.entity';
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||
import { SubSpaceModelDto } from '../../dtos';
|
||||
import { SpaceModelEntity } from '../space-model.entity';
|
||||
import { SubspaceEntity } from '@app/common/modules/space/entities';
|
||||
import { TagModel } from '../tag-model.entity';
|
||||
|
||||
@Entity({ name: 'subspace-model' })
|
||||
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceModelEntity,
|
||||
(spaceModel) => spaceModel.subspaceModels,
|
||||
{
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
)
|
||||
public spaceModel: SpaceModelEntity;
|
||||
|
||||
@OneToMany(() => SubspaceEntity, (subspace) => subspace.subSpaceModel, {
|
||||
cascade: true,
|
||||
})
|
||||
public subspaceModel: SubspaceEntity[];
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@OneToMany(() => TagModel, (tag) => tag.subspaceModel)
|
||||
tags: TagModel[];
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { TagModelDto } from '../dtos/tag-model.dto';
|
||||
import { SpaceModelEntity } from './space-model.entity';
|
||||
import { SubspaceModelEntity } from './subspace-model';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
import { TagEntity } from '../../space/entities/tag.entity';
|
||||
|
||||
@Entity({ name: 'tag_model' })
|
||||
export class TagModel extends AbstractEntity<TagModelDto> {
|
||||
@Column({ type: 'varchar', length: 255 })
|
||||
tag: string;
|
||||
|
||||
@ManyToOne(() => ProductEntity, (product) => product.tagModels, {
|
||||
nullable: false,
|
||||
})
|
||||
@JoinColumn({ name: 'product_id' })
|
||||
product: ProductEntity;
|
||||
|
||||
@ManyToOne(() => SpaceModelEntity, (space) => space.tags, { nullable: true })
|
||||
@JoinColumn({ name: 'space_model_id' })
|
||||
spaceModel: SpaceModelEntity;
|
||||
|
||||
@ManyToOne(() => SubspaceModelEntity, (subspace) => subspace.tags, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'subspace_model_id' })
|
||||
subspaceModel: SubspaceModelEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.model)
|
||||
tags: TagEntity[];
|
||||
}
|
||||
3
libs/common/src/modules/space-model/index.ts
Normal file
3
libs/common/src/modules/space-model/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './space-model.repository.module';
|
||||
export * from './entities';
|
||||
export * from './repositories';
|
||||
@ -0,0 +1 @@
|
||||
export * from './space-model.repository';
|
||||
@ -0,0 +1,23 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SpaceModelEntity, SubspaceModelEntity, TagModel } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceModelRepository extends Repository<SpaceModelEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SpaceModelEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@Injectable()
|
||||
export class SubspaceModelRepository extends Repository<SubspaceModelEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceModelEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class TagModelRepository extends Repository<TagModel> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(TagModel, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SpaceModelEntity, SubspaceModelEntity, TagModel } from './entities';
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([SpaceModelEntity, SubspaceModelEntity, TagModel]),
|
||||
],
|
||||
})
|
||||
export class SpaceModelRepositoryModule {}
|
||||
@ -1,2 +1,3 @@
|
||||
export * from './space.dto';
|
||||
export * from './subspace.dto';
|
||||
export * from './tag.dto';
|
||||
|
||||
21
libs/common/src/modules/space/dtos/tag.dto.ts
Normal file
21
libs/common/src/modules/space/dtos/tag.dto.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class TagDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public name: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public productUuid: string;
|
||||
|
||||
@IsString()
|
||||
spaceUuid: string;
|
||||
|
||||
@IsString()
|
||||
subspaceUuid: string;
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './space.entity';
|
||||
export * from './subspace.entity';
|
||||
export * from './subspace';
|
||||
export * from './space-link.entity';
|
||||
export * from './tag.entity';
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||
import { UserSpaceDto } from '../../user/dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
|
||||
@Entity({ name: 'invite-space' })
|
||||
@Unique(['invitationCode'])
|
||||
export class InviteSpaceEntity extends AbstractEntity<UserSpaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()', // Use gen_random_uuid() for default value
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.userSpaces, {
|
||||
nullable: false,
|
||||
})
|
||||
space: SpaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
public invitationCode: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: true,
|
||||
})
|
||||
public isActive: boolean;
|
||||
constructor(partial: Partial<InviteSpaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,12 @@ export class SpaceLinkEntity extends AbstractEntity {
|
||||
@JoinColumn({ name: 'end_space_id' })
|
||||
public endSpace: SpaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
enum: Object.values(Direction),
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
import { Column, Entity, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
|
||||
@Entity({ name: 'space-product' })
|
||||
export class SpaceProductEntity extends AbstractEntity<SpaceProductEntity> {
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.spaceProducts, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@ManyToOne(() => ProductEntity, (product) => product.spaceProducts, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'product_uuid' })
|
||||
product: ProductEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: 'int',
|
||||
})
|
||||
productCount: number;
|
||||
|
||||
constructor(partial: Partial<SpaceProductEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,17 @@
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SpaceDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { UserSpaceEntity } from '../../user/entities';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { CommunityEntity } from '../../community/entities';
|
||||
import { SubspaceEntity } from './subspace.entity';
|
||||
import { SubspaceEntity } from './subspace';
|
||||
import { SpaceLinkEntity } from './space-link.entity';
|
||||
import { SpaceProductEntity } from './space-product.entity';
|
||||
import { SceneEntity } from '../../scene/entities';
|
||||
import { SpaceModelEntity } from '../../space-model';
|
||||
import { InviteUserSpaceEntity } from '../../Invite-user/entities';
|
||||
import { TagEntity } from './tag.entity';
|
||||
|
||||
@Entity({ name: 'space' })
|
||||
@Unique(['invitationCode'])
|
||||
export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
@ -42,10 +36,6 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||
@JoinColumn({ name: 'community_id' })
|
||||
community: CommunityEntity;
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
public invitationCode: string;
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.children, { nullable: true })
|
||||
parent: SpaceEntity;
|
||||
|
||||
@ -58,6 +48,12 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.space)
|
||||
userSpaces: UserSpaceEntity[];
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@OneToMany(() => SubspaceEntity, (subspace) => subspace.space, {
|
||||
nullable: true,
|
||||
})
|
||||
@ -92,12 +88,23 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||
})
|
||||
public icon: string;
|
||||
|
||||
@OneToMany(() => SpaceProductEntity, (spaceProduct) => spaceProduct.space)
|
||||
spaceProducts: SpaceProductEntity[];
|
||||
|
||||
@OneToMany(() => SceneEntity, (scene) => scene.space)
|
||||
scenes: SceneEntity[];
|
||||
|
||||
@ManyToOne(() => SpaceModelEntity, (spaceModel) => spaceModel.spaces, {
|
||||
nullable: true,
|
||||
})
|
||||
spaceModel?: SpaceModelEntity;
|
||||
|
||||
@OneToMany(
|
||||
() => InviteUserSpaceEntity,
|
||||
(inviteUserSpace) => inviteUserSpace.space,
|
||||
)
|
||||
invitedUsers: InviteUserSpaceEntity[];
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.space)
|
||||
tags: TagEntity[];
|
||||
|
||||
constructor(partial: Partial<SpaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
import { SubspaceDto } from '../dtos';
|
||||
|
||||
@Entity({ name: 'subspace' })
|
||||
export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.subspaces, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'space_id' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@OneToMany(() => DeviceEntity, (device) => device.subspace, {
|
||||
nullable: true,
|
||||
})
|
||||
devices: DeviceEntity[];
|
||||
|
||||
constructor(partial: Partial<SubspaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
1
libs/common/src/modules/space/entities/subspace/index.ts
Normal file
1
libs/common/src/modules/space/entities/subspace/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './subspace.entity';
|
||||
@ -0,0 +1,52 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||
import { SubspaceModelEntity } from '@app/common/modules/space-model';
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SubspaceDto } from '../../dtos';
|
||||
import { SpaceEntity } from '../space.entity';
|
||||
import { TagEntity } from '../tag.entity';
|
||||
|
||||
@Entity({ name: 'subspace' })
|
||||
export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.subspaces, {
|
||||
nullable: false,
|
||||
})
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@OneToMany(() => DeviceEntity, (device) => device.subspace, {
|
||||
nullable: true,
|
||||
})
|
||||
devices: DeviceEntity[];
|
||||
|
||||
@ManyToOne(() => SubspaceModelEntity, (subspace) => subspace.subspaceModel, {
|
||||
nullable: true,
|
||||
})
|
||||
subSpaceModel?: SubspaceModelEntity;
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.subspace)
|
||||
tags: TagEntity[];
|
||||
|
||||
constructor(partial: Partial<SubspaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
45
libs/common/src/modules/space/entities/tag.entity.ts
Normal file
45
libs/common/src/modules/space/entities/tag.entity.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { Entity, Column, ManyToOne, JoinColumn, OneToOne } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
import { TagDto } from '../dtos';
|
||||
import { TagModel } from '../../space-model/entities/tag-model.entity';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
import { SubspaceEntity } from './subspace';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
|
||||
@Entity({ name: 'tag' })
|
||||
export class TagEntity extends AbstractEntity<TagDto> {
|
||||
@Column({ type: 'varchar', length: 255 })
|
||||
tag: string;
|
||||
|
||||
@ManyToOne(() => TagModel, (model) => model.tags, {
|
||||
nullable: true,
|
||||
})
|
||||
model: TagModel;
|
||||
|
||||
@ManyToOne(() => ProductEntity, (product) => product.tags, {
|
||||
nullable: false,
|
||||
})
|
||||
product: ProductEntity;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.tags, { nullable: true })
|
||||
space: SpaceEntity;
|
||||
|
||||
@ManyToOne(() => SubspaceEntity, (subspace) => subspace.tags, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'subspace_id' })
|
||||
subspace: SubspaceEntity;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
default: false,
|
||||
})
|
||||
public disabled: boolean;
|
||||
|
||||
@OneToOne(() => DeviceEntity, (device) => device.tag, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'device_id' })
|
||||
device: DeviceEntity;
|
||||
}
|
||||
4
libs/common/src/modules/space/index.ts
Normal file
4
libs/common/src/modules/space/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './dtos';
|
||||
export * from './entities';
|
||||
export * from './repositories';
|
||||
export * from './space.repository.module';
|
||||
@ -1,7 +1,7 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SpaceProductEntity } from '../entities/space-product.entity';
|
||||
import { SpaceEntity, SpaceLinkEntity, SubspaceEntity } from '../entities';
|
||||
import { SpaceEntity, SpaceLinkEntity, TagEntity } from '../entities';
|
||||
import { InviteSpaceEntity } from '../entities/invite-space.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceRepository extends Repository<SpaceEntity> {
|
||||
@ -9,12 +9,6 @@ export class SpaceRepository extends Repository<SpaceEntity> {
|
||||
super(SpaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@Injectable()
|
||||
export class SubspaceRepository extends Repository<SubspaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
|
||||
@ -22,9 +16,17 @@ export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
|
||||
super(SpaceLinkEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductRepository extends Repository<SpaceProductEntity> {
|
||||
export class TagRepository extends Repository<TagEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SpaceProductEntity, dataSource.createEntityManager());
|
||||
super(TagEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class InviteSpaceRepository extends Repository<InviteSpaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(InviteSpaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { SubspaceEntity } from '../entities';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceRepository extends Repository<SubspaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,19 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SpaceEntity, SubspaceEntity } from './entities';
|
||||
import { SpaceEntity, SubspaceEntity, TagEntity } from './entities';
|
||||
import { InviteSpaceEntity } from './entities/invite-space.entity';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([SpaceEntity, SubspaceEntity])],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
SpaceEntity,
|
||||
SubspaceEntity,
|
||||
TagEntity,
|
||||
InviteSpaceEntity,
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class SpaceRepositoryModule {}
|
||||
|
||||
@ -58,20 +58,6 @@ export class UserOtpDto {
|
||||
public expiryTime: string;
|
||||
}
|
||||
|
||||
export class UserRoleDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public userUuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public roleTypeUuid: string;
|
||||
}
|
||||
|
||||
export class UserSpaceDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
|
||||
@ -2,15 +2,16 @@ import {
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import {
|
||||
UserDto,
|
||||
UserNotificationDto,
|
||||
UserOtpDto,
|
||||
UserRoleDto,
|
||||
UserSpaceDto,
|
||||
} from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
@ -26,6 +27,8 @@ import { OtpType } from '../../../../src/constants/otp-type.enum';
|
||||
import { RoleTypeEntity } from '../../role-type/entities';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
import { VisitorPasswordEntity } from '../../visitor-password/entities';
|
||||
import { InviteUserEntity } from '../../Invite-user/entities';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
|
||||
@Entity({ name: 'user' })
|
||||
export class UserEntity extends AbstractEntity<UserDto> {
|
||||
@ -79,6 +82,18 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
})
|
||||
public isActive: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
hasAcceptedWebAgreement: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
hasAcceptedAppAgreement: boolean;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true })
|
||||
webAgreementAcceptedAt: Date;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true })
|
||||
appAgreementAcceptedAt: Date;
|
||||
|
||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user)
|
||||
userSpaces: UserSpaceEntity[];
|
||||
|
||||
@ -100,10 +115,7 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
(deviceUserNotification) => deviceUserNotification.user,
|
||||
)
|
||||
deviceUserNotification: DeviceNotificationEntity[];
|
||||
@OneToMany(() => UserRoleEntity, (role) => role.user, {
|
||||
nullable: true,
|
||||
})
|
||||
roles: UserRoleEntity[];
|
||||
|
||||
@ManyToOne(() => RegionEntity, (region) => region.users, { nullable: true })
|
||||
region: RegionEntity;
|
||||
@ManyToOne(() => TimeZoneEntity, (timezone) => timezone.users, {
|
||||
@ -116,6 +128,21 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
)
|
||||
public visitorPasswords: VisitorPasswordEntity[];
|
||||
|
||||
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.users, {
|
||||
nullable: false,
|
||||
})
|
||||
public roleType: RoleTypeEntity;
|
||||
@OneToOne(() => InviteUserEntity, (inviteUser) => inviteUser.user, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'invite_user_uuid' })
|
||||
inviteUser: InviteUserEntity;
|
||||
|
||||
@ManyToOne(() => ProjectEntity, (project) => project.users, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'project_uuid' })
|
||||
public project: ProjectEntity;
|
||||
constructor(partial: Partial<UserEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
@ -125,7 +152,7 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
@Entity({ name: 'user-notification' })
|
||||
@Unique(['user', 'subscriptionUuid'])
|
||||
export class UserNotificationEntity extends AbstractEntity<UserNotificationDto> {
|
||||
@ManyToOne(() => UserEntity, (user) => user.roles, {
|
||||
@ManyToOne(() => UserEntity, (user) => user.roleType, {
|
||||
nullable: false,
|
||||
})
|
||||
user: UserEntity;
|
||||
@ -178,25 +205,6 @@ export class UserOtpEntity extends AbstractEntity<UserOtpDto> {
|
||||
}
|
||||
}
|
||||
|
||||
@Entity({ name: 'user-role' })
|
||||
@Unique(['user', 'roleType'])
|
||||
export class UserRoleEntity extends AbstractEntity<UserRoleDto> {
|
||||
@ManyToOne(() => UserEntity, (user) => user.roles, {
|
||||
nullable: false,
|
||||
})
|
||||
user: UserEntity;
|
||||
|
||||
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.roles, {
|
||||
nullable: false,
|
||||
})
|
||||
roleType: RoleTypeEntity;
|
||||
|
||||
constructor(partial: Partial<UserRoleEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity({ name: 'user-space' })
|
||||
@Unique(['user', 'space'])
|
||||
export class UserSpaceEntity extends AbstractEntity<UserSpaceDto> {
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
UserEntity,
|
||||
UserNotificationEntity,
|
||||
UserOtpEntity,
|
||||
UserRoleEntity,
|
||||
UserSpaceEntity,
|
||||
} from '../entities/';
|
||||
|
||||
@ -29,13 +28,6 @@ export class UserOtpRepository extends Repository<UserOtpEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UserRoleRepository extends Repository<UserRoleEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(UserRoleEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UserSpaceRepository extends Repository<UserSpaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
UserEntity,
|
||||
UserNotificationEntity,
|
||||
UserOtpEntity,
|
||||
UserRoleEntity,
|
||||
UserSpaceEntity,
|
||||
} from './entities';
|
||||
|
||||
@ -17,7 +16,6 @@ import {
|
||||
UserEntity,
|
||||
UserNotificationEntity,
|
||||
UserOtpEntity,
|
||||
UserRoleEntity,
|
||||
UserSpaceEntity,
|
||||
]),
|
||||
],
|
||||
|
||||
@ -10,7 +10,6 @@ import { RoleTypeSeeder } from './services/role.type.seeder';
|
||||
import { SpaceRepositoryModule } from '../modules/space/space.repository.module';
|
||||
import { SuperAdminSeeder } from './services/supper.admin.seeder';
|
||||
import { UserRepository } from '../modules/user/repositories';
|
||||
import { UserRoleRepository } from '../modules/user/repositories';
|
||||
import { UserRepositoryModule } from '../modules/user/user.repository.module';
|
||||
import { RegionSeeder } from './services/regions.seeder';
|
||||
import { RegionRepository } from '../modules/region/repositories';
|
||||
@ -28,7 +27,6 @@ import { SceneIconRepository } from '../modules/scene/repositories';
|
||||
RoleTypeRepository,
|
||||
SuperAdminSeeder,
|
||||
UserRepository,
|
||||
UserRoleRepository,
|
||||
RegionSeeder,
|
||||
RegionRepository,
|
||||
TimeZoneSeeder,
|
||||
|
||||
@ -19,7 +19,12 @@ export class RoleTypeSeeder {
|
||||
if (!roleTypeNames.includes(RoleType.ADMIN)) {
|
||||
missingRoleTypes.push(RoleType.ADMIN);
|
||||
}
|
||||
|
||||
if (!roleTypeNames.includes(RoleType.SPACE_OWNER)) {
|
||||
missingRoleTypes.push(RoleType.SPACE_OWNER);
|
||||
}
|
||||
if (!roleTypeNames.includes(RoleType.SPACE_MEMBER)) {
|
||||
missingRoleTypes.push(RoleType.SPACE_MEMBER);
|
||||
}
|
||||
if (missingRoleTypes.length > 0) {
|
||||
await this.addRoleTypeData(missingRoleTypes);
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||
import { UserRoleRepository } from '@app/common/modules/user/repositories';
|
||||
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { HelperHashService } from '../../helper/services';
|
||||
@ -11,19 +10,23 @@ export class SuperAdminSeeder {
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly userRoleRepository: UserRoleRepository,
|
||||
private readonly roleTypeRepository: RoleTypeRepository,
|
||||
private readonly helperHashService: HelperHashService,
|
||||
) {}
|
||||
|
||||
async createSuperAdminIfNotFound(): Promise<void> {
|
||||
try {
|
||||
const superAdminData = await this.userRoleRepository.find({
|
||||
where: { roleType: { type: RoleType.SUPER_ADMIN } },
|
||||
const superAdmin = await this.userRepository.findOne({
|
||||
where: {
|
||||
roleType: { type: RoleType.SUPER_ADMIN },
|
||||
email: this.configService.get<string>(
|
||||
'super-admin.SUPER_ADMIN_EMAIL',
|
||||
),
|
||||
},
|
||||
relations: ['roleType'],
|
||||
});
|
||||
|
||||
if (superAdminData.length <= 0) {
|
||||
if (!superAdmin) {
|
||||
// Create the super admin user if not found
|
||||
console.log('Creating super admin user...');
|
||||
|
||||
@ -48,20 +51,16 @@ export class SuperAdminSeeder {
|
||||
salt,
|
||||
);
|
||||
try {
|
||||
const user = await this.userRepository.save({
|
||||
const defaultUserRoleUuid = await this.getRoleUuidByRoleType(
|
||||
RoleType.SUPER_ADMIN,
|
||||
);
|
||||
await this.userRepository.save({
|
||||
email: this.configService.get<string>('super-admin.SUPER_ADMIN_EMAIL'),
|
||||
password: hashedPassword,
|
||||
firstName: 'Super',
|
||||
lastName: 'Admin',
|
||||
isUserVerified: true,
|
||||
isActive: true,
|
||||
});
|
||||
const defaultUserRoleUuid = await this.getRoleUuidByRoleType(
|
||||
RoleType.SUPER_ADMIN,
|
||||
);
|
||||
|
||||
await this.userRoleRepository.save({
|
||||
user: { uuid: user.uuid },
|
||||
roleType: { uuid: defaultUserRoleUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@ -16,6 +16,20 @@ const mappingInclude: { [key: string]: any } = {
|
||||
subspace: {
|
||||
subspace: true,
|
||||
},
|
||||
project: {
|
||||
project: true,
|
||||
},
|
||||
'space-model': {
|
||||
subspaceModels: 'subspace-model',
|
||||
tags: 'tag_model',
|
||||
},
|
||||
'subspace-model': {
|
||||
tags: 'tag_model',
|
||||
},
|
||||
tag_model: {
|
||||
tag_model: true,
|
||||
product: true,
|
||||
},
|
||||
};
|
||||
|
||||
export function buildTypeORMIncludeQuery(
|
||||
@ -27,17 +41,33 @@ export function buildTypeORMIncludeQuery(
|
||||
const fieldsToInclude: string[] = includeParam.split(',');
|
||||
|
||||
fieldsToInclude.forEach((field: string) => {
|
||||
if (mappingInclude[field]) {
|
||||
relations.push(field); // Push mapped field
|
||||
} else {
|
||||
console.warn(
|
||||
`Field ${field} not found in mappingInclude for ${modelName}`,
|
||||
);
|
||||
const nestedFields = field.split('.');
|
||||
let currentModelName = modelName;
|
||||
let isValid = true;
|
||||
|
||||
nestedFields.forEach((nestedField, index) => {
|
||||
const currentMapping = mappingInclude[currentModelName];
|
||||
if (currentMapping?.[nestedField]) {
|
||||
currentModelName =
|
||||
typeof currentMapping[nestedField] === 'string'
|
||||
? currentMapping[nestedField]
|
||||
: currentModelName;
|
||||
} else {
|
||||
console.warn(
|
||||
`Field "${nestedFields.slice(0, index + 1).join('.')}" not found in mappingInclude for model "${currentModelName}"`,
|
||||
);
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
relations.push(field);
|
||||
}
|
||||
});
|
||||
|
||||
return relations;
|
||||
return relations.length ? relations : undefined;
|
||||
}
|
||||
|
||||
return undefined; // If no includes, return undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import axios from 'axios';
|
||||
import {
|
||||
SEND_EMAIL_API_URL_DEV,
|
||||
SEND_EMAIL_API_URL_PROD,
|
||||
} from '../constants/mail-trap';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
@ -35,4 +40,180 @@ export class EmailService {
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
}
|
||||
async sendEmailWithInvitationTemplate(
|
||||
email: string,
|
||||
emailInvitationData: any,
|
||||
): Promise<void> {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const API_TOKEN = this.configService.get<string>(
|
||||
'email-config.MAILTRAP_API_TOKEN',
|
||||
);
|
||||
const API_URL = isProduction
|
||||
? SEND_EMAIL_API_URL_PROD
|
||||
: SEND_EMAIL_API_URL_DEV;
|
||||
const TEMPLATE_UUID = this.configService.get<string>(
|
||||
'email-config.MAILTRAP_INVITATION_TEMPLATE_UUID',
|
||||
);
|
||||
|
||||
const emailData = {
|
||||
from: {
|
||||
email: this.smtpConfig.sender,
|
||||
},
|
||||
to: [
|
||||
{
|
||||
email: email,
|
||||
},
|
||||
],
|
||||
template_uuid: TEMPLATE_UUID,
|
||||
template_variables: emailInvitationData,
|
||||
};
|
||||
|
||||
try {
|
||||
await axios.post(API_URL, emailData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${API_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.response?.data?.message ||
|
||||
'Error sending email using Mailtrap template',
|
||||
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async sendEmailWithTemplate(
|
||||
email: string,
|
||||
name: string,
|
||||
isEnable: boolean,
|
||||
isDelete: boolean,
|
||||
): Promise<void> {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const API_TOKEN = this.configService.get<string>(
|
||||
'email-config.MAILTRAP_API_TOKEN',
|
||||
);
|
||||
const API_URL = isProduction
|
||||
? SEND_EMAIL_API_URL_PROD
|
||||
: SEND_EMAIL_API_URL_DEV;
|
||||
|
||||
// Determine the template UUID based on the arguments
|
||||
const templateUuid = isDelete
|
||||
? this.configService.get<string>(
|
||||
'email-config.MAILTRAP_DELETE_USER_TEMPLATE_UUID',
|
||||
)
|
||||
: this.configService.get<string>(
|
||||
isEnable
|
||||
? 'email-config.MAILTRAP_ENABLE_TEMPLATE_UUID'
|
||||
: 'email-config.MAILTRAP_DISABLE_TEMPLATE_UUID',
|
||||
);
|
||||
|
||||
const emailData = {
|
||||
from: {
|
||||
email: this.smtpConfig.sender,
|
||||
},
|
||||
to: [
|
||||
{
|
||||
email,
|
||||
},
|
||||
],
|
||||
template_uuid: templateUuid,
|
||||
template_variables: {
|
||||
name,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await axios.post(API_URL, emailData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${API_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.response?.data?.message ||
|
||||
'Error sending email using Mailtrap template',
|
||||
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async sendEditUserEmailWithTemplate(
|
||||
email: string,
|
||||
emailEditData: any,
|
||||
): Promise<void> {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const API_TOKEN = this.configService.get<string>(
|
||||
'email-config.MAILTRAP_API_TOKEN',
|
||||
);
|
||||
const API_URL = isProduction
|
||||
? SEND_EMAIL_API_URL_PROD
|
||||
: SEND_EMAIL_API_URL_DEV;
|
||||
const TEMPLATE_UUID = this.configService.get<string>(
|
||||
'email-config.MAILTRAP_EDIT_USER_TEMPLATE_UUID',
|
||||
);
|
||||
|
||||
const emailData = {
|
||||
from: {
|
||||
email: this.smtpConfig.sender,
|
||||
},
|
||||
to: [
|
||||
{
|
||||
email: email,
|
||||
},
|
||||
],
|
||||
template_uuid: TEMPLATE_UUID,
|
||||
template_variables: emailEditData,
|
||||
};
|
||||
|
||||
try {
|
||||
await axios.post(API_URL, emailData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${API_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.response?.data?.message ||
|
||||
'Error sending email using Mailtrap template',
|
||||
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
generateUserChangesEmailBody(
|
||||
addedSpaceNames: string[],
|
||||
removedSpaceNames: string[],
|
||||
oldRole: string,
|
||||
newRole: string,
|
||||
oldName: string,
|
||||
newName: string,
|
||||
) {
|
||||
const addedSpaceNamesChanged =
|
||||
addedSpaceNames.length > 0
|
||||
? `Access to the following spaces were added: ${addedSpaceNames.join(', ')}`
|
||||
: '';
|
||||
|
||||
const removedSpaceNamesChanged =
|
||||
removedSpaceNames.length > 0
|
||||
? `Access to the following spaces were deleted: ${removedSpaceNames.join(', ')}`
|
||||
: '';
|
||||
|
||||
const roleChanged =
|
||||
oldRole !== newRole
|
||||
? `Your user role has been changed from [${oldRole}] to [${newRole}]`
|
||||
: '';
|
||||
|
||||
const nameChanged =
|
||||
oldName !== newName
|
||||
? `The name associated with your account has changed from [${oldName}] to [${newName}]`
|
||||
: '';
|
||||
|
||||
return {
|
||||
addedSpaceNamesChanged,
|
||||
removedSpaceNamesChanged,
|
||||
roleChanged,
|
||||
nameChanged,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
1675
package-lock.json
generated
1675
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.2.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/cqrs": "^10.2.8",
|
||||
"@nestjs/jwt": "^10.2.0",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
@ -66,6 +67,7 @@
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
|
||||
@ -7,7 +7,6 @@ import { GroupModule } from './group/group.module';
|
||||
import { DeviceModule } from './device/device.module';
|
||||
import { UserDevicePermissionModule } from './user-device-permission/user-device-permission.module';
|
||||
import { CommunityModule } from './community/community.module';
|
||||
import { RoleModule } from './role/role.module';
|
||||
import { SeederModule } from '@app/common/seed/seeder.module';
|
||||
import { UserNotificationModule } from './user-notification/user-notification.module';
|
||||
import { DeviceMessagesSubscriptionModule } from './device-messages/device-messages.module';
|
||||
@ -22,6 +21,13 @@ import { VisitorPasswordModule } from './vistor-password/visitor-password.module
|
||||
import { ScheduleModule } from './schedule/schedule.module';
|
||||
import { SpaceModule } from './space/space.module';
|
||||
import { ProductModule } from './product';
|
||||
import { ProjectModule } from './project';
|
||||
import { SpaceModelModule } from './space-model';
|
||||
import { InviteUserModule } from './invite-user/invite-user.module';
|
||||
import { PermissionModule } from './permission/permission.module';
|
||||
import { RoleModule } from './role/role.module';
|
||||
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
|
||||
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
@ -29,11 +35,11 @@ import { ProductModule } from './product';
|
||||
}),
|
||||
AuthenticationModule,
|
||||
UserModule,
|
||||
RoleModule,
|
||||
InviteUserModule,
|
||||
CommunityModule,
|
||||
|
||||
SpaceModule,
|
||||
|
||||
SpaceModelModule,
|
||||
GroupModule,
|
||||
DeviceModule,
|
||||
DeviceMessagesSubscriptionModule,
|
||||
@ -48,6 +54,11 @@ import { ProductModule } from './product';
|
||||
VisitorPasswordModule,
|
||||
ScheduleModule,
|
||||
ProductModule,
|
||||
ProjectModule,
|
||||
PermissionModule,
|
||||
RoleModule,
|
||||
TermsConditionsModule,
|
||||
PrivacyPolicyModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
||||
@ -6,11 +6,9 @@ import { UserAuthController } from './controllers';
|
||||
import { UserAuthService } from './services';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { UserSessionRepository } from '@app/common/modules/session/repositories/session.repository';
|
||||
import {
|
||||
UserRoleRepository,
|
||||
UserOtpRepository,
|
||||
} from '@app/common/modules/user/repositories';
|
||||
import { UserOtpRepository } from '@app/common/modules/user/repositories';
|
||||
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||
import { RoleService } from 'src/role/services';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule, UserRepositoryModule, CommonModule],
|
||||
@ -20,8 +18,8 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||
UserRepository,
|
||||
UserSessionRepository,
|
||||
UserOtpRepository,
|
||||
UserRoleRepository,
|
||||
RoleTypeRepository,
|
||||
RoleService,
|
||||
],
|
||||
exports: [UserAuthService],
|
||||
})
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { IsPasswordStrong } from 'src/validators/password.validator';
|
||||
|
||||
export class UserSignUpDto {
|
||||
@ -39,7 +45,19 @@ export class UserSignUpDto {
|
||||
@IsNotEmpty()
|
||||
public lastName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'regionUuid',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public regionUuid?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'hasAcceptedAppAgreement',
|
||||
required: true,
|
||||
})
|
||||
@IsBoolean()
|
||||
@IsNotEmpty()
|
||||
public hasAcceptedAppAgreement: boolean;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user