@carlonicora/nestjs-neo4jsonapi 8.5.0 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/bootstrap/app.module.factory.d.ts.map +1 -1
  2. package/dist/bootstrap/app.module.factory.js +1 -0
  3. package/dist/bootstrap/app.module.factory.js.map +1 -1
  4. package/dist/bootstrap/bootstrap.options.d.ts +14 -0
  5. package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
  6. package/dist/config/enums/queue.id.d.ts +1 -0
  7. package/dist/config/enums/queue.id.d.ts.map +1 -1
  8. package/dist/config/enums/queue.id.js +1 -0
  9. package/dist/config/enums/queue.id.js.map +1 -1
  10. package/dist/core/email/templates/en/accountDeleted.hbs +23 -0
  11. package/dist/core/email/templates/en/accountDeletionRequested.hbs +28 -0
  12. package/dist/foundations/account-deletion/account-deletion.config.d.ts +18 -0
  13. package/dist/foundations/account-deletion/account-deletion.config.d.ts.map +1 -0
  14. package/dist/foundations/account-deletion/account-deletion.config.js +6 -0
  15. package/dist/foundations/account-deletion/account-deletion.config.js.map +1 -0
  16. package/dist/foundations/account-deletion/account-deletion.constants.d.ts +36 -0
  17. package/dist/foundations/account-deletion/account-deletion.constants.d.ts.map +1 -0
  18. package/dist/foundations/account-deletion/account-deletion.constants.js +41 -0
  19. package/dist/foundations/account-deletion/account-deletion.constants.js.map +1 -0
  20. package/dist/foundations/account-deletion/account-deletion.module.d.ts +31 -0
  21. package/dist/foundations/account-deletion/account-deletion.module.d.ts.map +1 -0
  22. package/dist/foundations/account-deletion/account-deletion.module.js +98 -0
  23. package/dist/foundations/account-deletion/account-deletion.module.js.map +1 -0
  24. package/dist/foundations/account-deletion/controllers/account-deletion.controller.d.ts +28 -0
  25. package/dist/foundations/account-deletion/controllers/account-deletion.controller.d.ts.map +1 -0
  26. package/dist/foundations/account-deletion/controllers/account-deletion.controller.js +132 -0
  27. package/dist/foundations/account-deletion/controllers/account-deletion.controller.js.map +1 -0
  28. package/dist/foundations/account-deletion/cron/account-deletion.cron.d.ts +20 -0
  29. package/dist/foundations/account-deletion/cron/account-deletion.cron.d.ts.map +1 -0
  30. package/dist/foundations/account-deletion/cron/account-deletion.cron.js +78 -0
  31. package/dist/foundations/account-deletion/cron/account-deletion.cron.js.map +1 -0
  32. package/dist/foundations/account-deletion/dtos/account-deletion.keep.post.dto.d.ts +14 -0
  33. package/dist/foundations/account-deletion/dtos/account-deletion.keep.post.dto.d.ts.map +1 -0
  34. package/dist/foundations/account-deletion/dtos/account-deletion.keep.post.dto.js +51 -0
  35. package/dist/foundations/account-deletion/dtos/account-deletion.keep.post.dto.js.map +1 -0
  36. package/dist/foundations/account-deletion/dtos/account-deletion.post.dto.d.ts +14 -0
  37. package/dist/foundations/account-deletion/dtos/account-deletion.post.dto.d.ts.map +1 -0
  38. package/dist/foundations/account-deletion/dtos/account-deletion.post.dto.js +51 -0
  39. package/dist/foundations/account-deletion/dtos/account-deletion.post.dto.js.map +1 -0
  40. package/dist/foundations/account-deletion/entities/account-deletion.d.ts +20 -0
  41. package/dist/foundations/account-deletion/entities/account-deletion.d.ts.map +1 -0
  42. package/dist/foundations/account-deletion/entities/account-deletion.js +21 -0
  43. package/dist/foundations/account-deletion/entities/account-deletion.js.map +1 -0
  44. package/dist/foundations/account-deletion/entities/account-deletion.meta.d.ts +3 -0
  45. package/dist/foundations/account-deletion/entities/account-deletion.meta.d.ts.map +1 -0
  46. package/dist/foundations/account-deletion/entities/account-deletion.meta.js +10 -0
  47. package/dist/foundations/account-deletion/entities/account-deletion.meta.js.map +1 -0
  48. package/dist/foundations/account-deletion/index.d.ts +15 -0
  49. package/dist/foundations/account-deletion/index.d.ts.map +1 -0
  50. package/dist/foundations/account-deletion/index.js +31 -0
  51. package/dist/foundations/account-deletion/index.js.map +1 -0
  52. package/dist/foundations/account-deletion/interfaces/account-deletion-handler.interface.d.ts +29 -0
  53. package/dist/foundations/account-deletion/interfaces/account-deletion-handler.interface.d.ts.map +1 -0
  54. package/dist/foundations/account-deletion/interfaces/account-deletion-handler.interface.js +5 -0
  55. package/dist/foundations/account-deletion/interfaces/account-deletion-handler.interface.js.map +1 -0
  56. package/dist/foundations/account-deletion/interfaces/account-deletion-login-hook.interface.d.ts +12 -0
  57. package/dist/foundations/account-deletion/interfaces/account-deletion-login-hook.interface.d.ts.map +1 -0
  58. package/dist/foundations/account-deletion/interfaces/account-deletion-login-hook.interface.js +5 -0
  59. package/dist/foundations/account-deletion/interfaces/account-deletion-login-hook.interface.js.map +1 -0
  60. package/dist/foundations/account-deletion/processors/account-deletion.processor.d.ts +28 -0
  61. package/dist/foundations/account-deletion/processors/account-deletion.processor.d.ts.map +1 -0
  62. package/dist/foundations/account-deletion/processors/account-deletion.processor.js +97 -0
  63. package/dist/foundations/account-deletion/processors/account-deletion.processor.js.map +1 -0
  64. package/dist/foundations/account-deletion/repositories/account-deletion.repository.d.ts +85 -0
  65. package/dist/foundations/account-deletion/repositories/account-deletion.repository.d.ts.map +1 -0
  66. package/dist/foundations/account-deletion/repositories/account-deletion.repository.js +186 -0
  67. package/dist/foundations/account-deletion/repositories/account-deletion.repository.js.map +1 -0
  68. package/dist/foundations/account-deletion/repositories/account-deletion.wipe.repository.d.ts +77 -0
  69. package/dist/foundations/account-deletion/repositories/account-deletion.wipe.repository.d.ts.map +1 -0
  70. package/dist/foundations/account-deletion/repositories/account-deletion.wipe.repository.js +243 -0
  71. package/dist/foundations/account-deletion/repositories/account-deletion.wipe.repository.js.map +1 -0
  72. package/dist/foundations/account-deletion/services/account-deletion.service.d.ts +105 -0
  73. package/dist/foundations/account-deletion/services/account-deletion.service.d.ts.map +1 -0
  74. package/dist/foundations/account-deletion/services/account-deletion.service.js +300 -0
  75. package/dist/foundations/account-deletion/services/account-deletion.service.js.map +1 -0
  76. package/dist/foundations/account-deletion/services/account-wipe.service.d.ts +64 -0
  77. package/dist/foundations/account-deletion/services/account-wipe.service.d.ts.map +1 -0
  78. package/dist/foundations/account-deletion/services/account-wipe.service.js +134 -0
  79. package/dist/foundations/account-deletion/services/account-wipe.service.js.map +1 -0
  80. package/dist/foundations/account-deletion/services/full-company-deletion.service.d.ts +88 -0
  81. package/dist/foundations/account-deletion/services/full-company-deletion.service.d.ts.map +1 -0
  82. package/dist/foundations/account-deletion/services/full-company-deletion.service.js +184 -0
  83. package/dist/foundations/account-deletion/services/full-company-deletion.service.js.map +1 -0
  84. package/dist/foundations/account-deletion/utils/deliverable-email.d.ts +8 -0
  85. package/dist/foundations/account-deletion/utils/deliverable-email.d.ts.map +1 -0
  86. package/dist/foundations/account-deletion/utils/deliverable-email.js +20 -0
  87. package/dist/foundations/account-deletion/utils/deliverable-email.js.map +1 -0
  88. package/dist/foundations/auth/entities/auth.d.ts +1 -0
  89. package/dist/foundations/auth/entities/auth.d.ts.map +1 -1
  90. package/dist/foundations/auth/entities/auth.js +4 -0
  91. package/dist/foundations/auth/entities/auth.js.map +1 -1
  92. package/dist/foundations/auth/repositories/auth.repository.d.ts +2 -0
  93. package/dist/foundations/auth/repositories/auth.repository.d.ts.map +1 -1
  94. package/dist/foundations/auth/repositories/auth.repository.js +4 -0
  95. package/dist/foundations/auth/repositories/auth.repository.js.map +1 -1
  96. package/dist/foundations/auth/services/auth.service.d.ts +3 -1
  97. package/dist/foundations/auth/services/auth.service.d.ts.map +1 -1
  98. package/dist/foundations/auth/services/auth.service.js +11 -2
  99. package/dist/foundations/auth/services/auth.service.js.map +1 -1
  100. package/dist/foundations/foundations.modules.d.ts +7 -0
  101. package/dist/foundations/foundations.modules.d.ts.map +1 -1
  102. package/dist/foundations/foundations.modules.js +5 -0
  103. package/dist/foundations/foundations.modules.js.map +1 -1
  104. package/dist/foundations/index.d.ts +1 -0
  105. package/dist/foundations/index.d.ts.map +1 -1
  106. package/dist/foundations/index.js +1 -0
  107. package/dist/foundations/index.js.map +1 -1
  108. package/dist/foundations/user/entities/user.d.ts +3 -0
  109. package/dist/foundations/user/entities/user.d.ts.map +1 -1
  110. package/dist/foundations/user/entities/user.js +4 -0
  111. package/dist/foundations/user/entities/user.js.map +1 -1
  112. package/package.json +1 -1
@@ -0,0 +1,105 @@
1
+ import { ConfigService } from "@nestjs/config";
2
+ import { ModuleRef } from "@nestjs/core";
3
+ import { ClsService } from "nestjs-cls";
4
+ import { BaseConfigInterface } from "../../../config/interfaces";
5
+ import { EmailService } from "../../../core/email/services/email.service";
6
+ import { JsonApiSingleDocument } from "../../../core/jsonapi/interfaces/jsonapi.document.interface";
7
+ import { JsonApiService } from "../../../core/jsonapi/services/jsonapi.service";
8
+ import { AbstractService } from "../../../core/neo4j/abstracts/abstract.service";
9
+ import { StripeCustomerRepository } from "../../stripe-customer/repositories/stripe-customer.repository";
10
+ import { StripeSubscriptionRepository } from "../../stripe-subscription/repositories/stripe-subscription.repository";
11
+ import { StripeSubscriptionApiService } from "../../stripe-subscription/services/stripe-subscription-api.service";
12
+ import { User, UserDescriptor } from "../../user/entities/user";
13
+ import { ResponseLanguageService } from "../../user/services/response-language.service";
14
+ import { AccountDeletionModuleConfig } from "../account-deletion.config";
15
+ import { AccountDeletionLoginHook } from "../interfaces/account-deletion-login-hook.interface";
16
+ import { AccountDeletionRepository } from "../repositories/account-deletion.repository";
17
+ /**
18
+ * The request side of account deletion: preview, request (self and admin), the
19
+ * public keep link and cancel-on-login. The wipe itself runs in the worker
20
+ * (AccountWipeService).
21
+ *
22
+ * Every response is the synthetic `account-deletions` resource built with
23
+ * `buildSingle(AccountDeletionDescriptor.model, ...)`; `id` is the user id.
24
+ */
25
+ export declare class AccountDeletionService extends AbstractService<User, typeof UserDescriptor.relationships> implements AccountDeletionLoginHook {
26
+ private readonly accountDeletionRepository;
27
+ private readonly stripeCustomerRepository;
28
+ private readonly stripeSubscriptionRepository;
29
+ private readonly stripeSubscriptionApiService;
30
+ private readonly emailService;
31
+ private readonly responseLanguage;
32
+ private readonly configService;
33
+ private readonly moduleRef;
34
+ private readonly config;
35
+ protected readonly descriptor: import("../../..").EntityDescriptor<User, {
36
+ role: {
37
+ model: import("../../..").DataMeta;
38
+ direction: "out";
39
+ relationship: string;
40
+ cardinality: "many";
41
+ dtoKey: string;
42
+ readOnly: true;
43
+ };
44
+ company: {
45
+ model: import("../../..").DataModelInterface<import("../..").Company>;
46
+ direction: "out";
47
+ relationship: string;
48
+ cardinality: "one";
49
+ };
50
+ module: {
51
+ model: import("../../..").DataMeta;
52
+ direction: "out";
53
+ relationship: string;
54
+ cardinality: "many";
55
+ dtoKey: string;
56
+ };
57
+ }>;
58
+ private readonly logger;
59
+ constructor(jsonApiService: JsonApiService, accountDeletionRepository: AccountDeletionRepository, clsService: ClsService, stripeCustomerRepository: StripeCustomerRepository, stripeSubscriptionRepository: StripeSubscriptionRepository, stripeSubscriptionApiService: StripeSubscriptionApiService, emailService: EmailService, responseLanguage: ResponseLanguageService, configService: ConfigService<BaseConfigInterface>, moduleRef: ModuleRef, config: AccountDeletionModuleConfig);
60
+ private get graceDays();
61
+ /**
62
+ * The app handler is provided by an app module (not global), so it is looked
63
+ * up lazily at call time, like AuthService's registration hook. Resolving it
64
+ * in the constructor would capture Nest's placeholder.
65
+ */
66
+ private get handler();
67
+ findPreview(params: {
68
+ userId: string;
69
+ }): Promise<JsonApiSingleDocument>;
70
+ request(params: {
71
+ targetUserId: string;
72
+ actingUserId: string;
73
+ confirmation: string;
74
+ }): Promise<JsonApiSingleDocument>;
75
+ /** Public undo link. Any failure gives the same answer, so no account can be probed. */
76
+ keep(params: {
77
+ token: string;
78
+ }): Promise<void>;
79
+ /** Login hook (ACCOUNT_DELETION_LOGIN_HOOK): a fresh login cancels a pending request. */
80
+ cancelOnLogin(params: {
81
+ userId: string;
82
+ }): Promise<boolean>;
83
+ private _loadTarget;
84
+ /**
85
+ * Runs the callback as the TARGET user (OD-4): a fresh CLS context with the
86
+ * target's userId and companyId, so an admin acting on another user reads the
87
+ * target's company, never the admin's.
88
+ */
89
+ private _asTarget;
90
+ /** Active, trialing and past-due subscriptions of the company that goes with the user; none when the company stays. */
91
+ private _activeSubscriptions;
92
+ /**
93
+ * Cancels one subscription at once and records it locally, so a second request does not
94
+ * cancel it again before Stripe's webhook arrives. A subscription Stripe no longer knows
95
+ * (already cancelled) counts as cancelled.
96
+ */
97
+ private _cancelNow;
98
+ private _describeImpact;
99
+ private _assertConfirmation;
100
+ private _isAdministrator;
101
+ private _hash;
102
+ private _sendRequestEmail;
103
+ private _build;
104
+ }
105
+ //# sourceMappingURL=account-deletion.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-deletion.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/account-deletion/services/account-deletion.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,300 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var AccountDeletionService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.AccountDeletionService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const config_1 = require("@nestjs/config");
19
+ const core_1 = require("@nestjs/core");
20
+ const crypto_1 = require("crypto");
21
+ const nestjs_cls_1 = require("nestjs-cls");
22
+ const system_roles_1 = require("../../../common/constants/system.roles");
23
+ const email_service_1 = require("../../../core/email/services/email.service");
24
+ const jsonapi_service_1 = require("../../../core/jsonapi/services/jsonapi.service");
25
+ const abstract_service_1 = require("../../../core/neo4j/abstracts/abstract.service");
26
+ const stripe_customer_repository_1 = require("../../stripe-customer/repositories/stripe-customer.repository");
27
+ const stripe_subscription_repository_1 = require("../../stripe-subscription/repositories/stripe-subscription.repository");
28
+ const stripe_subscription_api_service_1 = require("../../stripe-subscription/services/stripe-subscription-api.service");
29
+ const user_1 = require("../../user/entities/user");
30
+ const response_language_service_1 = require("../../user/services/response-language.service");
31
+ const account_deletion_config_1 = require("../account-deletion.config");
32
+ const account_deletion_1 = require("../entities/account-deletion");
33
+ const account_deletion_handler_interface_1 = require("../interfaces/account-deletion-handler.interface");
34
+ const account_deletion_repository_1 = require("../repositories/account-deletion.repository");
35
+ const deliverable_email_1 = require("../utils/deliverable-email");
36
+ const full_company_deletion_service_1 = require("./full-company-deletion.service");
37
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
38
+ const KEEP_LINK_FAILURE = "This link no longer works";
39
+ const UNDELIVERABLE_CONFIRMATIONS = ["DELETE", "ELIMINA"];
40
+ const CANCELLABLE_STATUSES = ["active", "trialing", "past_due"];
41
+ /**
42
+ * The request side of account deletion: preview, request (self and admin), the
43
+ * public keep link and cancel-on-login. The wipe itself runs in the worker
44
+ * (AccountWipeService).
45
+ *
46
+ * Every response is the synthetic `account-deletions` resource built with
47
+ * `buildSingle(AccountDeletionDescriptor.model, ...)`; `id` is the user id.
48
+ */
49
+ let AccountDeletionService = AccountDeletionService_1 = class AccountDeletionService extends abstract_service_1.AbstractService {
50
+ constructor(jsonApiService, accountDeletionRepository, clsService, stripeCustomerRepository, stripeSubscriptionRepository, stripeSubscriptionApiService, emailService, responseLanguage, configService, moduleRef, config) {
51
+ super(jsonApiService, accountDeletionRepository, clsService, user_1.UserDescriptor.model);
52
+ this.accountDeletionRepository = accountDeletionRepository;
53
+ this.stripeCustomerRepository = stripeCustomerRepository;
54
+ this.stripeSubscriptionRepository = stripeSubscriptionRepository;
55
+ this.stripeSubscriptionApiService = stripeSubscriptionApiService;
56
+ this.emailService = emailService;
57
+ this.responseLanguage = responseLanguage;
58
+ this.configService = configService;
59
+ this.moduleRef = moduleRef;
60
+ this.config = config;
61
+ this.descriptor = user_1.UserDescriptor;
62
+ this.logger = new common_1.Logger(AccountDeletionService_1.name);
63
+ }
64
+ get graceDays() {
65
+ return this.config?.graceDays ?? account_deletion_config_1.DEFAULT_ACCOUNT_DELETION_CONFIG.graceDays;
66
+ }
67
+ /**
68
+ * The app handler is provided by an app module (not global), so it is looked
69
+ * up lazily at call time, like AuthService's registration hook. Resolving it
70
+ * in the constructor would capture Nest's placeholder.
71
+ */
72
+ get handler() {
73
+ try {
74
+ return this.moduleRef.get(account_deletion_handler_interface_1.ACCOUNT_DELETION_HANDLER, { strict: false }) ?? undefined;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ async findPreview(params) {
81
+ const target = await this._loadTarget({ userId: params.userId });
82
+ const subscriptions = await this._activeSubscriptions(target);
83
+ const impact = await this._describeImpact(target);
84
+ return this._build({
85
+ target,
86
+ requestedAt: target.user.deletionRequestedAt,
87
+ scheduledAt: target.user.deletionScheduledAt,
88
+ hasActiveSubscription: subscriptions.length > 0,
89
+ impact,
90
+ });
91
+ }
92
+ async request(params) {
93
+ // Second line of defence behind the controller's @Roles(Administrator).
94
+ if (params.targetUserId !== params.actingUserId && !this._isAdministrator())
95
+ throw new common_1.ForbiddenException("You can only delete your own account");
96
+ const target = await this._loadTarget({ userId: params.targetUserId });
97
+ // A request is already pending: keep its date and token, send nothing, touch no subscription.
98
+ if (target.user.deletionScheduledAt) {
99
+ const subscriptions = await this._activeSubscriptions(target);
100
+ return this._build({
101
+ target,
102
+ requestedAt: target.user.deletionRequestedAt,
103
+ scheduledAt: target.user.deletionScheduledAt,
104
+ hasActiveSubscription: subscriptions.length > 0,
105
+ impact: await this._describeImpact(target),
106
+ });
107
+ }
108
+ this._assertConfirmation({ user: target.user, confirmation: params.confirmation });
109
+ const requestedAt = new Date();
110
+ const scheduledAt = new Date(requestedAt.getTime() + this.graceDays * ONE_DAY_MS);
111
+ const deliverable = (0, deliverable_email_1.hasDeliverableEmail)(target.user.email);
112
+ // Undeliverable users get no email, so no undo token is stored: only logging in cancels.
113
+ const undoToken = deliverable ? (0, crypto_1.randomBytes)(32).toString("base64url") : null;
114
+ // Cancelled now, not at the wipe, so no renewal is charged during the grace period. Before
115
+ // setRequest: if Stripe fails nothing is stored, and a retry cancels again instead of taking
116
+ // the "already pending" path above, which never cancels.
117
+ const subscriptions = await this._activeSubscriptions(target);
118
+ for (const subscription of subscriptions)
119
+ await this._cancelNow(target, subscription);
120
+ await this.accountDeletionRepository.setRequest({
121
+ userId: target.user.id,
122
+ requestedAt: requestedAt.toISOString(),
123
+ scheduledAt: scheduledAt.toISOString(),
124
+ undoTokenHash: undoToken ? this._hash(undoToken) : null,
125
+ });
126
+ await this.accountDeletionRepository.deleteSessions({ userId: target.user.id });
127
+ if (undoToken) {
128
+ await this._sendRequestEmail({
129
+ user: target.user,
130
+ scheduledAt,
131
+ undoToken,
132
+ subscriptionCancelled: subscriptions.length > 0,
133
+ });
134
+ }
135
+ this.logger.log(`Account deletion requested for user ${target.user.id} by ${params.actingUserId}`);
136
+ return this._build({
137
+ target,
138
+ requestedAt,
139
+ scheduledAt,
140
+ hasActiveSubscription: false,
141
+ impact: await this._describeImpact(target),
142
+ });
143
+ }
144
+ /** Public undo link. Any failure gives the same answer, so no account can be probed. */
145
+ async keep(params) {
146
+ try {
147
+ const user = await this.accountDeletionRepository.findByUndoTokenHash({
148
+ undoTokenHash: this._hash(params.token),
149
+ });
150
+ if (!user?.deletionScheduledAt || new Date(user.deletionScheduledAt).getTime() <= Date.now())
151
+ throw new common_1.NotFoundException(KEEP_LINK_FAILURE);
152
+ await this.accountDeletionRepository.clearRequest({ userId: user.id });
153
+ this.logger.log(`Account deletion cancelled by link for user ${user.id}`);
154
+ }
155
+ catch {
156
+ throw new common_1.NotFoundException(KEEP_LINK_FAILURE);
157
+ }
158
+ }
159
+ /** Login hook (ACCOUNT_DELETION_LOGIN_HOOK): a fresh login cancels a pending request. */
160
+ async cancelOnLogin(params) {
161
+ const user = await this.accountDeletionRepository.findTargetUser({ userId: params.userId });
162
+ if (!user?.deletionScheduledAt)
163
+ return false;
164
+ await this.accountDeletionRepository.clearRequest({ userId: params.userId });
165
+ this.logger.log(`Account deletion cancelled by login for user ${params.userId}`);
166
+ return true;
167
+ }
168
+ async _loadTarget(params) {
169
+ const user = await this.accountDeletionRepository.findTargetUser({ userId: params.userId });
170
+ if (!user)
171
+ throw new common_1.NotFoundException("User not found");
172
+ const summary = await this.accountDeletionRepository.findMembershipSummary({ userId: params.userId });
173
+ const deletesCompany = summary.companyId !== null && summary.memberCount === 1;
174
+ return {
175
+ user,
176
+ membershipCompanyId: summary.companyId,
177
+ deletesCompany,
178
+ clsCompanyId: summary.companyId ?? user.company?.id ?? undefined,
179
+ };
180
+ }
181
+ /**
182
+ * Runs the callback as the TARGET user (OD-4): a fresh CLS context with the
183
+ * target's userId and companyId, so an admin acting on another user reads the
184
+ * target's company, never the admin's.
185
+ */
186
+ _asTarget(target, callback) {
187
+ return this.clsService.run({ ifNested: "override" }, async () => {
188
+ this.clsService.set("userId", target.user.id);
189
+ if (target.clsCompanyId)
190
+ this.clsService.set("companyId", target.clsCompanyId);
191
+ return callback();
192
+ });
193
+ }
194
+ /** Active, trialing and past-due subscriptions of the company that goes with the user; none when the company stays. */
195
+ async _activeSubscriptions(target) {
196
+ if (!target.deletesCompany || !target.membershipCompanyId)
197
+ return [];
198
+ const companyId = target.membershipCompanyId;
199
+ return this._asTarget(target, async () => {
200
+ const customer = await this.stripeCustomerRepository.findByCompanyId({ companyId });
201
+ if (!customer?.id)
202
+ return [];
203
+ // findByStripeCustomerId matches the local StripeCustomer node id, not the cus_ id
204
+ const subscriptions = (await this.stripeSubscriptionRepository.findByStripeCustomerId({
205
+ stripeCustomerId: customer.id,
206
+ })) ?? [];
207
+ return subscriptions.filter((subscription) => CANCELLABLE_STATUSES.includes(subscription.status));
208
+ });
209
+ }
210
+ /**
211
+ * Cancels one subscription at once and records it locally, so a second request does not
212
+ * cancel it again before Stripe's webhook arrives. A subscription Stripe no longer knows
213
+ * (already cancelled) counts as cancelled.
214
+ */
215
+ async _cancelNow(target, subscription) {
216
+ try {
217
+ await this.stripeSubscriptionApiService.cancelSubscription(subscription.stripeSubscriptionId, false);
218
+ }
219
+ catch (error) {
220
+ if (!(0, full_company_deletion_service_1.isMissingStripeResource)(error))
221
+ throw error;
222
+ this.logger.log(`Subscription ${subscription.id} already gone in Stripe, marking it cancelled`);
223
+ }
224
+ await this._asTarget(target, () => this.stripeSubscriptionRepository.update({ id: subscription.id, status: "canceled", canceledAt: new Date() }));
225
+ }
226
+ async _describeImpact(target) {
227
+ const handler = this.handler;
228
+ if (!handler)
229
+ return { ownedCount: 0, otherTables: [] };
230
+ return this._asTarget(target, () => handler.describeImpact({
231
+ userId: target.user.id,
232
+ companyId: target.membershipCompanyId ?? undefined,
233
+ deletesCompany: target.deletesCompany,
234
+ }));
235
+ }
236
+ _assertConfirmation(params) {
237
+ const confirmation = (params.confirmation ?? "").trim();
238
+ const matches = (0, deliverable_email_1.hasDeliverableEmail)(params.user.email)
239
+ ? confirmation.toLowerCase() === params.user.email.trim().toLowerCase()
240
+ : UNDELIVERABLE_CONFIRMATIONS.includes(confirmation.toUpperCase());
241
+ if (!matches)
242
+ throw new common_1.BadRequestException("The confirmation does not match");
243
+ }
244
+ _isAdministrator() {
245
+ const roles = this.clsService.get("roles");
246
+ return Array.isArray(roles) && roles.includes(system_roles_1.SystemRoles.Administrator);
247
+ }
248
+ _hash(token) {
249
+ return (0, crypto_1.createHash)("sha256").update(token).digest("hex");
250
+ }
251
+ async _sendRequestEmail(params) {
252
+ const appConfig = this.configService.get("app");
253
+ const authConfig = this.configService.get("auth");
254
+ const locale = (await this.responseLanguage.resolveForEmail({ email: params.user.email })) ?? authConfig?.emailLocale ?? "en";
255
+ await this.emailService.sendEmail("accountDeletionRequested", {
256
+ to: params.user.email,
257
+ name: params.user.name ?? "",
258
+ deletionDate: params.scheduledAt.toLocaleDateString(locale, {
259
+ day: "numeric",
260
+ month: "long",
261
+ year: "numeric",
262
+ }),
263
+ keepUrl: `${appConfig?.url ?? ""}account/keep?token=${encodeURIComponent(params.undoToken)}`,
264
+ subscriptionCancelled: params.subscriptionCancelled,
265
+ }, locale);
266
+ }
267
+ async _build(params) {
268
+ const now = new Date();
269
+ const preview = {
270
+ id: params.target.user.id,
271
+ type: account_deletion_1.AccountDeletionDescriptor.model.type,
272
+ createdAt: now,
273
+ updatedAt: now,
274
+ requestedAt: params.requestedAt ? new Date(params.requestedAt) : undefined,
275
+ scheduledAt: params.scheduledAt ? new Date(params.scheduledAt) : undefined,
276
+ hasDeliverableEmail: (0, deliverable_email_1.hasDeliverableEmail)(params.target.user.email),
277
+ hasActiveSubscription: params.hasActiveSubscription,
278
+ deletesCompany: params.target.deletesCompany,
279
+ ownedCount: params.target.deletesCompany ? params.impact.ownedCount : 0,
280
+ otherTables: params.impact.otherTables ?? [],
281
+ };
282
+ return this.jsonApiService.buildSingle(account_deletion_1.AccountDeletionDescriptor.model, preview);
283
+ }
284
+ };
285
+ exports.AccountDeletionService = AccountDeletionService;
286
+ exports.AccountDeletionService = AccountDeletionService = AccountDeletionService_1 = __decorate([
287
+ (0, common_1.Injectable)(),
288
+ __param(10, (0, common_1.Inject)(account_deletion_config_1.ACCOUNT_DELETION_CONFIG)),
289
+ __metadata("design:paramtypes", [jsonapi_service_1.JsonApiService,
290
+ account_deletion_repository_1.AccountDeletionRepository,
291
+ nestjs_cls_1.ClsService,
292
+ stripe_customer_repository_1.StripeCustomerRepository,
293
+ stripe_subscription_repository_1.StripeSubscriptionRepository,
294
+ stripe_subscription_api_service_1.StripeSubscriptionApiService,
295
+ email_service_1.EmailService,
296
+ response_language_service_1.ResponseLanguageService,
297
+ config_1.ConfigService,
298
+ core_1.ModuleRef, Object])
299
+ ], AccountDeletionService);
300
+ //# sourceMappingURL=account-deletion.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-deletion.service.js","sourceRoot":"","sources":["../../../../src/foundations/account-deletion/services/account-deletion.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { ModuleRef } from "@nestjs/core";
2
+ import { ConfigService } from "@nestjs/config";
3
+ import { Queue } from "bullmq";
4
+ import { ClsService } from "nestjs-cls";
5
+ import { JsonApiService } from "../../../core/jsonapi/services/jsonapi.service";
6
+ import { AppLoggingService } from "../../../core/logging/services/logging.service";
7
+ import { AbstractService } from "../../../core/neo4j/abstracts/abstract.service";
8
+ import { User, UserDescriptor } from "../../user/entities/user";
9
+ import { ResponseLanguageService } from "../../user/services/response-language.service";
10
+ import { AccountDeletionRepository } from "../repositories/account-deletion.repository";
11
+ import { AccountDeletionWipeRepository } from "../repositories/account-deletion.wipe.repository";
12
+ import { FullCompanyDeletionService } from "./full-company-deletion.service";
13
+ /**
14
+ * The account wipe run by the worker (`AccountDeletionProcessor`, job
15
+ * `delete-account`). Every step tolerates "already gone", and the User node is
16
+ * deleted last, so a crash leaves a past `deletionScheduledAt` and the next run
17
+ * finishes the job. Logs carry ids only.
18
+ */
19
+ export declare class AccountWipeService extends AbstractService<User, typeof UserDescriptor.relationships> {
20
+ private readonly queue;
21
+ private readonly accountDeletionRepository;
22
+ private readonly wipeRepository;
23
+ private readonly fullCompanyDeletionService;
24
+ private readonly responseLanguageService;
25
+ private readonly configService;
26
+ private readonly logger;
27
+ private readonly moduleRef;
28
+ protected readonly descriptor: import("../../..").EntityDescriptor<User, {
29
+ role: {
30
+ model: import("../../..").DataMeta;
31
+ direction: "out";
32
+ relationship: string;
33
+ cardinality: "many";
34
+ dtoKey: string;
35
+ readOnly: true;
36
+ };
37
+ company: {
38
+ model: import("../../..").DataModelInterface<import("../..").Company>;
39
+ direction: "out";
40
+ relationship: string;
41
+ cardinality: "one";
42
+ };
43
+ module: {
44
+ model: import("../../..").DataMeta;
45
+ direction: "out";
46
+ relationship: string;
47
+ cardinality: "many";
48
+ dtoKey: string;
49
+ };
50
+ }>;
51
+ constructor(jsonApiService: JsonApiService, queue: Queue, accountDeletionRepository: AccountDeletionRepository, wipeRepository: AccountDeletionWipeRepository, fullCompanyDeletionService: FullCompanyDeletionService, responseLanguageService: ResponseLanguageService, configService: ConfigService, clsService: ClsService, logger: AppLoggingService, moduleRef: ModuleRef);
52
+ /**
53
+ * The app handler comes from an app module, looked up at call time like AccountDeletionService
54
+ * does. Injected with @Optional it resolved to undefined here (provider cycle through
55
+ * COMPANY_DELETION_HANDLER), so the app content step was silently skipped.
56
+ */
57
+ private get handler();
58
+ /** Runs inside the processor's `clsService.run`; sets the CLS user and company itself. */
59
+ deleteAccount(params: {
60
+ userId: string;
61
+ }): Promise<void>;
62
+ private resolveLocale;
63
+ }
64
+ //# sourceMappingURL=account-wipe.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-wipe.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/account-deletion/services/account-wipe.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;AASxF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AAEjG,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;;;;GAKG;AACH,qBACa,kBAAmB,SAAQ,eAAe,CAAC,IAAI,EAAE,OAAO,cAAc,CAAC,aAAa,CAAC;IAKvD,OAAO,CAAC,QAAQ,CAAC,KAAK;IAC7D,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAZ5B,SAAS,CAAC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;;;;;;;;;OAAkB;gBAG7C,cAAc,EAAE,cAAc,EAC0B,KAAK,EAAE,KAAK,EACnD,yBAAyB,EAAE,yBAAyB,EACpD,cAAc,EAAE,6BAA6B,EAC7C,0BAA0B,EAAE,0BAA0B,EACtD,uBAAuB,EAAE,uBAAuB,EAChD,aAAa,EAAE,aAAa,EAC7C,UAAU,EAAE,UAAU,EACL,MAAM,EAAE,iBAAiB,EACzB,SAAS,EAAE,SAAS;IAKvC;;;;OAIG;IACH,OAAO,KAAK,OAAO,GAMlB;IAED,0FAA0F;IACpF,aAAa,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YA2DhD,aAAa;CAI5B"}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AccountWipeService = void 0;
16
+ const bullmq_1 = require("@nestjs/bullmq");
17
+ const common_1 = require("@nestjs/common");
18
+ const core_1 = require("@nestjs/core");
19
+ const config_1 = require("@nestjs/config");
20
+ const bullmq_2 = require("bullmq");
21
+ const nestjs_cls_1 = require("nestjs-cls");
22
+ const queue_id_1 = require("../../../config/enums/queue.id");
23
+ const jsonapi_service_1 = require("../../../core/jsonapi/services/jsonapi.service");
24
+ const logging_service_1 = require("../../../core/logging/services/logging.service");
25
+ const abstract_service_1 = require("../../../core/neo4j/abstracts/abstract.service");
26
+ const user_1 = require("../../user/entities/user");
27
+ const response_language_service_1 = require("../../user/services/response-language.service");
28
+ const account_deletion_constants_1 = require("../account-deletion.constants");
29
+ const account_deletion_handler_interface_1 = require("../interfaces/account-deletion-handler.interface");
30
+ const account_deletion_repository_1 = require("../repositories/account-deletion.repository");
31
+ const account_deletion_wipe_repository_1 = require("../repositories/account-deletion.wipe.repository");
32
+ const deliverable_email_1 = require("../utils/deliverable-email");
33
+ const full_company_deletion_service_1 = require("./full-company-deletion.service");
34
+ /**
35
+ * The account wipe run by the worker (`AccountDeletionProcessor`, job
36
+ * `delete-account`). Every step tolerates "already gone", and the User node is
37
+ * deleted last, so a crash leaves a past `deletionScheduledAt` and the next run
38
+ * finishes the job. Logs carry ids only.
39
+ */
40
+ let AccountWipeService = class AccountWipeService extends abstract_service_1.AbstractService {
41
+ constructor(jsonApiService, queue, accountDeletionRepository, wipeRepository, fullCompanyDeletionService, responseLanguageService, configService, clsService, logger, moduleRef) {
42
+ super(jsonApiService, accountDeletionRepository, clsService, user_1.UserDescriptor.model);
43
+ this.queue = queue;
44
+ this.accountDeletionRepository = accountDeletionRepository;
45
+ this.wipeRepository = wipeRepository;
46
+ this.fullCompanyDeletionService = fullCompanyDeletionService;
47
+ this.responseLanguageService = responseLanguageService;
48
+ this.configService = configService;
49
+ this.logger = logger;
50
+ this.moduleRef = moduleRef;
51
+ this.descriptor = user_1.UserDescriptor;
52
+ }
53
+ /**
54
+ * The app handler comes from an app module, looked up at call time like AccountDeletionService
55
+ * does. Injected with @Optional it resolved to undefined here (provider cycle through
56
+ * COMPANY_DELETION_HANDLER), so the app content step was silently skipped.
57
+ */
58
+ get handler() {
59
+ try {
60
+ return this.moduleRef.get(account_deletion_handler_interface_1.ACCOUNT_DELETION_HANDLER, { strict: false }) ?? undefined;
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ }
66
+ /** Runs inside the processor's `clsService.run`; sets the CLS user and company itself. */
67
+ async deleteAccount(params) {
68
+ const { userId } = params;
69
+ // 0. Load and re-check: the request may have been cancelled after the job was queued
70
+ const user = await this.accountDeletionRepository.findTargetUser({ userId });
71
+ if (!user) {
72
+ this.logger.log(`Account ${userId} already deleted`, "AccountWipeService");
73
+ return;
74
+ }
75
+ const scheduledAt = user.deletionScheduledAt ? new Date(user.deletionScheduledAt) : undefined;
76
+ if (!scheduledAt || scheduledAt.getTime() > Date.now()) {
77
+ this.logger.log(`Account ${userId} deletion cancelled or not due, skipping`, "AccountWipeService");
78
+ return;
79
+ }
80
+ const summary = await this.accountDeletionRepository.findMembershipSummary({ userId });
81
+ const deletesCompany = !!summary.companyId && summary.memberCount === 1;
82
+ const wipedCompanyId = deletesCompany ? summary.companyId : undefined;
83
+ const email = user.email ?? "";
84
+ const sendsFinalEmail = (0, deliverable_email_1.hasDeliverableEmail)(email);
85
+ const locale = sendsFinalEmail ? await this.resolveLocale(email) : undefined;
86
+ const name = user.name ?? "";
87
+ this.clsService.set("userId", userId);
88
+ if (summary.companyId)
89
+ this.clsService.set("companyId", summary.companyId);
90
+ this.logger.log(`Deleting account ${userId}${wipedCompanyId ? ` with company ${wipedCompanyId}` : ""}`, "AccountWipeService");
91
+ // 1. App hook: the user's traces in companies that stay
92
+ const handler = this.handler;
93
+ if (handler)
94
+ await handler.removeUserTraces({ userId, wipedCompanyId });
95
+ else
96
+ this.logger.warn(`No ACCOUNT_DELETION_HANDLER: app traces of ${userId} not removed`, "AccountWipeService");
97
+ // 2. The user's own company, when they are its only member
98
+ if (wipedCompanyId)
99
+ await this.fullCompanyDeletionService.wipeCompany({ companyId: wipedCompanyId });
100
+ // 3. User-linked nodes, email-keyed entries, avatar, cache
101
+ await this.fullCompanyDeletionService.removeUserLinkedData({ user, wipedCompanyId });
102
+ // 4. Final email, deduplicated by job id so a re-run never sends a second one
103
+ if (sendsFinalEmail) {
104
+ const data = { to: email, name, locale: locale };
105
+ await this.queue.add(account_deletion_constants_1.ACCOUNT_DELETION_JOB_NAMES.accountDeletedEmail, data, {
106
+ ...account_deletion_constants_1.ACCOUNT_DELETED_EMAIL_JOB_OPTIONS,
107
+ jobId: (0, account_deletion_constants_1.accountDeletedEmailJobId)(userId),
108
+ });
109
+ }
110
+ // 5. The User node, last
111
+ await this.wipeRepository.deleteUserNode({ userId });
112
+ this.logger.log(`Account ${userId} deleted`, "AccountWipeService");
113
+ }
114
+ async resolveLocale(email) {
115
+ const saved = await this.responseLanguageService.resolveForEmail({ email });
116
+ return saved ?? this.configService.get("auth")?.emailLocale ?? "en";
117
+ }
118
+ };
119
+ exports.AccountWipeService = AccountWipeService;
120
+ exports.AccountWipeService = AccountWipeService = __decorate([
121
+ (0, common_1.Injectable)(),
122
+ __param(1, (0, bullmq_1.InjectQueue)(queue_id_1.QueueId.ACCOUNT_DELETION)),
123
+ __metadata("design:paramtypes", [jsonapi_service_1.JsonApiService,
124
+ bullmq_2.Queue,
125
+ account_deletion_repository_1.AccountDeletionRepository,
126
+ account_deletion_wipe_repository_1.AccountDeletionWipeRepository,
127
+ full_company_deletion_service_1.FullCompanyDeletionService,
128
+ response_language_service_1.ResponseLanguageService,
129
+ config_1.ConfigService,
130
+ nestjs_cls_1.ClsService,
131
+ logging_service_1.AppLoggingService,
132
+ core_1.ModuleRef])
133
+ ], AccountWipeService);
134
+ //# sourceMappingURL=account-wipe.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-wipe.service.js","sourceRoot":"","sources":["../../../../src/foundations/account-deletion/services/account-wipe.service.ts"],"names":[],"mappings":"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"}