From 82a6677f92ebfd546a020de9f553c00a47728d5c Mon Sep 17 00:00:00 2001 From: TSLA Date: Sat, 27 Sep 2025 22:11:26 +0300 Subject: [PATCH 01/10] Fix: Subscription links username adding --- .../templates/replace-templates-values.ts | 4 +- .../generators/format-hosts.service.ts | 26 ++-- .../subscription/subscription.service.ts | 79 ++++++++-- .../users/controllers/users.controller.ts | 33 +++-- .../models/create-user.response.model.ts | 4 +- .../models/get-full-user.response.model.ts | 4 +- .../users/models/get-user.response.model.ts | 4 +- src/modules/users/users.service.ts | 136 +++++++++++++++--- 8 files changed, 232 insertions(+), 58 deletions(-) diff --git a/src/common/utils/templates/replace-templates-values.ts b/src/common/utils/templates/replace-templates-values.ts index 882ea4f9..84edcc0a 100644 --- a/src/common/utils/templates/replace-templates-values.ts +++ b/src/common/utils/templates/replace-templates-values.ts @@ -25,7 +25,7 @@ export class TemplateEngine { return hasReplacement ? result : template; } - static formatWithUser(template: string, user: UserEntity, subPublicDomain: string): string { + static formatWithUser(template: string, user: UserEntity, subscriptionLink: string): string { return this.replace(template, { DAYS_LEFT: Math.max(0, dayjs(user.expireAt).diff(dayjs(), 'day')), TRAFFIC_USED: prettyBytesUtil(user.usedTrafficBytes, true, 3), @@ -35,7 +35,7 @@ export class TemplateEngine { USERNAME: user.username, EMAIL: user.email || '', TELEGRAM_ID: user.telegramId?.toString() || '', - SUBSCRIPTION_URL: `https://${subPublicDomain}/${user.shortUuid}`, + SUBSCRIPTION_URL: subscriptionLink, TAG: user.tag || '', }); } diff --git a/src/modules/subscription-template/generators/format-hosts.service.ts b/src/modules/subscription-template/generators/format-hosts.service.ts index 19b57235..450d1eb1 100644 --- a/src/modules/subscription-template/generators/format-hosts.service.ts +++ b/src/modules/subscription-template/generators/format-hosts.service.ts @@ -23,6 +23,7 @@ import { SECURITY_LAYERS, USERS_STATUS } from '@libs/contracts/constants'; import { SubscriptionSettingsEntity } from '@modules/subscription-settings/entities/subscription-settings.entity'; import { GetSubscriptionSettingsQuery } from '@modules/subscription-settings/queries/get-subscription-settings'; import { HostWithRawInbound } from '@modules/hosts/entities/host-with-inbound-tag.entity'; +import { SubscriptionService } from '@modules/subscription/subscription.service'; import { UserEntity } from '@modules/users/entities'; import { IFormattedHost } from './interfaces/formatted-hosts.interface'; @@ -35,6 +36,7 @@ export class FormatHostsService { constructor( private readonly queryBus: QueryBus, private readonly configService: ConfigService, + private readonly subscriptionService: SubscriptionService, ) { this.nanoid = customAlphabet('0123456789abcdefghjkmnopqrstuvwxyz', 10); this.subPublicDomain = this.configService.getOrThrow('SUB_PUBLIC_DOMAIN'); @@ -49,12 +51,18 @@ export class FormatHostsService { let specialRemarks: string[] = []; - if (user.status !== USERS_STATUS.ACTIVE) { - const settings = await this.getSubscriptionSettings(); - if (!settings) { - return formattedHosts; - } + const settings = await this.getSubscriptionSettings(); + const subscriptionUrlResult = await this.subscriptionService.getUserSubscriptionLinkByUser( + user.shortUuid, + user.username, + ); + + if (!settings || !subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return formattedHosts; + } + const subscriptionUrl = subscriptionUrlResult.response; + if (user.status !== USERS_STATUS.ACTIVE) { if (settings.isShowCustomRemarks) { switch (user.status) { case USERS_STATUS.EXPIRED: @@ -69,7 +77,7 @@ export class FormatHostsService { } const templatedRemarks = specialRemarks.map((remark) => - TemplateEngine.formatWithUser(remark, user, this.subPublicDomain), + TemplateEngine.formatWithUser(remark, user, subscriptionUrl), ); formattedHosts.push(...this.createFallbackHosts(templatedRemarks)); @@ -109,11 +117,7 @@ export class FormatHostsService { const knownRemarks = new Map(); for (const inputHost of hosts) { - const remark = TemplateEngine.formatWithUser( - inputHost.remark, - user, - this.subPublicDomain, - ); + const remark = TemplateEngine.formatWithUser(inputHost.remark, user, subscriptionUrl); const currentCount = knownRemarks.get(remark) || 0; knownRemarks.set(remark, currentCount + 1); diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index a783ae07..6004e535 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -12,6 +12,7 @@ import { ConfigService } from '@nestjs/config'; import { TemplateEngine } from '@common/utils/templates/replace-templates-values'; import { prettyBytesUtil } from '@common/utils/bytes/pretty-bytes.util'; import { ICommandResponse } from '@common/types/command-response.type'; +import { errorHandler } from '@common/helpers/error-handler.helper'; import { HwidHeaders } from '@common/utils/extract-hwid-headers'; import { createHappCryptoLink } from '@common/utils'; import { @@ -74,6 +75,7 @@ export class SubscriptionService { private readonly formatHostsService: FormatHostsService, private readonly xrayGeneratorService: XrayGeneratorService, private readonly userSubscriptionRequestHistoryQueue: UserSubscriptionRequestHistoryQueueService, + private readonly subscriptionService: SubscriptionService, ) { this.hwidDeviceLimitEnabled = this.configService.getOrThrow('HWID_DEVICE_LIMIT_ENABLED') === 'true'; @@ -273,6 +275,13 @@ export class SubscriptionService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + user.response.shortUuid, + user.response.username, + ); + const subscriptionUrl = errorHandler(subscriptionUrlResult); + let isHwidLimited: boolean | undefined; const headers = await this.getUserProfileHeadersInfo( @@ -332,7 +341,7 @@ export class SubscriptionService { return { isOk: true, response: new RawSubscriptionWithHostsResponse({ - user: new GetUserResponseModel(user.response, this.subPublicDomain), + user: new GetUserResponseModel(user.response, subscriptionUrl), convertedUserInfo: { daysLeft: dayjs(user.response.expireAt).diff(dayjs(), 'day'), trafficUsed: prettyBytesUtil(user.response.usedTrafficBytes), @@ -677,6 +686,56 @@ export class SubscriptionService { } } + public async getUserSubscriptionLinkByUser( + userShortUuid: string, + username: string, + ): Promise> { + const settingEntity = await this.getCachedSubscriptionSettings(); + + if (!settingEntity) { + return { + isOk: false, + ...ERRORS.INTERNAL_SERVER_ERROR, + }; + } + + return { + isOk: true, + response: this.resolveSubscriptionUrl( + userShortUuid, + username, + settingEntity.addUsernameToBaseSubscription, + ), + }; + } + + public async getUsersSubscriptionLinkByUser( + users: Pick[], + ): Promise>> { + const settingEntity = await this.getCachedSubscriptionSettings(); + + if (!settingEntity) { + return { + isOk: false, + ...ERRORS.INTERNAL_SERVER_ERROR, + }; + } + + const linksEntries = users.map((user) => [ + user.shortUuid, + this.resolveSubscriptionUrl( + user.shortUuid, + user.username, + settingEntity.addUsernameToBaseSubscription, + ), + ]); + + return { + isOk: true, + response: Object.fromEntries(linksEntries), + }; + } + private async generateSsConfLinks( subscriptionShortUuid: string, formattedHosts: IFormattedHost[], @@ -703,11 +762,17 @@ export class SubscriptionService { isHapp: boolean, settings: SubscriptionSettingsEntity, ): Promise { + const subscriptionLink = this.resolveSubscriptionUrl( + user.shortUuid, + user.username, + settings.addUsernameToBaseSubscription, + ); + const headers: ISubscriptionHeaders = { 'content-disposition': `attachment; filename=${user.username}`, 'support-url': settings.supportLink, 'profile-title': `base64:${Buffer.from( - TemplateEngine.formatWithUser(settings.profileTitle, user, this.subPublicDomain), + TemplateEngine.formatWithUser(settings.profileTitle, user, subscriptionLink), ).toString('base64')}`, 'profile-update-interval': settings.profileUpdateInterval.toString(), 'subscription-userinfo': Object.entries(getSubscriptionUserInfo(user)) @@ -717,7 +782,7 @@ export class SubscriptionService { if (settings.happAnnounce) { headers.announce = `base64:${Buffer.from( - TemplateEngine.formatWithUser(settings.happAnnounce, user, this.subPublicDomain), + TemplateEngine.formatWithUser(settings.happAnnounce, user, subscriptionLink), ).toString('base64')}`; } @@ -726,11 +791,7 @@ export class SubscriptionService { } if (settings.isProfileWebpageUrlEnabled && !this.hwidDeviceLimitEnabled) { - headers['profile-web-page-url'] = this.resolveSubscriptionUrl( - user.shortUuid, - user.username, - settings.addUsernameToBaseSubscription, - ); + headers['profile-web-page-url'] = subscriptionLink; } const refillDate = getSubscriptionRefillDate(user.trafficLimitStrategy); @@ -740,7 +801,7 @@ export class SubscriptionService { if (settings.customResponseHeaders) { for (const [key, value] of Object.entries(settings.customResponseHeaders)) { - headers[key] = TemplateEngine.formatWithUser(value, user, this.subPublicDomain); + headers[key] = TemplateEngine.formatWithUser(value, user, subscriptionLink); } } diff --git a/src/modules/users/controllers/users.controller.ts b/src/modules/users/controllers/users.controller.ts index 806599c8..19d1fba9 100644 --- a/src/modules/users/controllers/users.controller.ts +++ b/src/modules/users/controllers/users.controller.ts @@ -114,7 +114,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new CreateUserResponseModel(data, this.subPublicDomain), + response: new CreateUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -132,7 +132,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetUserResponseModel(data, this.subPublicDomain), + response: new GetUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -193,7 +193,8 @@ export class UsersController { response: new GetAllUsersResponseModel({ total: data.total, users: data.users.map( - (item) => new GetFullUserResponseModel(item, this.subPublicDomain), + (item) => + new GetFullUserResponseModel(item, data.subscriptionUrls[item.shortUuid]), ), }), }; @@ -297,7 +298,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetFullUserResponseModel(data, this.subPublicDomain), + response: new GetFullUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -320,7 +321,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetFullUserResponseModel(data, this.subPublicDomain), + response: new GetFullUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -350,7 +351,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetFullUserResponseModel(data, this.subPublicDomain), + response: new GetFullUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -380,7 +381,9 @@ export class UsersController { const data = errorHandler(result); return { - response: data.map((item) => new GetFullUserResponseModel(item, this.subPublicDomain)), + response: data.users.map( + (item) => new GetFullUserResponseModel(item, data.subscriptionUrls[item.shortUuid]), + ), }; } @@ -410,7 +413,9 @@ export class UsersController { const data = errorHandler(result); return { - response: data.map((item) => new GetFullUserResponseModel(item, this.subPublicDomain)), + response: data.users.map( + (item) => new GetFullUserResponseModel(item, data.subscriptionUrls[item.shortUuid]), + ), }; } @@ -441,7 +446,9 @@ export class UsersController { const data = errorHandler(result); return { - response: data.map((item) => new GetFullUserResponseModel(item, this.subPublicDomain)), + response: data.users.map( + (item) => new GetFullUserResponseModel(item, data.subscriptionUrls[item.shortUuid]), + ), }; } @@ -474,7 +481,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetUserResponseModel(data, this.subPublicDomain), + response: new GetUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -495,7 +502,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetUserResponseModel(data, this.subPublicDomain), + response: new GetUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -516,7 +523,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetUserResponseModel(data, this.subPublicDomain), + response: new GetUserResponseModel(data.user, data.subscriptionUrl), }; } @@ -539,7 +546,7 @@ export class UsersController { const data = errorHandler(result); return { - response: new GetUserResponseModel(data, this.subPublicDomain), + response: new GetUserResponseModel(data.user, data.subscriptionUrl), }; } } diff --git a/src/modules/users/models/create-user.response.model.ts b/src/modules/users/models/create-user.response.model.ts index 9ab9722d..eee6cb85 100644 --- a/src/modules/users/models/create-user.response.model.ts +++ b/src/modules/users/models/create-user.response.model.ts @@ -44,7 +44,7 @@ export class CreateUserResponseModel { cryptoLink: string; }; - constructor(entity: UserEntity, subPublicDomain: string) { + constructor(entity: UserEntity, subscriptionUrl: string) { this.uuid = entity.uuid; this.username = entity.username; this.shortUuid = entity.shortUuid; @@ -75,7 +75,7 @@ export class CreateUserResponseModel { this.firstConnectedAt = entity.firstConnectedAt; this.lastTriggeredThreshold = entity.lastTriggeredThreshold; - this.subscriptionUrl = `https://${subPublicDomain}/${entity.shortUuid}`; + this.subscriptionUrl = subscriptionUrl; this.activeInternalSquads = entity.activeInternalSquads; this.lastConnectedNode = entity.lastConnectedNode; diff --git a/src/modules/users/models/get-full-user.response.model.ts b/src/modules/users/models/get-full-user.response.model.ts index c1541271..8ec3313a 100644 --- a/src/modules/users/models/get-full-user.response.model.ts +++ b/src/modules/users/models/get-full-user.response.model.ts @@ -48,7 +48,7 @@ export class GetFullUserResponseModel { cryptoLink: string; }; - constructor(entity: UserEntity, subPublicDomain: string) { + constructor(entity: UserEntity, subscriptionUrl: string) { this.uuid = entity.uuid; this.username = entity.username; this.shortUuid = entity.shortUuid; @@ -80,7 +80,7 @@ export class GetFullUserResponseModel { this.firstConnectedAt = entity.firstConnectedAt; this.lastTriggeredThreshold = entity.lastTriggeredThreshold; - this.subscriptionUrl = `https://${subPublicDomain}/${entity.shortUuid}`; + this.subscriptionUrl = subscriptionUrl; this.lastConnectedNode = entity.lastConnectedNode; this.activeInternalSquads = entity.activeInternalSquads; diff --git a/src/modules/users/models/get-user.response.model.ts b/src/modules/users/models/get-user.response.model.ts index 2410ca1d..27f2a2b8 100644 --- a/src/modules/users/models/get-user.response.model.ts +++ b/src/modules/users/models/get-user.response.model.ts @@ -47,7 +47,7 @@ export class GetUserResponseModel { cryptoLink: string; }; - constructor(entity: UserEntity, subPublicDomain: string) { + constructor(entity: UserEntity, subscriptionUrl: string) { this.uuid = entity.uuid; this.username = entity.username; this.shortUuid = entity.shortUuid; @@ -79,7 +79,7 @@ export class GetUserResponseModel { this.firstConnectedAt = entity.firstConnectedAt; this.lastTriggeredThreshold = entity.lastTriggeredThreshold; - this.subscriptionUrl = `https://${subPublicDomain}/${entity.shortUuid}`; + this.subscriptionUrl = subscriptionUrl; this.activeInternalSquads = entity.activeInternalSquads; this.lastConnectedNode = entity.lastConnectedNode; diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index b34aec89..0454406d 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -21,6 +21,7 @@ import { GetUserSubscriptionRequestHistoryQuery } from '@modules/user-subscripti import { CreateUserTrafficHistoryCommand } from '@modules/user-traffic-history/commands/create-user-traffic-history'; import { GetUserUsageByRangeQuery } from '@modules/nodes-user-usage-history/queries/get-user-usage-by-range'; import { RemoveUserFromNodeEvent } from '@modules/nodes/events/remove-user-from-node'; +import { SubscriptionService } from '@modules/subscription/subscription.service'; import { AddUserToNodeEvent } from '@modules/nodes/events/add-user-to-node'; import { UserTrafficHistoryEntity } from '@modules/user-traffic-history'; @@ -68,16 +69,29 @@ export class UsersService { private readonly startAllNodesQueue: StartAllNodesQueueService, private readonly resetUserTrafficQueueService: ResetUserTrafficQueueService, private readonly userActionsQueueService: UserActionsQueueService, + private readonly subscriptionService: SubscriptionService, ) { this.shortUuidLength = this.configService.getOrThrow('SHORT_UUID_LENGTH'); } - public async createUser(dto: CreateUserRequestDto): Promise> { + public async createUser( + dto: CreateUserRequestDto, + ): Promise> { try { const user = await this.createUserTransactional(dto); if (!user.isOk || !user.response) { - return user; + return { ...user, response: undefined }; + } + + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + user.response.shortUuid, + user.response.username, + ); + + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; } if (user.response.status === USERS_STATUS.ACTIVE) { @@ -88,7 +102,13 @@ export class UsersService { EVENTS.USER.CREATED, new UserEvent(user.response, EVENTS.USER.CREATED), ); - return user; + return { + isOk: true, + response: { + user: user.response, + subscriptionUrl: subscriptionUrlResult.response, + }, + }; } catch (error) { this.logger.error(error); if ( @@ -113,7 +133,9 @@ export class UsersService { } } - public async updateUser(dto: UpdateUserRequestDto): Promise> { + public async updateUser( + dto: UpdateUserRequestDto, + ): Promise> { try { const user = await this.updateUserTransactional(dto); @@ -131,6 +153,16 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + user.response.user.shortUuid, + user.response.user.username, + ); + + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + if ( user.response.user.status === USERS_STATUS.ACTIVE && user.response.isNeedToBeAddedToNode @@ -154,7 +186,10 @@ export class UsersService { return { isOk: true, - response: user.response.user, + response: { + user: user.response.user, + subscriptionUrl: subscriptionUrlResult.response, + }, }; } catch (error) { this.logger.error(error); @@ -398,16 +433,24 @@ export class UsersService { ICommandResponse<{ total: number; users: UserEntity[]; + subscriptionUrls: Record; }> > { try { const [users, total] = await this.userRepository.getAllUsersV2(dto); + const subscriptionUrlsResult = + await this.subscriptionService.getUsersSubscriptionLinkByUser(users); + if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { + return { ...subscriptionUrlsResult, response: undefined }; + } + return { isOk: true, response: { users, total, + subscriptionUrls: subscriptionUrlsResult.response, }, }; } catch (error) { @@ -421,7 +464,7 @@ export class UsersService { public async getUserByUniqueFields( dto: IGetUserByUnique, - ): Promise> { + ): Promise> { try { const result = await this.userRepository.findUniqueByCriteria({ username: dto.username || undefined, @@ -436,9 +479,18 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + result.shortUuid, + result.username, + ); + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + return { isOk: true, - response: result, + response: { user: result, subscriptionUrl: subscriptionUrlResult.response }, }; } catch (error) { this.logger.error(error); @@ -451,7 +503,9 @@ export class UsersService { public async getUsersByNonUniqueFields( dto: IGetUsersByTelegramIdOrEmail, - ): Promise> { + ): Promise< + ICommandResponse<{ users: UserEntity[]; subscriptionUrls: Record }> + > { try { const result = await this.userRepository.findByNonUniqueCriteria({ email: dto.email || undefined, @@ -466,9 +520,15 @@ export class UsersService { }; } + const subscriptionUrlsResult = + await this.subscriptionService.getUsersSubscriptionLinkByUser(result); + if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { + return { ...subscriptionUrlsResult, response: undefined }; + } + return { isOk: true, - response: result, + response: { users: result, subscriptionUrls: subscriptionUrlsResult.response }, }; } catch (error) { this.logger.error(error); @@ -482,7 +542,7 @@ export class UsersService { public async revokeUserSubscription( userUuid: string, shortUuid?: string, - ): Promise> { + ): Promise> { try { const user = await this.userRepository.getPartialUserByUniqueFields( { uuid: userUuid }, @@ -521,6 +581,15 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + updatedUser.shortUuid, + updatedUser.username, + ); + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + if (updatedUser.status === USERS_STATUS.ACTIVE) { this.eventBus.publish(new AddUserToNodeEvent(updatedUser.uuid, user.vlessUuid)); } @@ -532,7 +601,7 @@ export class UsersService { return { isOk: true, - response: updatedUser, + response: { user: updatedUser, subscriptionUrl: subscriptionUrlResult.response }, }; } catch (error) { this.logger.error(error); @@ -575,7 +644,9 @@ export class UsersService { } } - public async disableUser(userUuid: string): Promise> { + public async disableUser( + userUuid: string, + ): Promise> { try { const user = await this.userRepository.getPartialUserByUniqueFields( { uuid: userUuid }, @@ -607,6 +678,15 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + updatedUser.shortUuid, + updatedUser.username, + ); + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + this.eventBus.publish( new RemoveUserFromNodeEvent(updatedUser.username, updatedUser.vlessUuid), ); @@ -617,7 +697,7 @@ export class UsersService { return { isOk: true, - response: updatedUser, + response: { user: updatedUser, subscriptionUrl: subscriptionUrlResult.response }, }; } catch (error) { this.logger.error(error); @@ -628,7 +708,9 @@ export class UsersService { } } - public async enableUser(userUuid: string): Promise> { + public async enableUser( + userUuid: string, + ): Promise> { try { const user = await this.userRepository.getPartialUserByUniqueFields( { uuid: userUuid }, @@ -660,6 +742,15 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + updatedUser.shortUuid, + updatedUser.username, + ); + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + this.eventBus.publish(new AddUserToNodeEvent(user.uuid)); this.eventEmitter.emit( @@ -669,7 +760,7 @@ export class UsersService { return { isOk: true, - response: updatedUser, + response: { user: updatedUser, subscriptionUrl: subscriptionUrlResult.response }, }; } catch (error) { this.logger.error(error); @@ -681,7 +772,9 @@ export class UsersService { } @Transactional() - public async resetUserTraffic(userUuid: string): Promise> { + public async resetUserTraffic( + userUuid: string, + ): Promise> { try { const user = await this.userRepository.getPartialUserByUniqueFields( { uuid: userUuid }, @@ -730,6 +823,15 @@ export class UsersService { }; } + const subscriptionUrlResult = + await this.subscriptionService.getUserSubscriptionLinkByUser( + newUser.shortUuid, + newUser.username, + ); + if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + return { ...subscriptionUrlResult, response: undefined }; + } + if (user.status === USERS_STATUS.LIMITED) { this.eventEmitter.emit( EVENTS.USER.ENABLED, @@ -744,7 +846,7 @@ export class UsersService { return { isOk: true, - response: newUser, + response: { user: newUser, subscriptionUrl: subscriptionUrlResult.response }, }; } catch (error) { this.logger.error(error); From 77024bb03c591d80870a5864febc4c09166b6e88 Mon Sep 17 00:00:00 2001 From: TSLA Date: Sun, 28 Sep 2025 00:17:43 +0300 Subject: [PATCH 02/10] Fix: Using commands --- .../generators/format-hosts.service.ts | 35 +++++++++++++------ .../get-subscription-url.handler.ts | 20 +++++++++++ .../get-subscription-url.query.ts | 6 ++++ .../queries/get-subscription-url/index.ts | 2 ++ src/modules/subscription/queries/index.ts | 3 ++ .../subscription/subscription.module.ts | 2 +- .../subscription/subscription.service.ts | 13 +++---- src/modules/users/users.module.ts | 8 +++-- 8 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts create mode 100644 src/modules/subscription/queries/get-subscription-url/get-subscription-url.query.ts create mode 100644 src/modules/subscription/queries/get-subscription-url/index.ts create mode 100644 src/modules/subscription/queries/index.ts diff --git a/src/modules/subscription-template/generators/format-hosts.service.ts b/src/modules/subscription-template/generators/format-hosts.service.ts index 450d1eb1..7b96edc5 100644 --- a/src/modules/subscription-template/generators/format-hosts.service.ts +++ b/src/modules/subscription-template/generators/format-hosts.service.ts @@ -2,17 +2,16 @@ import { randomUUID } from 'node:crypto'; import { customAlphabet } from 'nanoid'; import { ConfigService } from '@nestjs/config'; -import { Injectable } from '@nestjs/common'; import { QueryBus } from '@nestjs/cqrs'; import { HttpUpgradeObject, + RawObject, StreamSettingsObject, TcpObject, WebSocketObject, xHttpObject, } from '@common/helpers/xray-config/interfaces/transport.config'; -import { RawObject } from '@common/helpers/xray-config/interfaces/transport.config'; import { TemplateEngine } from '@common/utils/templates/replace-templates-values'; import { resolveInboundAndPublicKey } from '@common/helpers/xray-config'; import { ICommandResponse } from '@common/types/command-response.type'; @@ -23,10 +22,11 @@ import { SECURITY_LAYERS, USERS_STATUS } from '@libs/contracts/constants'; import { SubscriptionSettingsEntity } from '@modules/subscription-settings/entities/subscription-settings.entity'; import { GetSubscriptionSettingsQuery } from '@modules/subscription-settings/queries/get-subscription-settings'; import { HostWithRawInbound } from '@modules/hosts/entities/host-with-inbound-tag.entity'; -import { SubscriptionService } from '@modules/subscription/subscription.service'; import { UserEntity } from '@modules/users/entities'; import { IFormattedHost } from './interfaces/formatted-hosts.interface'; +import { Injectable } from '@nestjs/common'; +import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; @Injectable() export class FormatHostsService { @@ -36,7 +36,6 @@ export class FormatHostsService { constructor( private readonly queryBus: QueryBus, private readonly configService: ConfigService, - private readonly subscriptionService: SubscriptionService, ) { this.nanoid = customAlphabet('0123456789abcdefghjkmnopqrstuvwxyz', 10); this.subPublicDomain = this.configService.getOrThrow('SUB_PUBLIC_DOMAIN'); @@ -52,15 +51,16 @@ export class FormatHostsService { let specialRemarks: string[] = []; const settings = await this.getSubscriptionSettings(); - const subscriptionUrlResult = await this.subscriptionService.getUserSubscriptionLinkByUser( - user.shortUuid, - user.username, - ); + // const subscriptionUrlResult = await this.subscriptionService.getUserSubscriptionLinkByUser( + // user.shortUuid, + // user.username, + // ); - if (!settings || !subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { + const subscriptionUrl = await this.getSubscriptionUrl(user.shortUuid, user.username); + + if (!settings || !subscriptionUrl) { return formattedHosts; } - const subscriptionUrl = subscriptionUrlResult.response; if (user.status !== USERS_STATUS.ACTIVE) { if (settings.isShowCustomRemarks) { @@ -419,6 +419,21 @@ export class FormatHostsService { return settingsResponse.response; } + private async getSubscriptionUrl( + userShortUuid: string, + username: string, + ): Promise { + const url = await this.queryBus.execute>( + new GetSubscriptionUrlQuery(userShortUuid, username), + ); + + if (!url.isOk || !url.response) { + return null; + } + + return url.response; + } + private createFallbackHosts(remarks: string[]): IFormattedHost[] { return remarks.map((remark) => ({ remark, diff --git a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts new file mode 100644 index 00000000..ec4545db --- /dev/null +++ b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts @@ -0,0 +1,20 @@ +import { IQueryHandler, QueryHandler } from '@nestjs/cqrs'; + +import { ICommandResponse } from '@common/types/command-response.type'; + +import { GetSubscriptionUrlQuery } from './get-subscription-url.query'; +import { SubscriptionService } from '@modules/subscription/subscription.service'; + +@QueryHandler(GetSubscriptionUrlQuery) +export class GetSubscriptionUrlHandler + implements IQueryHandler> +{ + constructor(private readonly subscriptionService: SubscriptionService) {} + + async execute(query: GetSubscriptionUrlQuery): Promise> { + return this.subscriptionService.getUserSubscriptionLinkByUser( + query.userShortUuid, + query.username, + ); + } +} diff --git a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.query.ts b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.query.ts new file mode 100644 index 00000000..99ebf403 --- /dev/null +++ b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.query.ts @@ -0,0 +1,6 @@ +export class GetSubscriptionUrlQuery { + constructor( + public readonly userShortUuid: string, + public readonly username: string, + ) {} +} diff --git a/src/modules/subscription/queries/get-subscription-url/index.ts b/src/modules/subscription/queries/get-subscription-url/index.ts new file mode 100644 index 00000000..bce1a609 --- /dev/null +++ b/src/modules/subscription/queries/get-subscription-url/index.ts @@ -0,0 +1,2 @@ +export * from './get-subscription-url.handler'; +export * from './get-subscription-url.query'; diff --git a/src/modules/subscription/queries/index.ts b/src/modules/subscription/queries/index.ts new file mode 100644 index 00000000..c4b4e6b1 --- /dev/null +++ b/src/modules/subscription/queries/index.ts @@ -0,0 +1,3 @@ +import { GetSubscriptionUrlHandler } from './get-subscription-url'; + +export const QUERIES = [GetSubscriptionUrlHandler]; diff --git a/src/modules/subscription/subscription.module.ts b/src/modules/subscription/subscription.module.ts index c3660163..99c73afc 100644 --- a/src/modules/subscription/subscription.module.ts +++ b/src/modules/subscription/subscription.module.ts @@ -12,7 +12,7 @@ import { SubscriptionService } from './subscription.service'; imports: [CqrsModule, SubscriptionTemplateModule], controllers: [SubscriptionController, SubscriptionsController], providers: [SubscriptionService], - exports: [], + exports: [SubscriptionService], }) export class SubscriptionModule implements NestModule { configure(consumer: MiddlewareConsumer) { diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index 6004e535..9d8bc781 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -12,7 +12,6 @@ import { ConfigService } from '@nestjs/config'; import { TemplateEngine } from '@common/utils/templates/replace-templates-values'; import { prettyBytesUtil } from '@common/utils/bytes/pretty-bytes.util'; import { ICommandResponse } from '@common/types/command-response.type'; -import { errorHandler } from '@common/helpers/error-handler.helper'; import { HwidHeaders } from '@common/utils/extract-hwid-headers'; import { createHappCryptoLink } from '@common/utils'; import { @@ -75,7 +74,6 @@ export class SubscriptionService { private readonly formatHostsService: FormatHostsService, private readonly xrayGeneratorService: XrayGeneratorService, private readonly userSubscriptionRequestHistoryQueue: UserSubscriptionRequestHistoryQueueService, - private readonly subscriptionService: SubscriptionService, ) { this.hwidDeviceLimitEnabled = this.configService.getOrThrow('HWID_DEVICE_LIMIT_ENABLED') === 'true'; @@ -275,12 +273,11 @@ export class SubscriptionService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - user.response.shortUuid, - user.response.username, - ); - const subscriptionUrl = errorHandler(subscriptionUrlResult); + const subscriptionUrl = this.resolveSubscriptionUrl( + user.response.shortUuid, + user.response.username, + settingEntity.addUsernameToBaseSubscription, + ); let isHwidLimited: boolean | undefined; diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 62787bee..b5abb3f8 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -1,16 +1,18 @@ import { CqrsModule } from '@nestjs/cqrs'; import { Module } from '@nestjs/common'; -import { UsersController, UsersBulkActionsController, UsersStatsController } from './controllers'; +import { UsersBulkActionsController, UsersController, UsersStatsController } from './controllers'; import { UsersRepository } from './repositories/users.repository'; import { UserConverter } from './users.converter'; import { UsersService } from './users.service'; import { COMMANDS } from './commands'; import { QUERIES } from './queries'; +import { SubscriptionModule } from '@modules/subscription/subscription.module'; + @Module({ - imports: [CqrsModule], + imports: [CqrsModule, SubscriptionModule], controllers: [UsersController, UsersBulkActionsController, UsersStatsController], providers: [UsersRepository, UserConverter, UsersService, ...QUERIES, ...COMMANDS], exports: [], }) -export class UsersModule {} +export class UsersModule {} \ No newline at end of file From c12f7a23bdff2ed1b70852c29091cf5b47ed06bd Mon Sep 17 00:00:00 2001 From: TSLA Date: Sun, 28 Sep 2025 05:58:17 +0300 Subject: [PATCH 03/10] Fix: Using Queries --- .../generators/format-hosts.service.ts | 48 ++++++++++--------- .../get-subscription-url.handler.ts | 3 +- .../subscription/subscription.module.ts | 3 +- .../subscription/subscription.service.ts | 38 ++++++++------- .../utils/resolve-subscription-url.ts | 12 +++++ 5 files changed, 63 insertions(+), 41 deletions(-) create mode 100644 src/modules/subscription/utils/resolve-subscription-url.ts diff --git a/src/modules/subscription-template/generators/format-hosts.service.ts b/src/modules/subscription-template/generators/format-hosts.service.ts index 7b96edc5..a2dfe52c 100644 --- a/src/modules/subscription-template/generators/format-hosts.service.ts +++ b/src/modules/subscription-template/generators/format-hosts.service.ts @@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto'; import { customAlphabet } from 'nanoid'; import { ConfigService } from '@nestjs/config'; +import { Injectable } from '@nestjs/common'; import { QueryBus } from '@nestjs/cqrs'; import { @@ -21,12 +22,12 @@ import { SECURITY_LAYERS, USERS_STATUS } from '@libs/contracts/constants'; import { SubscriptionSettingsEntity } from '@modules/subscription-settings/entities/subscription-settings.entity'; import { GetSubscriptionSettingsQuery } from '@modules/subscription-settings/queries/get-subscription-settings'; +// import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; +import { resolveSubscriptionUrl } from '@modules/subscription/utils/resolve-subscription-url'; import { HostWithRawInbound } from '@modules/hosts/entities/host-with-inbound-tag.entity'; import { UserEntity } from '@modules/users/entities'; import { IFormattedHost } from './interfaces/formatted-hosts.interface'; -import { Injectable } from '@nestjs/common'; -import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; @Injectable() export class FormatHostsService { @@ -51,17 +52,18 @@ export class FormatHostsService { let specialRemarks: string[] = []; const settings = await this.getSubscriptionSettings(); - // const subscriptionUrlResult = await this.subscriptionService.getUserSubscriptionLinkByUser( - // user.shortUuid, - // user.username, - // ); - - const subscriptionUrl = await this.getSubscriptionUrl(user.shortUuid, user.username); - if (!settings || !subscriptionUrl) { + if (!settings) { return formattedHosts; } + const subscriptionUrl = resolveSubscriptionUrl( + user.shortUuid, + user.username, + settings?.addUsernameToBaseSubscription, + this.subPublicDomain, + ); + if (user.status !== USERS_STATUS.ACTIVE) { if (settings.isShowCustomRemarks) { switch (user.status) { @@ -419,20 +421,20 @@ export class FormatHostsService { return settingsResponse.response; } - private async getSubscriptionUrl( - userShortUuid: string, - username: string, - ): Promise { - const url = await this.queryBus.execute>( - new GetSubscriptionUrlQuery(userShortUuid, username), - ); - - if (!url.isOk || !url.response) { - return null; - } - - return url.response; - } + // private async getSubscriptionUrl( + // userShortUuid: string, + // username: string, + // ): Promise { + // const url = await this.queryBus.execute>( + // new GetSubscriptionUrlQuery(userShortUuid, username), + // ); + // + // if (!url.isOk || !url.response) { + // return null; + // } + // + // return url.response; + // } private createFallbackHosts(remarks: string[]): IFormattedHost[] { return remarks.map((remark) => ({ diff --git a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts index ec4545db..1c3eeff2 100644 --- a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts +++ b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts @@ -2,9 +2,10 @@ import { IQueryHandler, QueryHandler } from '@nestjs/cqrs'; import { ICommandResponse } from '@common/types/command-response.type'; -import { GetSubscriptionUrlQuery } from './get-subscription-url.query'; import { SubscriptionService } from '@modules/subscription/subscription.service'; +import { GetSubscriptionUrlQuery } from './get-subscription-url.query'; + @QueryHandler(GetSubscriptionUrlQuery) export class GetSubscriptionUrlHandler implements IQueryHandler> diff --git a/src/modules/subscription/subscription.module.ts b/src/modules/subscription/subscription.module.ts index 99c73afc..a6dcb0b6 100644 --- a/src/modules/subscription/subscription.module.ts +++ b/src/modules/subscription/subscription.module.ts @@ -4,6 +4,7 @@ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { CqrsModule } from '@nestjs/cqrs'; import { SubscriptionTemplateModule } from '@modules/subscription-template/subscription-template.module'; +import { QUERIES } from '@modules/subscription/queries'; import { SubscriptionController, SubscriptionsController } from './controllers'; import { SubscriptionService } from './subscription.service'; @@ -11,7 +12,7 @@ import { SubscriptionService } from './subscription.service'; @Module({ imports: [CqrsModule, SubscriptionTemplateModule], controllers: [SubscriptionController, SubscriptionsController], - providers: [SubscriptionService], + providers: [SubscriptionService, ...QUERIES], exports: [SubscriptionService], }) export class SubscriptionModule implements NestModule { diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index 9d8bc781..16806e89 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -56,6 +56,7 @@ import { HostWithRawInbound } from '../hosts/entities/host-with-inbound-tag.enti import { ISubscriptionHeaders } from './interfaces/subscription-headers.interface'; import { GetHostsForUserQuery } from '../hosts/queries/get-hosts-for-user'; import { GetAllSubscriptionsQueryDto } from './dto'; +import { resolveSubscriptionUrl } from '@modules/subscription/utils/resolve-subscription-url'; @Injectable() export class SubscriptionService { @@ -273,10 +274,11 @@ export class SubscriptionService { }; } - const subscriptionUrl = this.resolveSubscriptionUrl( + const subscriptionUrl = resolveSubscriptionUrl( user.response.shortUuid, user.response.username, settingEntity.addUsernameToBaseSubscription, + this.subPublicDomain, ); let isHwidLimited: boolean | undefined; @@ -523,10 +525,11 @@ export class SubscriptionService { ssConfLinks: Record, settingEntity: SubscriptionSettingsEntity, ): Promise { - const subscriptionUrl = this.resolveSubscriptionUrl( + const subscriptionUrl = resolveSubscriptionUrl( user.shortUuid, user.username, settingEntity.addUsernameToBaseSubscription, + this.subPublicDomain, ); return new SubscriptionRawResponse({ @@ -698,10 +701,11 @@ export class SubscriptionService { return { isOk: true, - response: this.resolveSubscriptionUrl( + response: resolveSubscriptionUrl( userShortUuid, username, settingEntity.addUsernameToBaseSubscription, + this.subPublicDomain, ), }; } @@ -720,10 +724,11 @@ export class SubscriptionService { const linksEntries = users.map((user) => [ user.shortUuid, - this.resolveSubscriptionUrl( + resolveSubscriptionUrl( user.shortUuid, user.username, settingEntity.addUsernameToBaseSubscription, + this.subPublicDomain, ), ]); @@ -759,10 +764,11 @@ export class SubscriptionService { isHapp: boolean, settings: SubscriptionSettingsEntity, ): Promise { - const subscriptionLink = this.resolveSubscriptionUrl( + const subscriptionLink = resolveSubscriptionUrl( user.shortUuid, user.username, settings.addUsernameToBaseSubscription, + this.subPublicDomain, ); const headers: ISubscriptionHeaders = { @@ -1004,17 +1010,17 @@ export class SubscriptionService { } } - private resolveSubscriptionUrl( - shortUuid: string, - username: string, - addUsernameToBaseSubscription: boolean, - ): string { - if (addUsernameToBaseSubscription) { - return `https://${this.subPublicDomain}/${shortUuid}#${username}`; - } - - return `https://${this.subPublicDomain}/${shortUuid}`; - } + // private resolveSubscriptionUrl( + // shortUuid: string, + // username: string, + // addUsernameToBaseSubscription: boolean, + // ): string { + // if (addUsernameToBaseSubscription) { + // return `https://${this.subPublicDomain}/${shortUuid}#${username}`; + // } + // + // return `https://${this.subPublicDomain}/${shortUuid}`; + // } private async updateAndReportSubscriptionRequest( userUuid: string, diff --git a/src/modules/subscription/utils/resolve-subscription-url.ts b/src/modules/subscription/utils/resolve-subscription-url.ts new file mode 100644 index 00000000..4e1ba136 --- /dev/null +++ b/src/modules/subscription/utils/resolve-subscription-url.ts @@ -0,0 +1,12 @@ +export const resolveSubscriptionUrl = ( + shortUuid: string, + username: string, + addUsernameToBaseSubscription: boolean, + subPublicDomain: string, +): string => { + if (addUsernameToBaseSubscription) { + return `https://${subPublicDomain}/${shortUuid}#${username}`; + } + + return `https://${subPublicDomain}/${shortUuid}`; +}; From b4cb015d08a964aec2b548b571af4ad3442b798f Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 04:48:45 +0300 Subject: [PATCH 04/10] Fix: Using Queries --- .../generators/format-hosts.service.ts | 2 + .../subscription/subscription.module.ts | 2 +- .../subscription/subscription.service.ts | 2 +- src/modules/users/users.module.ts | 6 +- src/modules/users/users.service.ts | 90 ++++++++++--------- 5 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/modules/subscription-template/generators/format-hosts.service.ts b/src/modules/subscription-template/generators/format-hosts.service.ts index a2dfe52c..8587fdc7 100644 --- a/src/modules/subscription-template/generators/format-hosts.service.ts +++ b/src/modules/subscription-template/generators/format-hosts.service.ts @@ -52,7 +52,9 @@ export class FormatHostsService { let specialRemarks: string[] = []; const settings = await this.getSubscriptionSettings(); + // const subscriptionUrl = await this.getSubscriptionUrl(user.shortUuid, user.username); + // if (!settings || !subscriptionUrl) { if (!settings) { return formattedHosts; } diff --git a/src/modules/subscription/subscription.module.ts b/src/modules/subscription/subscription.module.ts index a6dcb0b6..adb699aa 100644 --- a/src/modules/subscription/subscription.module.ts +++ b/src/modules/subscription/subscription.module.ts @@ -13,7 +13,7 @@ import { SubscriptionService } from './subscription.service'; imports: [CqrsModule, SubscriptionTemplateModule], controllers: [SubscriptionController, SubscriptionsController], providers: [SubscriptionService, ...QUERIES], - exports: [SubscriptionService], + exports: [], }) export class SubscriptionModule implements NestModule { configure(consumer: MiddlewareConsumer) { diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index 16806e89..404409cc 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -37,6 +37,7 @@ import { RenderTemplatesService } from '@modules/subscription-template/render-te import { CountUsersDevicesQuery } from '@modules/hwid-user-devices/queries/count-users-devices'; import { IFormattedHost, IRawHost } from '@modules/subscription-template/generators/interfaces'; import { GetUsersWithPaginationQuery } from '@modules/users/queries/get-users-with-pagination'; +import { resolveSubscriptionUrl } from '@modules/subscription/utils/resolve-subscription-url'; import { CheckHwidExistsQuery } from '@modules/hwid-user-devices/queries/check-hwid-exists'; import { GetUserByUniqueFieldQuery } from '@modules/users/queries/get-user-by-unique-field'; import { UserEntity } from '@modules/users/entities/user.entity'; @@ -56,7 +57,6 @@ import { HostWithRawInbound } from '../hosts/entities/host-with-inbound-tag.enti import { ISubscriptionHeaders } from './interfaces/subscription-headers.interface'; import { GetHostsForUserQuery } from '../hosts/queries/get-hosts-for-user'; import { GetAllSubscriptionsQueryDto } from './dto'; -import { resolveSubscriptionUrl } from '@modules/subscription/utils/resolve-subscription-url'; @Injectable() export class SubscriptionService { diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index b5abb3f8..9cd62303 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -7,12 +7,10 @@ import { UserConverter } from './users.converter'; import { UsersService } from './users.service'; import { COMMANDS } from './commands'; import { QUERIES } from './queries'; -import { SubscriptionModule } from '@modules/subscription/subscription.module'; - @Module({ - imports: [CqrsModule, SubscriptionModule], + imports: [CqrsModule], controllers: [UsersController, UsersBulkActionsController, UsersStatsController], providers: [UsersRepository, UserConverter, UsersService, ...QUERIES, ...COMMANDS], exports: [], }) -export class UsersModule {} \ No newline at end of file +export class UsersModule {} diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index 0454406d..a38209e3 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -20,8 +20,9 @@ import { UserEvent } from '@integration-modules/notifications/interfaces'; import { GetUserSubscriptionRequestHistoryQuery } from '@modules/user-subscription-request-history/queries/get-user-subscription-request-history'; import { CreateUserTrafficHistoryCommand } from '@modules/user-traffic-history/commands/create-user-traffic-history'; import { GetUserUsageByRangeQuery } from '@modules/nodes-user-usage-history/queries/get-user-usage-by-range'; +import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; import { RemoveUserFromNodeEvent } from '@modules/nodes/events/remove-user-from-node'; -import { SubscriptionService } from '@modules/subscription/subscription.service'; +// import { SubscriptionService } from '@modules/subscription/subscription.service'; import { AddUserToNodeEvent } from '@modules/nodes/events/add-user-to-node'; import { UserTrafficHistoryEntity } from '@modules/user-traffic-history'; @@ -69,7 +70,7 @@ export class UsersService { private readonly startAllNodesQueue: StartAllNodesQueueService, private readonly resetUserTrafficQueueService: ResetUserTrafficQueueService, private readonly userActionsQueueService: UserActionsQueueService, - private readonly subscriptionService: SubscriptionService, + // private readonly subscriptionService: SubscriptionService, ) { this.shortUuidLength = this.configService.getOrThrow('SHORT_UUID_LENGTH'); } @@ -84,11 +85,10 @@ export class UsersService { return { ...user, response: undefined }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - user.response.shortUuid, - user.response.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + user.response.shortUuid, + user.response.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; @@ -153,11 +153,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - user.response.user.shortUuid, - user.response.user.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + user.response.user.shortUuid, + user.response.user.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; @@ -439,8 +438,7 @@ export class UsersService { try { const [users, total] = await this.userRepository.getAllUsersV2(dto); - const subscriptionUrlsResult = - await this.subscriptionService.getUsersSubscriptionLinkByUser(users); + const subscriptionUrlsResult = await this.getUsersSubscriptionLink(users); if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { return { ...subscriptionUrlsResult, response: undefined }; } @@ -479,11 +477,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - result.shortUuid, - result.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + result.shortUuid, + result.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; } @@ -520,8 +517,7 @@ export class UsersService { }; } - const subscriptionUrlsResult = - await this.subscriptionService.getUsersSubscriptionLinkByUser(result); + const subscriptionUrlsResult = await this.getUsersSubscriptionLink(result); if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { return { ...subscriptionUrlsResult, response: undefined }; } @@ -581,11 +577,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - updatedUser.shortUuid, - updatedUser.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + updatedUser.shortUuid, + updatedUser.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; } @@ -678,11 +673,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - updatedUser.shortUuid, - updatedUser.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + updatedUser.shortUuid, + updatedUser.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; } @@ -742,11 +736,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - updatedUser.shortUuid, - updatedUser.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + updatedUser.shortUuid, + updatedUser.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; } @@ -823,11 +816,10 @@ export class UsersService { }; } - const subscriptionUrlResult = - await this.subscriptionService.getUserSubscriptionLinkByUser( - newUser.shortUuid, - newUser.username, - ); + const subscriptionUrlResult = await this.getUserSubscriptionLink( + newUser.shortUuid, + newUser.username, + ); if (!subscriptionUrlResult.isOk || !subscriptionUrlResult.response) { return { ...subscriptionUrlResult, response: undefined }; } @@ -1255,4 +1247,20 @@ export class UsersService { ICommandResponse >(new GetUserUsageByRangeQuery(userUuid, start, end)); } + + private getUserSubscriptionLink = async ( + shortUuid: string, + username: string, + ): Promise> => { + // return { isOk: true, response: 'Sublink' }; + return this.queryBus.execute>( + new GetSubscriptionUrlQuery(shortUuid, username), + ); + }; + + private getUsersSubscriptionLink = async ( + users: Pick[], + ): Promise>> => { + return { isOk: true, response: { user: 'Sublinks' } }; + }; } From 02ea80d2c583a163942e22d096fcffd2fcacde83 Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 06:14:50 +0300 Subject: [PATCH 05/10] Fix: Debugging --- src/modules/users/users.service.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index a38209e3..664ddd17 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -485,6 +485,13 @@ export class UsersService { return { ...subscriptionUrlResult, response: undefined }; } + this.logger.error( + 'GET by uunic', + result.shortUuid, + result.username, + subscriptionUrlResult.response, + ); + return { isOk: true, response: { user: result, subscriptionUrl: subscriptionUrlResult.response }, From 67f04acf97e4bdf88da5007e4ae49a0c9402d5b5 Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 08:29:38 +0300 Subject: [PATCH 06/10] Fix: Using Query for multiple users --- .../get-users-subscription-url.handler.ts | 20 +++++++++++++++++++ .../get-users-subscription-url.query.ts | 5 +++++ .../get-users-subscription-url/index.ts | 2 ++ src/modules/subscription/queries/index.ts | 3 ++- src/modules/users/users.service.ts | 7 +++++-- 5 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts create mode 100644 src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.query.ts create mode 100644 src/modules/subscription/queries/get-users-subscription-url/index.ts diff --git a/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts new file mode 100644 index 00000000..b2cf9674 --- /dev/null +++ b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts @@ -0,0 +1,20 @@ +import { IQueryHandler, QueryHandler } from '@nestjs/cqrs'; + +import { ICommandResponse } from '@common/types/command-response.type'; + +import { SubscriptionService } from '@modules/subscription/subscription.service'; + +import { GetUsersSubscriptionUrlQuery } from './get-users-subscription-url.query'; + +@QueryHandler(GetUsersSubscriptionUrlQuery) +export class GetUsersSubscriptionUrlHandler + implements IQueryHandler>> +{ + constructor(private readonly subscriptionService: SubscriptionService) {} + + async execute( + query: GetUsersSubscriptionUrlQuery, + ): Promise>> { + return this.subscriptionService.getUsersSubscriptionLinkByUser(query.users); + } +} diff --git a/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.query.ts b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.query.ts new file mode 100644 index 00000000..22144a4b --- /dev/null +++ b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.query.ts @@ -0,0 +1,5 @@ +import { UserEntity } from '@modules/users/entities'; + +export class GetUsersSubscriptionUrlQuery { + constructor(public readonly users: Pick[]) {} +} diff --git a/src/modules/subscription/queries/get-users-subscription-url/index.ts b/src/modules/subscription/queries/get-users-subscription-url/index.ts new file mode 100644 index 00000000..4d7f7606 --- /dev/null +++ b/src/modules/subscription/queries/get-users-subscription-url/index.ts @@ -0,0 +1,2 @@ +export * from './get-users-subscription-url.handler'; +export * from './get-users-subscription-url.query'; diff --git a/src/modules/subscription/queries/index.ts b/src/modules/subscription/queries/index.ts index c4b4e6b1..ea5cf0ad 100644 --- a/src/modules/subscription/queries/index.ts +++ b/src/modules/subscription/queries/index.ts @@ -1,3 +1,4 @@ +import { GetUsersSubscriptionUrlHandler } from './get-users-subscription-url'; import { GetSubscriptionUrlHandler } from './get-subscription-url'; -export const QUERIES = [GetSubscriptionUrlHandler]; +export const QUERIES = [GetSubscriptionUrlHandler, GetUsersSubscriptionUrlHandler]; diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index 664ddd17..717d2f2f 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -20,6 +20,7 @@ import { UserEvent } from '@integration-modules/notifications/interfaces'; import { GetUserSubscriptionRequestHistoryQuery } from '@modules/user-subscription-request-history/queries/get-user-subscription-request-history'; import { CreateUserTrafficHistoryCommand } from '@modules/user-traffic-history/commands/create-user-traffic-history'; import { GetUserUsageByRangeQuery } from '@modules/nodes-user-usage-history/queries/get-user-usage-by-range'; +import { GetUsersSubscriptionUrlQuery } from '@modules/subscription/queries/get-users-subscription-url'; import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; import { RemoveUserFromNodeEvent } from '@modules/nodes/events/remove-user-from-node'; // import { SubscriptionService } from '@modules/subscription/subscription.service'; @@ -1259,7 +1260,6 @@ export class UsersService { shortUuid: string, username: string, ): Promise> => { - // return { isOk: true, response: 'Sublink' }; return this.queryBus.execute>( new GetSubscriptionUrlQuery(shortUuid, username), ); @@ -1268,6 +1268,9 @@ export class UsersService { private getUsersSubscriptionLink = async ( users: Pick[], ): Promise>> => { - return { isOk: true, response: { user: 'Sublinks' } }; + return this.queryBus.execute< + GetUsersSubscriptionUrlQuery, + ICommandResponse> + >(new GetUsersSubscriptionUrlQuery(users)); }; } From a38c6d9cc673fb609a11f0b34e207c204899824d Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 08:30:23 +0300 Subject: [PATCH 07/10] Revert "Fix: Debugging" This reverts commit 02ea80d2c583a163942e22d096fcffd2fcacde83. --- src/modules/users/users.service.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index 717d2f2f..b65f632c 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -486,13 +486,6 @@ export class UsersService { return { ...subscriptionUrlResult, response: undefined }; } - this.logger.error( - 'GET by uunic', - result.shortUuid, - result.username, - subscriptionUrlResult.response, - ); - return { isOk: true, response: { user: result, subscriptionUrl: subscriptionUrlResult.response }, From 3bdafb2fbf59458c78b91b00ea1d0ed36986ad79 Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 08:48:11 +0300 Subject: [PATCH 08/10] Refactoring: renaming methods to one theme --- .../generators/format-hosts.service.ts | 18 --------------- .../get-subscription-url.handler.ts | 5 +---- .../get-users-subscription-url.handler.ts | 2 +- .../subscription/subscription.service.ts | 4 ++-- src/modules/users/users.service.ts | 22 +++++++++---------- 5 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/modules/subscription-template/generators/format-hosts.service.ts b/src/modules/subscription-template/generators/format-hosts.service.ts index 8587fdc7..b1606ada 100644 --- a/src/modules/subscription-template/generators/format-hosts.service.ts +++ b/src/modules/subscription-template/generators/format-hosts.service.ts @@ -22,7 +22,6 @@ import { SECURITY_LAYERS, USERS_STATUS } from '@libs/contracts/constants'; import { SubscriptionSettingsEntity } from '@modules/subscription-settings/entities/subscription-settings.entity'; import { GetSubscriptionSettingsQuery } from '@modules/subscription-settings/queries/get-subscription-settings'; -// import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; import { resolveSubscriptionUrl } from '@modules/subscription/utils/resolve-subscription-url'; import { HostWithRawInbound } from '@modules/hosts/entities/host-with-inbound-tag.entity'; import { UserEntity } from '@modules/users/entities'; @@ -52,9 +51,7 @@ export class FormatHostsService { let specialRemarks: string[] = []; const settings = await this.getSubscriptionSettings(); - // const subscriptionUrl = await this.getSubscriptionUrl(user.shortUuid, user.username); - // if (!settings || !subscriptionUrl) { if (!settings) { return formattedHosts; } @@ -423,21 +420,6 @@ export class FormatHostsService { return settingsResponse.response; } - // private async getSubscriptionUrl( - // userShortUuid: string, - // username: string, - // ): Promise { - // const url = await this.queryBus.execute>( - // new GetSubscriptionUrlQuery(userShortUuid, username), - // ); - // - // if (!url.isOk || !url.response) { - // return null; - // } - // - // return url.response; - // } - private createFallbackHosts(remarks: string[]): IFormattedHost[] { return remarks.map((remark) => ({ remark, diff --git a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts index 1c3eeff2..cbacfc9d 100644 --- a/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts +++ b/src/modules/subscription/queries/get-subscription-url/get-subscription-url.handler.ts @@ -13,9 +13,6 @@ export class GetSubscriptionUrlHandler constructor(private readonly subscriptionService: SubscriptionService) {} async execute(query: GetSubscriptionUrlQuery): Promise> { - return this.subscriptionService.getUserSubscriptionLinkByUser( - query.userShortUuid, - query.username, - ); + return this.subscriptionService.getSubscriptionUrl(query.userShortUuid, query.username); } } diff --git a/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts index b2cf9674..577810e8 100644 --- a/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts +++ b/src/modules/subscription/queries/get-users-subscription-url/get-users-subscription-url.handler.ts @@ -15,6 +15,6 @@ export class GetUsersSubscriptionUrlHandler async execute( query: GetUsersSubscriptionUrlQuery, ): Promise>> { - return this.subscriptionService.getUsersSubscriptionLinkByUser(query.users); + return this.subscriptionService.getUsersSubscriptionUrl(query.users); } } diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index 404409cc..ec379514 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -686,7 +686,7 @@ export class SubscriptionService { } } - public async getUserSubscriptionLinkByUser( + public async getSubscriptionUrl( userShortUuid: string, username: string, ): Promise> { @@ -710,7 +710,7 @@ export class SubscriptionService { }; } - public async getUsersSubscriptionLinkByUser( + public async getUsersSubscriptionUrl( users: Pick[], ): Promise>> { const settingEntity = await this.getCachedSubscriptionSettings(); diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index b65f632c..8726327b 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -86,7 +86,7 @@ export class UsersService { return { ...user, response: undefined }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( user.response.shortUuid, user.response.username, ); @@ -154,7 +154,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( user.response.user.shortUuid, user.response.user.username, ); @@ -439,7 +439,7 @@ export class UsersService { try { const [users, total] = await this.userRepository.getAllUsersV2(dto); - const subscriptionUrlsResult = await this.getUsersSubscriptionLink(users); + const subscriptionUrlsResult = await this.getUsersSubscriptionUrl(users); if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { return { ...subscriptionUrlsResult, response: undefined }; } @@ -478,7 +478,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( result.shortUuid, result.username, ); @@ -518,7 +518,7 @@ export class UsersService { }; } - const subscriptionUrlsResult = await this.getUsersSubscriptionLink(result); + const subscriptionUrlsResult = await this.getUsersSubscriptionUrl(result); if (!subscriptionUrlsResult.isOk || !subscriptionUrlsResult.response) { return { ...subscriptionUrlsResult, response: undefined }; } @@ -578,7 +578,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( updatedUser.shortUuid, updatedUser.username, ); @@ -674,7 +674,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( updatedUser.shortUuid, updatedUser.username, ); @@ -737,7 +737,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( updatedUser.shortUuid, updatedUser.username, ); @@ -817,7 +817,7 @@ export class UsersService { }; } - const subscriptionUrlResult = await this.getUserSubscriptionLink( + const subscriptionUrlResult = await this.getSubscriptionUrl( newUser.shortUuid, newUser.username, ); @@ -1249,7 +1249,7 @@ export class UsersService { >(new GetUserUsageByRangeQuery(userUuid, start, end)); } - private getUserSubscriptionLink = async ( + private getSubscriptionUrl = async ( shortUuid: string, username: string, ): Promise> => { @@ -1258,7 +1258,7 @@ export class UsersService { ); }; - private getUsersSubscriptionLink = async ( + private getUsersSubscriptionUrl = async ( users: Pick[], ): Promise>> => { return this.queryBus.execute< From 73f9b0b8687bbab71ae96358774cacf4068d7c91 Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 08:51:34 +0300 Subject: [PATCH 09/10] Refactoring: eslint fixes --- src/modules/hosts/index.ts | 2 +- src/queue/bulk-user-operations/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/hosts/index.ts b/src/modules/hosts/index.ts index a6c094b7..3a98b7d4 100644 --- a/src/modules/hosts/index.ts +++ b/src/modules/hosts/index.ts @@ -1,5 +1,5 @@ -export * from './entities/hosts.entity'; export * from './controllers/hosts.controller'; +export * from './entities/hosts.entity'; export * from './hosts.module'; export * from './hosts.service'; export * from './repositories/hosts.repository'; diff --git a/src/queue/bulk-user-operations/index.ts b/src/queue/bulk-user-operations/index.ts index d5829ae4..e2e6547a 100644 --- a/src/queue/bulk-user-operations/index.ts +++ b/src/queue/bulk-user-operations/index.ts @@ -1,2 +1,2 @@ -export * from './enums'; export * from './bulk-user-operations.service'; +export * from './enums'; From 4c1e55bb405a4c797517e60e53d1c2c5e0849eb8 Mon Sep 17 00:00:00 2001 From: TSLA Date: Mon, 29 Sep 2025 20:59:14 +0300 Subject: [PATCH 10/10] Refactoring: removed comments --- src/modules/subscription/subscription.service.ts | 12 ------------ src/modules/users/users.service.ts | 2 -- 2 files changed, 14 deletions(-) diff --git a/src/modules/subscription/subscription.service.ts b/src/modules/subscription/subscription.service.ts index ec379514..a6325d42 100644 --- a/src/modules/subscription/subscription.service.ts +++ b/src/modules/subscription/subscription.service.ts @@ -1010,18 +1010,6 @@ export class SubscriptionService { } } - // private resolveSubscriptionUrl( - // shortUuid: string, - // username: string, - // addUsernameToBaseSubscription: boolean, - // ): string { - // if (addUsernameToBaseSubscription) { - // return `https://${this.subPublicDomain}/${shortUuid}#${username}`; - // } - // - // return `https://${this.subPublicDomain}/${shortUuid}`; - // } - private async updateAndReportSubscriptionRequest( userUuid: string, userAgent: string, diff --git a/src/modules/users/users.service.ts b/src/modules/users/users.service.ts index 8726327b..c1225f97 100644 --- a/src/modules/users/users.service.ts +++ b/src/modules/users/users.service.ts @@ -23,7 +23,6 @@ import { GetUserUsageByRangeQuery } from '@modules/nodes-user-usage-history/quer import { GetUsersSubscriptionUrlQuery } from '@modules/subscription/queries/get-users-subscription-url'; import { GetSubscriptionUrlQuery } from '@modules/subscription/queries/get-subscription-url'; import { RemoveUserFromNodeEvent } from '@modules/nodes/events/remove-user-from-node'; -// import { SubscriptionService } from '@modules/subscription/subscription.service'; import { AddUserToNodeEvent } from '@modules/nodes/events/add-user-to-node'; import { UserTrafficHistoryEntity } from '@modules/user-traffic-history'; @@ -71,7 +70,6 @@ export class UsersService { private readonly startAllNodesQueue: StartAllNodesQueueService, private readonly resetUserTrafficQueueService: ResetUserTrafficQueueService, private readonly userActionsQueueService: UserActionsQueueService, - // private readonly subscriptionService: SubscriptionService, ) { this.shortUuidLength = this.configService.getOrThrow('SHORT_UUID_LENGTH'); }