mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +00:00
Merge pull request #61 from SyncrowIOT/SP-203-handle-user-profile
Sp 203 handle user profile
This commit is contained in:
2
libs/common/src/constants/default.profile.picture.ts
Normal file
2
libs/common/src/constants/default.profile.picture.ts
Normal file
File diff suppressed because one or more lines are too long
197
libs/common/src/constants/regions.ts
Normal file
197
libs/common/src/constants/regions.ts
Normal file
@ -0,0 +1,197 @@
|
||||
export const allCountries = [
|
||||
'Afghanistan',
|
||||
'Albania',
|
||||
'Algeria',
|
||||
'Andorra',
|
||||
'Angola',
|
||||
'Antigua and Barbuda',
|
||||
'Argentina',
|
||||
'Armenia',
|
||||
'Australia',
|
||||
'Austria',
|
||||
'Azerbaijan',
|
||||
'Bahamas',
|
||||
'Bahrain',
|
||||
'Bangladesh',
|
||||
'Barbados',
|
||||
'Belarus',
|
||||
'Belgium',
|
||||
'Belize',
|
||||
'Benin',
|
||||
'Bhutan',
|
||||
'Bolivia',
|
||||
'Bosnia and Herzegovina',
|
||||
'Botswana',
|
||||
'Brazil',
|
||||
'Brunei',
|
||||
'Bulgaria',
|
||||
'Burkina Faso',
|
||||
'Burundi',
|
||||
'Cabo Verde',
|
||||
'Cambodia',
|
||||
'Cameroon',
|
||||
'Canada',
|
||||
'Central African Republic',
|
||||
'Chad',
|
||||
'Chile',
|
||||
'China',
|
||||
'Colombia',
|
||||
'Comoros',
|
||||
'Congo (Congo-Brazzaville)',
|
||||
'Costa Rica',
|
||||
'Croatia',
|
||||
'Cuba',
|
||||
'Cyprus',
|
||||
'Czech Republic (Czechia)',
|
||||
'Democratic Republic of the Congo',
|
||||
'Denmark',
|
||||
'Djibouti',
|
||||
'Dominica',
|
||||
'Dominican Republic',
|
||||
'Ecuador',
|
||||
'Egypt',
|
||||
'El Salvador',
|
||||
'Equatorial Guinea',
|
||||
'Eritrea',
|
||||
'Estonia',
|
||||
'Eswatini (fmr. "Swaziland")',
|
||||
'Ethiopia',
|
||||
'Fiji',
|
||||
'Finland',
|
||||
'France',
|
||||
'Gabon',
|
||||
'Gambia',
|
||||
'Georgia',
|
||||
'Germany',
|
||||
'Ghana',
|
||||
'Greece',
|
||||
'Grenada',
|
||||
'Guatemala',
|
||||
'Guinea',
|
||||
'Guinea-Bissau',
|
||||
'Guyana',
|
||||
'Haiti',
|
||||
'Honduras',
|
||||
'Hungary',
|
||||
'Iceland',
|
||||
'India',
|
||||
'Indonesia',
|
||||
'Iran',
|
||||
'Iraq',
|
||||
'Ireland',
|
||||
'Israel',
|
||||
'Italy',
|
||||
'Jamaica',
|
||||
'Japan',
|
||||
'Jordan',
|
||||
'Kazakhstan',
|
||||
'Kenya',
|
||||
'Kiribati',
|
||||
'Kuwait',
|
||||
'Kyrgyzstan',
|
||||
'Laos',
|
||||
'Latvia',
|
||||
'Lebanon',
|
||||
'Lesotho',
|
||||
'Liberia',
|
||||
'Libya',
|
||||
'Liechtenstein',
|
||||
'Lithuania',
|
||||
'Luxembourg',
|
||||
'Madagascar',
|
||||
'Malawi',
|
||||
'Malaysia',
|
||||
'Maldives',
|
||||
'Mali',
|
||||
'Malta',
|
||||
'Marshall Islands',
|
||||
'Mauritania',
|
||||
'Mauritius',
|
||||
'Mexico',
|
||||
'Micronesia',
|
||||
'Moldova',
|
||||
'Monaco',
|
||||
'Mongolia',
|
||||
'Montenegro',
|
||||
'Morocco',
|
||||
'Mozambique',
|
||||
'Myanmar (formerly Burma)',
|
||||
'Namibia',
|
||||
'Nauru',
|
||||
'Nepal',
|
||||
'Netherlands',
|
||||
'New Zealand',
|
||||
'Nicaragua',
|
||||
'Niger',
|
||||
'Nigeria',
|
||||
'North Korea',
|
||||
'North Macedonia (formerly Macedonia)',
|
||||
'Norway',
|
||||
'Oman',
|
||||
'Pakistan',
|
||||
'Palau',
|
||||
'Palestine State',
|
||||
'Panama',
|
||||
'Papua New Guinea',
|
||||
'Paraguay',
|
||||
'Peru',
|
||||
'Philippines',
|
||||
'Poland',
|
||||
'Portugal',
|
||||
'Qatar',
|
||||
'Romania',
|
||||
'Russia',
|
||||
'Rwanda',
|
||||
'Saint Kitts and Nevis',
|
||||
'Saint Lucia',
|
||||
'Saint Vincent and the Grenadines',
|
||||
'Samoa',
|
||||
'San Marino',
|
||||
'Sao Tome and Principe',
|
||||
'Saudi Arabia',
|
||||
'Senegal',
|
||||
'Serbia',
|
||||
'Seychelles',
|
||||
'Sierra Leone',
|
||||
'Singapore',
|
||||
'Slovakia',
|
||||
'Slovenia',
|
||||
'Solomon Islands',
|
||||
'Somalia',
|
||||
'South Africa',
|
||||
'South Korea',
|
||||
'South Sudan',
|
||||
'Spain',
|
||||
'Sri Lanka',
|
||||
'Sudan',
|
||||
'Suriname',
|
||||
'Sweden',
|
||||
'Switzerland',
|
||||
'Syria',
|
||||
'Taiwan',
|
||||
'Tajikistan',
|
||||
'Tanzania',
|
||||
'Thailand',
|
||||
'Timor-Leste',
|
||||
'Togo',
|
||||
'Tonga',
|
||||
'Trinidad and Tobago',
|
||||
'Tunisia',
|
||||
'Turkey',
|
||||
'Turkmenistan',
|
||||
'Tuvalu',
|
||||
'Uganda',
|
||||
'Ukraine',
|
||||
'United Arab Emirates',
|
||||
'United Kingdom',
|
||||
'United States of America',
|
||||
'Uruguay',
|
||||
'Uzbekistan',
|
||||
'Vanuatu',
|
||||
'Vatican City',
|
||||
'Venezuela',
|
||||
'Vietnam',
|
||||
'Yemen',
|
||||
'Zambia',
|
||||
'Zimbabwe',
|
||||
];
|
126
libs/common/src/constants/timezones.ts
Normal file
126
libs/common/src/constants/timezones.ts
Normal file
@ -0,0 +1,126 @@
|
||||
export const allTimeZones = [
|
||||
{ name: 'International Date Line West', offset: 'GMT-12:00' },
|
||||
{ name: 'Hawaii', offset: 'GMT-10:00' },
|
||||
{ name: 'Alaska', offset: 'GMT-09:00' },
|
||||
{ name: 'Pacific Time (US & Canada)', offset: 'GMT-08:00' },
|
||||
{ name: 'Arizona', offset: 'GMT-07:00' },
|
||||
{ name: 'Mountain Time (US & Canada)', offset: 'GMT-07:00' },
|
||||
{ name: 'Central Time (US & Canada)', offset: 'GMT-06:00' },
|
||||
{ name: 'Mexico City', offset: 'GMT-06:00' },
|
||||
{ name: 'Saskatchewan', offset: 'GMT-06:00' },
|
||||
{ name: 'Eastern Time (US & Canada)', offset: 'GMT-05:00' },
|
||||
{ name: 'Bogota', offset: 'GMT-05:00' },
|
||||
{ name: 'Indiana (East)', offset: 'GMT-05:00' },
|
||||
{ name: 'Atlantic Time (Canada)', offset: 'GMT-04:00' },
|
||||
{ name: 'Caracas', offset: 'GMT-04:00' },
|
||||
{ name: 'Santiago', offset: 'GMT-04:00' },
|
||||
{ name: 'Newfoundland', offset: 'GMT-03:30' },
|
||||
{ name: 'Brasilia', offset: 'GMT-03:00' },
|
||||
{ name: 'Buenos Aires', offset: 'GMT-03:00' },
|
||||
{ name: 'Greenland', offset: 'GMT-03:00' },
|
||||
{ name: 'Mid-Atlantic', offset: 'GMT-02:00' },
|
||||
{ name: 'Azores', offset: 'GMT-01:00' },
|
||||
{ name: 'Cape Verde Is.', offset: 'GMT-01:00' },
|
||||
{ name: 'Casablanca', offset: 'GMT+00:00' },
|
||||
{ name: 'Dublin', offset: 'GMT+00:00' },
|
||||
{ name: 'Lisbon', offset: 'GMT+00:00' },
|
||||
{ name: 'London', offset: 'GMT+00:00' },
|
||||
{ name: 'Monrovia', offset: 'GMT+00:00' },
|
||||
{ name: 'Amsterdam', offset: 'GMT+01:00' },
|
||||
{ name: 'Belgrade', offset: 'GMT+01:00' },
|
||||
{ name: 'Berlin', offset: 'GMT+01:00' },
|
||||
{ name: 'Bratislava', offset: 'GMT+01:00' },
|
||||
{ name: 'Brussels', offset: 'GMT+01:00' },
|
||||
{ name: 'Budapest', offset: 'GMT+01:00' },
|
||||
{ name: 'Copenhagen', offset: 'GMT+01:00' },
|
||||
{ name: 'Madrid', offset: 'GMT+01:00' },
|
||||
{ name: 'Paris', offset: 'GMT+01:00' },
|
||||
{ name: 'Prague', offset: 'GMT+01:00' },
|
||||
{ name: 'Rome', offset: 'GMT+01:00' },
|
||||
{ name: 'Sarajevo', offset: 'GMT+01:00' },
|
||||
{ name: 'Warsaw', offset: 'GMT+01:00' },
|
||||
{ name: 'West Central Africa', offset: 'GMT+01:00' },
|
||||
{ name: 'Zagreb', offset: 'GMT+01:00' },
|
||||
{ name: 'Athens', offset: 'GMT+02:00' },
|
||||
{ name: 'Bucharest', offset: 'GMT+02:00' },
|
||||
{ name: 'Cairo', offset: 'GMT+02:00' },
|
||||
{ name: 'Harare', offset: 'GMT+02:00' },
|
||||
{ name: 'Helsinki', offset: 'GMT+02:00' },
|
||||
{ name: 'Jerusalem', offset: 'GMT+02:00' },
|
||||
{ name: 'Kaliningrad', offset: 'GMT+02:00' },
|
||||
{ name: 'Kyiv', offset: 'GMT+02:00' },
|
||||
{ name: 'Pretoria', offset: 'GMT+02:00' },
|
||||
{ name: 'Riga', offset: 'GMT+02:00' },
|
||||
{ name: 'Sofia', offset: 'GMT+02:00' },
|
||||
{ name: 'Tallinn', offset: 'GMT+02:00' },
|
||||
{ name: 'Vilnius', offset: 'GMT+02:00' },
|
||||
{ name: 'Baghdad', offset: 'GMT+03:00' },
|
||||
{ name: 'Istanbul', offset: 'GMT+03:00' },
|
||||
{ name: 'Kuwait', offset: 'GMT+03:00' },
|
||||
{ name: 'Minsk', offset: 'GMT+03:00' },
|
||||
{ name: 'Moscow', offset: 'GMT+03:00' },
|
||||
{ name: 'Nairobi', offset: 'GMT+03:00' },
|
||||
{ name: 'Riyadh', offset: 'GMT+03:00' },
|
||||
{ name: 'St. Petersburg', offset: 'GMT+03:00' },
|
||||
{ name: 'Tehran', offset: 'GMT+03:30' },
|
||||
{ name: 'Abu Dhabi', offset: 'GMT+04:00' },
|
||||
{ name: 'Baku', offset: 'GMT+04:00' },
|
||||
{ name: 'Muscat', offset: 'GMT+04:00' },
|
||||
{ name: 'Tbilisi', offset: 'GMT+04:00' },
|
||||
{ name: 'Yerevan', offset: 'GMT+04:00' },
|
||||
{ name: 'Kabul', offset: 'GMT+04:30' },
|
||||
{ name: 'Ekaterinburg', offset: 'GMT+05:00' },
|
||||
{ name: 'Islamabad', offset: 'GMT+05:00' },
|
||||
{ name: 'Karachi', offset: 'GMT+05:00' },
|
||||
{ name: 'Tashkent', offset: 'GMT+05:00' },
|
||||
{ name: 'Chennai', offset: 'GMT+05:30' },
|
||||
{ name: 'Kolkata', offset: 'GMT+05:30' },
|
||||
{ name: 'Mumbai', offset: 'GMT+05:30' },
|
||||
{ name: 'New Delhi', offset: 'GMT+05:30' },
|
||||
{ name: 'Sri Jayawardenepura', offset: 'GMT+05:30' },
|
||||
{ name: 'Kathmandu', offset: 'GMT+05:45' },
|
||||
{ name: 'Almaty', offset: 'GMT+06:00' },
|
||||
{ name: 'Astana', offset: 'GMT+06:00' },
|
||||
{ name: 'Dhaka', offset: 'GMT+06:00' },
|
||||
{ name: 'Urumqi', offset: 'GMT+06:00' },
|
||||
{ name: 'Rangoon', offset: 'GMT+06:30' },
|
||||
{ name: 'Bangkok', offset: 'GMT+07:00' },
|
||||
{ name: 'Hanoi', offset: 'GMT+07:00' },
|
||||
{ name: 'Jakarta', offset: 'GMT+07:00' },
|
||||
{ name: 'Krasnoyarsk', offset: 'GMT+07:00' },
|
||||
{ name: 'Beijing', offset: 'GMT+08:00' },
|
||||
{ name: 'Chongqing', offset: 'GMT+08:00' },
|
||||
{ name: 'Hong Kong', offset: 'GMT+08:00' },
|
||||
{ name: 'Irkutsk', offset: 'GMT+08:00' },
|
||||
{ name: 'Kuala Lumpur', offset: 'GMT+08:00' },
|
||||
{ name: 'Perth', offset: 'GMT+08:00' },
|
||||
{ name: 'Singapore', offset: 'GMT+08:00' },
|
||||
{ name: 'Taipei', offset: 'GMT+08:00' },
|
||||
{ name: 'Ulaan Bataar', offset: 'GMT+08:00' },
|
||||
{ name: 'Osaka', offset: 'GMT+09:00' },
|
||||
{ name: 'Sapporo', offset: 'GMT+09:00' },
|
||||
{ name: 'Seoul', offset: 'GMT+09:00' },
|
||||
{ name: 'Tokyo', offset: 'GMT+09:00' },
|
||||
{ name: 'Yakutsk', offset: 'GMT+09:00' },
|
||||
{ name: 'Adelaide', offset: 'GMT+09:30' },
|
||||
{ name: 'Darwin', offset: 'GMT+09:30' },
|
||||
{ name: 'Brisbane', offset: 'GMT+10:00' },
|
||||
{ name: 'Canberra', offset: 'GMT+10:00' },
|
||||
{ name: 'Guam', offset: 'GMT+10:00' },
|
||||
{ name: 'Hobart', offset: 'GMT+10:00' },
|
||||
{ name: 'Melbourne', offset: 'GMT+10:00' },
|
||||
{ name: 'Port Moresby', offset: 'GMT+10:00' },
|
||||
{ name: 'Sydney', offset: 'GMT+10:00' },
|
||||
{ name: 'Vladivostok', offset: 'GMT+10:00' },
|
||||
{ name: 'Magadan', offset: 'GMT+11:00' },
|
||||
{ name: 'New Caledonia', offset: 'GMT+11:00' },
|
||||
{ name: 'Solomon Is.', offset: 'GMT+11:00' },
|
||||
{ name: 'Kamchatka', offset: 'GMT+12:00' },
|
||||
{ name: 'Marshall Is.', offset: 'GMT+12:00' },
|
||||
{ name: 'Fiji', offset: 'GMT+12:00' },
|
||||
{ name: 'Auckland', offset: 'GMT+12:00' },
|
||||
{ name: 'Wellington', offset: 'GMT+12:00' },
|
||||
{ name: "Nuku'alofa", offset: 'GMT+13:00' },
|
||||
{ name: 'Samoa', offset: 'GMT+13:00' },
|
||||
{ name: 'Tokelau Is.', offset: 'GMT+13:00' },
|
||||
];
|
@ -16,6 +16,8 @@ import { UserRoleEntity } from '../modules/user-role/entities';
|
||||
import { RoleTypeEntity } from '../modules/role-type/entities';
|
||||
import { UserNotificationEntity } from '../modules/user-notification/entities';
|
||||
import { DeviceNotificationEntity } from '../modules/device-notification/entities';
|
||||
import { RegionEntity } from '../modules/region/entities';
|
||||
import { TimeZoneEntity } from '../modules/timezone/entities';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -46,6 +48,8 @@ import { DeviceNotificationEntity } from '../modules/device-notification/entitie
|
||||
RoleTypeEntity,
|
||||
UserNotificationEntity,
|
||||
DeviceNotificationEntity,
|
||||
RegionEntity,
|
||||
TimeZoneEntity,
|
||||
],
|
||||
namingStrategy: new SnakeNamingStrategy(),
|
||||
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
|
||||
|
1
libs/common/src/modules/region/dtos/index.ts
Normal file
1
libs/common/src/modules/region/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './region.dto';
|
11
libs/common/src/modules/region/dtos/region.dto.ts
Normal file
11
libs/common/src/modules/region/dtos/region.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class RegionDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public regionName: string;
|
||||
}
|
1
libs/common/src/modules/region/entities/index.ts
Normal file
1
libs/common/src/modules/region/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './region.entity';
|
20
libs/common/src/modules/region/entities/region.entity.ts
Normal file
20
libs/common/src/modules/region/entities/region.entity.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Column, Entity, OneToMany } from 'typeorm';
|
||||
import { RegionDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
|
||||
@Entity({ name: 'region' })
|
||||
export class RegionEntity extends AbstractEntity<RegionDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
regionName: string;
|
||||
|
||||
@OneToMany(() => UserEntity, (user) => user.region)
|
||||
users: UserEntity[];
|
||||
|
||||
constructor(partial: Partial<RegionEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
11
libs/common/src/modules/region/region.repository.module.ts
Normal file
11
libs/common/src/modules/region/region.repository.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { RegionEntity } from './entities/region.entity';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([RegionEntity])],
|
||||
})
|
||||
export class RegionRepositoryModule {}
|
1
libs/common/src/modules/region/repositories/index.ts
Normal file
1
libs/common/src/modules/region/repositories/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './region.repository';
|
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RegionEntity } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class RegionRepository extends Repository<RegionEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(RegionEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
1
libs/common/src/modules/timezone/dtos/index.ts
Normal file
1
libs/common/src/modules/timezone/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './timezone.dto';
|
15
libs/common/src/modules/timezone/dtos/timezone.dto.ts
Normal file
15
libs/common/src/modules/timezone/dtos/timezone.dto.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class TimeZoneDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public cityName: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public timeZoneOffset: string;
|
||||
}
|
1
libs/common/src/modules/timezone/entities/index.ts
Normal file
1
libs/common/src/modules/timezone/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './timezone.entity';
|
23
libs/common/src/modules/timezone/entities/timezone.entity.ts
Normal file
23
libs/common/src/modules/timezone/entities/timezone.entity.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Column, Entity, OneToMany } from 'typeorm';
|
||||
import { TimeZoneDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
|
||||
@Entity({ name: 'timezone' })
|
||||
export class TimeZoneEntity extends AbstractEntity<TimeZoneDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
cityName: string;
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
timeZoneOffset: string;
|
||||
@OneToMany(() => UserEntity, (user) => user.timezone)
|
||||
users: UserEntity[];
|
||||
|
||||
constructor(partial: Partial<TimeZoneEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
1
libs/common/src/modules/timezone/repositories/index.ts
Normal file
1
libs/common/src/modules/timezone/repositories/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './timezone.repository';
|
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TimeZoneEntity } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class TimeZoneRepository extends Repository<TimeZoneEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(TimeZoneEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TimeZoneEntity } from './entities/timezone.entity';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([TimeZoneEntity])],
|
||||
})
|
||||
export class TimeZoneRepositoryModule {}
|
@ -1,5 +1,5 @@
|
||||
import { DeviceUserPermissionEntity } from '../../device-user-permission/entities/device.user.permission.entity';
|
||||
import { Column, Entity, OneToMany } from 'typeorm';
|
||||
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { UserDto } from '../dtos';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { UserSpaceEntity } from '../../user-space/entities';
|
||||
@ -7,6 +7,9 @@ import { UserRoleEntity } from '../../user-role/entities';
|
||||
import { DeviceNotificationEntity } from '../../device-notification/entities';
|
||||
import { UserNotificationEntity } from '../../user-notification/entities';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { defaultProfilePicture } from '@app/common/constants/default.profile.picture';
|
||||
import { RegionEntity } from '../../region/entities';
|
||||
import { TimeZoneEntity } from '../../timezone/entities';
|
||||
|
||||
@Entity({ name: 'user' })
|
||||
export class UserEntity extends AbstractEntity<UserDto> {
|
||||
@ -17,6 +20,13 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: 'text',
|
||||
default: defaultProfilePicture,
|
||||
})
|
||||
public profilePicture: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
unique: true,
|
||||
@ -78,6 +88,12 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
nullable: true,
|
||||
})
|
||||
roles: UserRoleEntity[];
|
||||
@ManyToOne(() => RegionEntity, (region) => region.users, { nullable: true })
|
||||
region: RegionEntity;
|
||||
@ManyToOne(() => TimeZoneEntity, (timezone) => timezone.users, {
|
||||
nullable: true,
|
||||
})
|
||||
timezone: TimeZoneEntity;
|
||||
constructor(partial: Partial<UserEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
@ -15,6 +15,10 @@ import { UserRepository } from '../modules/user/repositories';
|
||||
import { UserRoleRepository } from '../modules/user-role/repositories';
|
||||
import { UserRoleRepositoryModule } from '../modules/user-role/user.role.repository.module';
|
||||
import { UserRepositoryModule } from '../modules/user/user.repository.module';
|
||||
import { RegionSeeder } from './services/regions.seeder';
|
||||
import { RegionRepository } from '../modules/region/repositories';
|
||||
import { TimeZoneSeeder } from './services/timezone.seeder';
|
||||
import { TimeZoneRepository } from '../modules/timezone/repositories';
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [
|
||||
@ -28,6 +32,10 @@ import { UserRepositoryModule } from '../modules/user/user.repository.module';
|
||||
SuperAdminSeeder,
|
||||
UserRepository,
|
||||
UserRoleRepository,
|
||||
RegionSeeder,
|
||||
RegionRepository,
|
||||
TimeZoneSeeder,
|
||||
TimeZoneRepository,
|
||||
],
|
||||
exports: [SeederService],
|
||||
controllers: [],
|
||||
|
40
libs/common/src/seed/services/regions.seeder.ts
Normal file
40
libs/common/src/seed/services/regions.seeder.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { allCountries } from '@app/common/constants/regions';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class RegionSeeder {
|
||||
constructor(private readonly regionRepository: RegionRepository) {}
|
||||
|
||||
async addRegionDataIfNotFound(): Promise<void> {
|
||||
try {
|
||||
const existingRegions = await this.regionRepository.find();
|
||||
|
||||
const regionNames = existingRegions.map((region) => region.regionName);
|
||||
|
||||
const missingRegions = allCountries.filter(
|
||||
(country) => !regionNames.includes(country),
|
||||
);
|
||||
|
||||
if (missingRegions.length > 0) {
|
||||
await this.addRegionData(missingRegions);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error while checking region data:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private async addRegionData(regions: string[]): Promise<void> {
|
||||
try {
|
||||
const regionEntities = regions.map((regionName) => ({
|
||||
regionName,
|
||||
}));
|
||||
|
||||
await this.regionRepository.save(regionEntities);
|
||||
} catch (err) {
|
||||
console.error('Error while adding region data:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,12 +3,16 @@ import { PermissionTypeSeeder } from './permission.type.seeder';
|
||||
import { RoleTypeSeeder } from './role.type.seeder';
|
||||
import { SpaceTypeSeeder } from './space.type.seeder';
|
||||
import { SuperAdminSeeder } from './supper.admin.seeder';
|
||||
import { RegionSeeder } from './regions.seeder';
|
||||
import { TimeZoneSeeder } from './timezone.seeder';
|
||||
@Injectable()
|
||||
export class SeederService {
|
||||
constructor(
|
||||
private readonly permissionTypeSeeder: PermissionTypeSeeder,
|
||||
private readonly roleTypeSeeder: RoleTypeSeeder,
|
||||
private readonly spaceTypeSeeder: SpaceTypeSeeder,
|
||||
private readonly regionSeeder: RegionSeeder,
|
||||
private readonly timeZoneSeeder: TimeZoneSeeder,
|
||||
private readonly superAdminSeeder: SuperAdminSeeder,
|
||||
) {}
|
||||
|
||||
@ -16,6 +20,8 @@ export class SeederService {
|
||||
await this.permissionTypeSeeder.addPermissionTypeDataIfNotFound();
|
||||
await this.roleTypeSeeder.addRoleTypeDataIfNotFound();
|
||||
await this.spaceTypeSeeder.addSpaceTypeDataIfNotFound();
|
||||
await this.regionSeeder.addRegionDataIfNotFound();
|
||||
await this.timeZoneSeeder.addTimeZoneDataIfNotFound();
|
||||
await this.superAdminSeeder.createSuperAdminIfNotFound();
|
||||
}
|
||||
}
|
||||
|
42
libs/common/src/seed/services/timezone.seeder.ts
Normal file
42
libs/common/src/seed/services/timezone.seeder.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
import { allTimeZones } from '@app/common/constants/timezones';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class TimeZoneSeeder {
|
||||
constructor(private readonly timeZoneRepository: TimeZoneRepository) {}
|
||||
|
||||
async addTimeZoneDataIfNotFound(): Promise<void> {
|
||||
try {
|
||||
const existingTimeZones = await this.timeZoneRepository.find();
|
||||
const timeZoneNames = existingTimeZones.map((tz) => tz.cityName);
|
||||
|
||||
const missingTimeZones = allTimeZones.filter(
|
||||
(tz) => !timeZoneNames.includes(tz.name),
|
||||
);
|
||||
|
||||
if (missingTimeZones.length > 0) {
|
||||
await this.addTimeZoneData(missingTimeZones);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error while checking time zone data:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private async addTimeZoneData(
|
||||
timeZones: { name: string; offset: string }[],
|
||||
): Promise<void> {
|
||||
try {
|
||||
const timeZoneEntities = timeZones.map((tz) => ({
|
||||
cityName: tz.name,
|
||||
timeZoneOffset: tz.offset,
|
||||
}));
|
||||
|
||||
await this.timeZoneRepository.save(timeZoneEntities);
|
||||
} catch (err) {
|
||||
console.error('Error while adding time zone data:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ import { DoorLockModule } from './door-lock/door.lock.module';
|
||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
||||
import { AutomationModule } from './automation/automation.module';
|
||||
import { RegionModule } from './region/region.module';
|
||||
import { TimeZoneModule } from './timezone/timezone.module';
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
@ -44,6 +46,8 @@ import { AutomationModule } from './automation/automation.module';
|
||||
SceneModule,
|
||||
AutomationModule,
|
||||
DoorLockModule,
|
||||
RegionModule,
|
||||
TimeZoneModule,
|
||||
],
|
||||
controllers: [AuthenticationController],
|
||||
providers: [
|
||||
|
45
src/guards/profile.picture.guard.ts
Normal file
45
src/guards/profile.picture.guard.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class CheckProfilePictureGuard implements CanActivate {
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
|
||||
try {
|
||||
if (req.body) {
|
||||
const { profilePicture } = req.body;
|
||||
if (profilePicture) {
|
||||
const isBase64 = /^data:image\/[a-z]+;base64,/.test(profilePicture);
|
||||
if (!isBase64) {
|
||||
throw new BadRequestException(
|
||||
'Profile picture must be in base64 format.',
|
||||
);
|
||||
}
|
||||
|
||||
// Get the size of the base64 string (in bytes)
|
||||
const base64StringLength =
|
||||
profilePicture.length - 'data:image/[a-z]+;base64,'.length;
|
||||
const base64ImageSizeInBytes = base64StringLength * 0.75; // Base64 encoding expands data by 33%
|
||||
const maxSizeInBytes = 1 * 1024 * 1024; // 1 MB
|
||||
|
||||
// Check if the size exceeds the limit
|
||||
if (base64ImageSizeInBytes > maxSizeInBytes) {
|
||||
throw new BadRequestException(
|
||||
'Profile picture size exceeds the allowed limit.',
|
||||
);
|
||||
}
|
||||
}
|
||||
// Check if profilePicture is a base64 string
|
||||
} else {
|
||||
throw new BadRequestException('Invalid request parameters');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log('Profile picture guard error: ', error);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import rateLimit from 'express-rate-limit';
|
||||
import helmet from 'helmet';
|
||||
import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.swagger.utils';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { json, urlencoded } from 'body-parser';
|
||||
import { SeederService } from '@app/common/seed/services/seeder.service';
|
||||
|
||||
async function bootstrap() {
|
||||
@ -11,6 +12,10 @@ async function bootstrap() {
|
||||
|
||||
app.enableCors();
|
||||
|
||||
// Set the body parser limit to 1 MB
|
||||
app.use(json({ limit: '1mb' }));
|
||||
app.use(urlencoded({ limit: '1mb', extended: true }));
|
||||
|
||||
app.use(
|
||||
rateLimit({
|
||||
windowMs: 5 * 60 * 1000,
|
||||
@ -42,7 +47,8 @@ async function bootstrap() {
|
||||
} catch (error) {
|
||||
console.error('Seeding failed!', error);
|
||||
}
|
||||
|
||||
console.log('Starting auth at port ...', process.env.PORT || 4000);
|
||||
await app.listen(process.env.PORT || 4000);
|
||||
}
|
||||
console.log('Starting auth at port ...', process.env.PORT || 4000);
|
||||
bootstrap();
|
||||
|
1
src/region/controllers/index.ts
Normal file
1
src/region/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './region.controller';
|
33
src/region/controllers/region.controller.ts
Normal file
33
src/region/controllers/region.controller.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { RegionService } from '../services/region.service';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
|
||||
@ApiTags('Region Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'region',
|
||||
})
|
||||
export class RegionController {
|
||||
constructor(private readonly regionService: RegionService) {}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
async getAllRegions() {
|
||||
try {
|
||||
return await this.regionService.getAllRegions();
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
13
src/region/region.module.ts
Normal file
13
src/region/region.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { RegionService } from './services/region.service';
|
||||
import { RegionController } from './controllers/region.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
controllers: [RegionController],
|
||||
providers: [RegionService, RegionRepository],
|
||||
exports: [RegionService],
|
||||
})
|
||||
export class RegionModule {}
|
1
src/region/services/index.ts
Normal file
1
src/region/services/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './region.service';
|
25
src/region/services/region.service.ts
Normal file
25
src/region/services/region.service.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
|
||||
@Injectable()
|
||||
export class RegionService {
|
||||
constructor(private readonly regionRepository: RegionRepository) {}
|
||||
async getAllRegions() {
|
||||
try {
|
||||
const regions = await this.regionRepository.find();
|
||||
|
||||
return regions;
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException) {
|
||||
throw err; // Re-throw BadRequestException
|
||||
} else {
|
||||
throw new HttpException('Regions found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
src/timezone/controllers/index.ts
Normal file
1
src/timezone/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './timezone.controller';
|
33
src/timezone/controllers/timezone.controller.ts
Normal file
33
src/timezone/controllers/timezone.controller.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { TimeZoneService } from '../services/timezone.service';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
|
||||
@ApiTags('TimeZone Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'timezone',
|
||||
})
|
||||
export class TimeZoneController {
|
||||
constructor(private readonly timeZoneService: TimeZoneService) {}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
async getAllTimeZones() {
|
||||
try {
|
||||
return await this.timeZoneService.getAllTimeZones();
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
1
src/timezone/services/index.ts
Normal file
1
src/timezone/services/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './timezone.service';
|
25
src/timezone/services/timezone.service.ts
Normal file
25
src/timezone/services/timezone.service.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class TimeZoneService {
|
||||
constructor(private readonly timeZoneRepository: TimeZoneRepository) {}
|
||||
async getAllTimeZones() {
|
||||
try {
|
||||
const timeZones = await this.timeZoneRepository.find();
|
||||
|
||||
return timeZones;
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException) {
|
||||
throw err; // Re-throw BadRequestException
|
||||
} else {
|
||||
throw new HttpException('TimeZones found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
src/timezone/timezone.module.ts
Normal file
13
src/timezone/timezone.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TimeZoneService } from './services/timezone.service';
|
||||
import { TimeZoneController } from './controllers/timezone.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
controllers: [TimeZoneController],
|
||||
providers: [TimeZoneService, TimeZoneRepository],
|
||||
exports: [TimeZoneService],
|
||||
})
|
||||
export class TimeZoneModule {}
|
@ -1,8 +1,23 @@
|
||||
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Put,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { UserListDto } from '../dtos/user.list.dto';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
import {
|
||||
UpdateNameDto,
|
||||
UpdateProfilePictureDataDto,
|
||||
UpdateRegionDataDto,
|
||||
UpdateTimezoneDataDto,
|
||||
} from '../dtos';
|
||||
import { CheckProfilePictureGuard } from 'src/guards/profile.picture.guard';
|
||||
|
||||
@ApiTags('User Module')
|
||||
@Controller({
|
||||
@ -13,13 +28,116 @@ export class UserController {
|
||||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@Get('list')
|
||||
async userList(@Query() userListDto: UserListDto) {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':userUuid')
|
||||
async getUserDetailsByUserUuid(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.userService.userDetails(userListDto);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
return await this.userService.getUserDetailsByUserUuid(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckProfilePictureGuard)
|
||||
@Put('/profile-picture/:userUuid')
|
||||
async updateProfilePictureByUserUuid(
|
||||
@Param('userUuid') userUuid: string,
|
||||
@Body() updateProfilePictureDataDto: UpdateProfilePictureDataDto,
|
||||
) {
|
||||
try {
|
||||
const userData = await this.userService.updateProfilePictureByUserUuid(
|
||||
userUuid,
|
||||
updateProfilePictureDataDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'profile picture updated successfully',
|
||||
data: userData,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put('/region/:userUuid')
|
||||
async updateRegionByUserUuid(
|
||||
@Param('userUuid') userUuid: string,
|
||||
@Body() updateRegionDataDto: UpdateRegionDataDto,
|
||||
) {
|
||||
try {
|
||||
const userData = await this.userService.updateRegionByUserUuid(
|
||||
userUuid,
|
||||
updateRegionDataDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'region updated successfully',
|
||||
data: userData,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put('/timezone/:userUuid')
|
||||
async updateNameByUserUuid(
|
||||
@Param('userUuid') userUuid: string,
|
||||
@Body() updateTimezoneDataDto: UpdateTimezoneDataDto,
|
||||
) {
|
||||
try {
|
||||
const userData = await this.userService.updateTimezoneByUserUuid(
|
||||
userUuid,
|
||||
updateTimezoneDataDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'timezone updated successfully',
|
||||
data: userData,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put('/name/:userUuid')
|
||||
async updateTimezoneByUserUuid(
|
||||
@Param('userUuid') userUuid: string,
|
||||
@Body() updateNameDto: UpdateNameDto,
|
||||
) {
|
||||
try {
|
||||
const userData = await this.userService.updateNameByUserUuid(
|
||||
userUuid,
|
||||
updateNameDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'name updated successfully',
|
||||
data: userData,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
export * from './user.list.dto';
|
||||
export * from './update.user.dto';
|
||||
|
61
src/users/dtos/update.user.dto.ts
Normal file
61
src/users/dtos/update.user.dto.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class UpdateProfilePictureDataDto {
|
||||
@ApiProperty({
|
||||
description: 'profilePicture',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public profilePicture: string;
|
||||
|
||||
constructor(dto: Partial<UpdateProfilePictureDataDto>) {
|
||||
Object.assign(this, dto);
|
||||
}
|
||||
}
|
||||
export class UpdateRegionDataDto {
|
||||
@ApiProperty({
|
||||
description: 'regionUuid',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public regionUuid: string;
|
||||
|
||||
constructor(dto: Partial<UpdateProfilePictureDataDto>) {
|
||||
Object.assign(this, dto);
|
||||
}
|
||||
}
|
||||
export class UpdateTimezoneDataDto {
|
||||
@ApiProperty({
|
||||
description: 'timezoneUuid',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public timezoneUuid: string;
|
||||
|
||||
constructor(dto: Partial<UpdateProfilePictureDataDto>) {
|
||||
Object.assign(this, dto);
|
||||
}
|
||||
}
|
||||
export class UpdateNameDto {
|
||||
@ApiProperty({
|
||||
description: 'firstName',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public firstName: string;
|
||||
@ApiProperty({
|
||||
description: 'lastName',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public lastName: string;
|
||||
constructor(dto: Partial<UpdateProfilePictureDataDto>) {
|
||||
Object.assign(this, dto);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import {
|
||||
IsNotEmpty,
|
||||
IsNumberString,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class UserListDto {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
schema: string;
|
||||
|
||||
@IsNumberString()
|
||||
@IsNotEmpty()
|
||||
page_no: number;
|
||||
|
||||
@IsNumberString()
|
||||
@IsNotEmpty()
|
||||
page_size: number;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
username: string;
|
||||
|
||||
@IsNumberString()
|
||||
@IsOptional()
|
||||
start_time: number;
|
||||
|
||||
@IsNumberString()
|
||||
@IsOptional()
|
||||
end_time: number;
|
||||
}
|
@ -1,28 +1,225 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import { UserListDto } from '../dtos/user.list.dto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
UpdateNameDto,
|
||||
UpdateProfilePictureDataDto,
|
||||
UpdateRegionDataDto,
|
||||
UpdateTimezoneDataDto,
|
||||
} from './../dtos/update.user.dto';
|
||||
import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
private tuya: TuyaContext;
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
||||
const tuyaEuUrl = this.configService.get<string>('tuya-config.TUYA_EU_URL');
|
||||
this.tuya = new TuyaContext({
|
||||
baseUrl: tuyaEuUrl,
|
||||
accessKey,
|
||||
secretKey,
|
||||
});
|
||||
constructor(
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly regionRepository: RegionRepository,
|
||||
private readonly timeZoneRepository: TimeZoneRepository,
|
||||
) {}
|
||||
async getUserDetailsByUserUuid(userUuid: string) {
|
||||
try {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
uuid: userUuid,
|
||||
},
|
||||
relations: ['region', 'timezone'],
|
||||
});
|
||||
if (!user) {
|
||||
throw new BadRequestException('Invalid room UUID');
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: user.uuid,
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
profilePicture: user.profilePicture,
|
||||
region: user.region,
|
||||
timeZone: user.timezone,
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException) {
|
||||
throw err; // Re-throw BadRequestException
|
||||
} else {
|
||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
async userDetails(userListDto: UserListDto) {
|
||||
const path = `/v2.0/apps/${userListDto.schema}/users`;
|
||||
const data = await this.tuya.request({
|
||||
method: 'GET',
|
||||
path,
|
||||
query: userListDto,
|
||||
});
|
||||
return data;
|
||||
|
||||
async updateProfilePictureByUserUuid(
|
||||
userUuid: string,
|
||||
updateProfilePictureDataDto: UpdateProfilePictureDataDto,
|
||||
) {
|
||||
try {
|
||||
await this.userRepository.update(
|
||||
{ uuid: userUuid },
|
||||
{ ...updateProfilePictureDataDto },
|
||||
);
|
||||
const updatedUser = await this.getUserDetailsByUserUuid(userUuid);
|
||||
return {
|
||||
uuid: updatedUser.uuid,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
profilePicture: updatedUser.profilePicture,
|
||||
region: updatedUser.region,
|
||||
timeZoneUuid: updatedUser.timeZone,
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
|
||||
if (err instanceof BadRequestException) {
|
||||
throw err; // Re-throw BadRequestException
|
||||
} else {
|
||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
async updateRegionByUserUuid(
|
||||
userUuid: string,
|
||||
updateRegionDataDto: UpdateRegionDataDto,
|
||||
) {
|
||||
try {
|
||||
const user = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!user) {
|
||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Ensure the region UUID is provided
|
||||
if (!updateRegionDataDto.regionUuid) {
|
||||
throw new BadRequestException('Region UUID is required');
|
||||
}
|
||||
|
||||
// Ensure the region exists
|
||||
const region = await this.regionRepository.findOne({
|
||||
where: {
|
||||
uuid: updateRegionDataDto.regionUuid,
|
||||
},
|
||||
});
|
||||
if (!region) {
|
||||
throw new BadRequestException('Invalid region UUID');
|
||||
}
|
||||
|
||||
await this.userRepository.update(
|
||||
{ uuid: userUuid },
|
||||
{
|
||||
region: region,
|
||||
},
|
||||
);
|
||||
|
||||
const updatedUser = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!updatedUser.region) {
|
||||
throw new BadRequestException('Region update failed');
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: updatedUser.uuid,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
profilePicture: updatedUser.profilePicture,
|
||||
region: updatedUser.region,
|
||||
timeZoneUuid: updatedUser.timeZone,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new HttpException(
|
||||
err.message || 'User not found',
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
async updateTimezoneByUserUuid(
|
||||
userUuid: string,
|
||||
updateTimezoneDataDto: UpdateTimezoneDataDto,
|
||||
) {
|
||||
try {
|
||||
const user = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!user) {
|
||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Ensure the region UUID is provided
|
||||
if (!updateTimezoneDataDto.timezoneUuid) {
|
||||
throw new BadRequestException('Timezone UUID is required');
|
||||
}
|
||||
|
||||
// Ensure the region exists
|
||||
const timezone = await this.timeZoneRepository.findOne({
|
||||
where: {
|
||||
uuid: updateTimezoneDataDto.timezoneUuid,
|
||||
},
|
||||
});
|
||||
if (!timezone) {
|
||||
throw new BadRequestException('Invalid timezone UUID');
|
||||
}
|
||||
|
||||
await this.userRepository.update(
|
||||
{ uuid: userUuid },
|
||||
{
|
||||
timezone: timezone,
|
||||
},
|
||||
);
|
||||
|
||||
const updatedUser = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!updatedUser.timeZone) {
|
||||
throw new BadRequestException('Timezone update failed');
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: updatedUser.uuid,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
profilePicture: updatedUser.profilePicture,
|
||||
region: updatedUser.region,
|
||||
timeZoneUuid: updatedUser.timeZone,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new HttpException(
|
||||
err.message || 'User not found',
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
async updateNameByUserUuid(userUuid: string, updateNameDto: UpdateNameDto) {
|
||||
try {
|
||||
const user = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!user) {
|
||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!updateNameDto.firstName || !updateNameDto.lastName) {
|
||||
throw new BadRequestException('First Name and Last Name is required');
|
||||
}
|
||||
|
||||
await this.userRepository.update(
|
||||
{ uuid: userUuid },
|
||||
{
|
||||
firstName: updateNameDto.firstName,
|
||||
lastName: updateNameDto.lastName,
|
||||
},
|
||||
);
|
||||
|
||||
const updatedUser = await this.getUserDetailsByUserUuid(userUuid);
|
||||
if (!updatedUser.firstName || !updatedUser.lastName) {
|
||||
throw new BadRequestException('First Name and Last Name update failed');
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: updatedUser.uuid,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
profilePicture: updatedUser.profilePicture,
|
||||
region: updatedUser.region,
|
||||
timeZoneUuid: updatedUser.timeZone,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new HttpException(
|
||||
err.message || 'User not found',
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,19 @@ import { Module } from '@nestjs/common';
|
||||
import { UserService } from './services/user.service';
|
||||
import { UserController } from './controllers/user.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
controllers: [UserController],
|
||||
providers: [UserService],
|
||||
providers: [
|
||||
UserService,
|
||||
UserRepository,
|
||||
RegionRepository,
|
||||
TimeZoneRepository,
|
||||
],
|
||||
exports: [UserService],
|
||||
})
|
||||
export class UserModule {}
|
||||
|
Reference in New Issue
Block a user