@solidxai/core 0.1.9-beta.7 → 0.1.9

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 (165) hide show
  1. package/LICENSE +89 -0
  2. package/README.md +3 -1
  3. package/dist/constants/chatter-message.constants.d.ts +6 -0
  4. package/dist/constants/chatter-message.constants.d.ts.map +1 -1
  5. package/dist/constants/chatter-message.constants.js +7 -1
  6. package/dist/constants/chatter-message.constants.js.map +1 -1
  7. package/dist/controllers/authentication.controller.d.ts +12 -0
  8. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  9. package/dist/controllers/authentication.controller.js +13 -0
  10. package/dist/controllers/authentication.controller.js.map +1 -1
  11. package/dist/controllers/chatter-message.controller.d.ts +1 -0
  12. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  13. package/dist/controllers/chatter-message.controller.js +12 -0
  14. package/dist/controllers/chatter-message.controller.js.map +1 -1
  15. package/dist/controllers/facebook-authentication.controller.d.ts +27 -0
  16. package/dist/controllers/facebook-authentication.controller.d.ts.map +1 -0
  17. package/dist/controllers/facebook-authentication.controller.js +117 -0
  18. package/dist/controllers/facebook-authentication.controller.js.map +1 -0
  19. package/dist/controllers/menu-item-metadata.controller.d.ts +1 -0
  20. package/dist/controllers/menu-item-metadata.controller.d.ts.map +1 -1
  21. package/dist/controllers/menu-item-metadata.controller.js +15 -0
  22. package/dist/controllers/menu-item-metadata.controller.js.map +1 -1
  23. package/dist/controllers/microsoft-authentication.controller.d.ts +27 -0
  24. package/dist/controllers/microsoft-authentication.controller.d.ts.map +1 -0
  25. package/dist/controllers/microsoft-authentication.controller.js +118 -0
  26. package/dist/controllers/microsoft-authentication.controller.js.map +1 -0
  27. package/dist/controllers/setting.controller.d.ts +2 -2
  28. package/dist/controllers/setting.controller.js +2 -2
  29. package/dist/decorators/auth.decorator.d.ts.map +1 -1
  30. package/dist/decorators/computed-field-provider.decorator.d.ts.map +1 -1
  31. package/dist/decorators/dashboard-question-data-provider.decorator.d.ts.map +1 -1
  32. package/dist/decorators/dashboard-selection-provider.decorator.d.ts.map +1 -1
  33. package/dist/decorators/disallow-in-production.decorator.d.ts.map +1 -1
  34. package/dist/decorators/error-codes-provider.decorator.d.ts.map +1 -1
  35. package/dist/decorators/extension-user-creation-provider.decorator.d.ts.map +1 -1
  36. package/dist/decorators/is-not-in-enum.decorator.d.ts.map +1 -1
  37. package/dist/decorators/mail-provider.decorator.d.ts.map +1 -1
  38. package/dist/decorators/roles.decorator.d.ts.map +1 -1
  39. package/dist/decorators/scheduled-job-provider.decorator.d.ts.map +1 -1
  40. package/dist/decorators/security-rule-config-provider.decorator.d.ts.map +1 -1
  41. package/dist/decorators/selection-provider.decorator.d.ts.map +1 -1
  42. package/dist/decorators/sms-provider.decorator.d.ts.map +1 -1
  43. package/dist/decorators/solid-database-module.decorator.d.ts.map +1 -1
  44. package/dist/decorators/whatsapp-provider.decorator.d.ts.map +1 -1
  45. package/dist/dtos/create-chatter-message.dto.d.ts +1 -0
  46. package/dist/dtos/create-chatter-message.dto.d.ts.map +1 -1
  47. package/dist/dtos/create-chatter-message.dto.js +7 -1
  48. package/dist/dtos/create-chatter-message.dto.js.map +1 -1
  49. package/dist/dtos/post-chatter-message.dto.d.ts +1 -0
  50. package/dist/dtos/post-chatter-message.dto.d.ts.map +1 -1
  51. package/dist/dtos/post-chatter-message.dto.js +6 -1
  52. package/dist/dtos/post-chatter-message.dto.js.map +1 -1
  53. package/dist/dtos/update-chatter-message.dto.d.ts +1 -0
  54. package/dist/dtos/update-chatter-message.dto.d.ts.map +1 -1
  55. package/dist/dtos/update-chatter-message.dto.js +7 -1
  56. package/dist/dtos/update-chatter-message.dto.js.map +1 -1
  57. package/dist/entities/chatter-message.entity.d.ts +1 -0
  58. package/dist/entities/chatter-message.entity.d.ts.map +1 -1
  59. package/dist/entities/chatter-message.entity.js +5 -1
  60. package/dist/entities/chatter-message.entity.js.map +1 -1
  61. package/dist/entities/user.entity.d.ts +8 -0
  62. package/dist/entities/user.entity.d.ts.map +1 -1
  63. package/dist/entities/user.entity.js +33 -1
  64. package/dist/entities/user.entity.js.map +1 -1
  65. package/dist/helpers/cors.helper.js +1 -1
  66. package/dist/helpers/cors.helper.js.map +1 -1
  67. package/dist/helpers/facebook-oauth.helper.d.ts +8 -0
  68. package/dist/helpers/facebook-oauth.helper.d.ts.map +1 -0
  69. package/dist/helpers/facebook-oauth.helper.js +11 -0
  70. package/dist/helpers/facebook-oauth.helper.js.map +1 -0
  71. package/dist/helpers/microsoft-oauth.helper.d.ts +9 -0
  72. package/dist/helpers/microsoft-oauth.helper.d.ts.map +1 -0
  73. package/dist/helpers/microsoft-oauth.helper.js +12 -0
  74. package/dist/helpers/microsoft-oauth.helper.js.map +1 -0
  75. package/dist/helpers/security.helper.d.ts.map +1 -1
  76. package/dist/helpers/string.helper.d.ts.map +1 -1
  77. package/dist/helpers/user-helper.d.ts.map +1 -1
  78. package/dist/helpers/user-helper.js +4 -0
  79. package/dist/helpers/user-helper.js.map +1 -1
  80. package/dist/index.d.ts +2 -0
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +2 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/interfaces.d.ts +19 -0
  85. package/dist/interfaces.d.ts.map +1 -1
  86. package/dist/interfaces.js.map +1 -1
  87. package/dist/passport-strategies/facebook-oauth.strategy.d.ts +16 -0
  88. package/dist/passport-strategies/facebook-oauth.strategy.d.ts.map +1 -0
  89. package/dist/passport-strategies/facebook-oauth.strategy.js +96 -0
  90. package/dist/passport-strategies/facebook-oauth.strategy.js.map +1 -0
  91. package/dist/passport-strategies/microsoft-oauth.strategy.d.ts +14 -0
  92. package/dist/passport-strategies/microsoft-oauth.strategy.d.ts.map +1 -0
  93. package/dist/passport-strategies/microsoft-oauth.strategy.js +77 -0
  94. package/dist/passport-strategies/microsoft-oauth.strategy.js.map +1 -0
  95. package/dist/seeders/seed-data/solid-core-metadata.json +27 -58
  96. package/dist/services/api-key.service.d.ts +17 -1
  97. package/dist/services/api-key.service.d.ts.map +1 -1
  98. package/dist/services/api-key.service.js +38 -2
  99. package/dist/services/api-key.service.js.map +1 -1
  100. package/dist/services/authentication.service.d.ts +61 -27
  101. package/dist/services/authentication.service.d.ts.map +1 -1
  102. package/dist/services/authentication.service.js +356 -164
  103. package/dist/services/authentication.service.js.map +1 -1
  104. package/dist/services/chatter-message.service.d.ts +1 -0
  105. package/dist/services/chatter-message.service.d.ts.map +1 -1
  106. package/dist/services/chatter-message.service.js +24 -7
  107. package/dist/services/chatter-message.service.js.map +1 -1
  108. package/dist/services/crud-helper.service.d.ts.map +1 -1
  109. package/dist/services/model-metadata.service.js +1 -1
  110. package/dist/services/model-metadata.service.js.map +1 -1
  111. package/dist/services/setting.service.d.ts +5 -2
  112. package/dist/services/setting.service.d.ts.map +1 -1
  113. package/dist/services/setting.service.js +51 -6
  114. package/dist/services/setting.service.js.map +1 -1
  115. package/dist/services/settings/default-settings-provider.service.d.ts +846 -0
  116. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  117. package/dist/services/settings/default-settings-provider.service.js +1096 -117
  118. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  119. package/dist/services/user.service.d.ts +12 -8
  120. package/dist/services/user.service.d.ts.map +1 -1
  121. package/dist/services/user.service.js +143 -32
  122. package/dist/services/user.service.js.map +1 -1
  123. package/dist/solid-core.module.d.ts.map +1 -1
  124. package/dist/solid-core.module.js +11 -3
  125. package/dist/solid-core.module.js.map +1 -1
  126. package/dist/transformers/array-transformer.d.ts.map +1 -1
  127. package/dist/transformers/boolean-transformer.d.ts.map +1 -1
  128. package/dist/transformers/datetime-transformer.d.ts.map +1 -1
  129. package/dist/transformers/integer-transformer.d.ts.map +1 -1
  130. package/dist/validators/is-parsable-int.d.ts.map +1 -1
  131. package/nest +0 -0
  132. package/package.json +8 -2
  133. package/src/constants/chatter-message.constants.ts +7 -0
  134. package/src/controllers/authentication.controller.ts +8 -1
  135. package/src/controllers/chatter-message.controller.ts +6 -0
  136. package/src/controllers/facebook-authentication.controller.ts +113 -0
  137. package/src/controllers/menu-item-metadata.controller.ts +21 -15
  138. package/src/controllers/microsoft-authentication.controller.ts +116 -0
  139. package/src/dtos/create-chatter-message.dto.ts +11 -0
  140. package/src/dtos/post-chatter-message.dto.ts +4 -0
  141. package/src/dtos/update-chatter-message.dto.ts +13 -1
  142. package/src/entities/chatter-message.entity.ts +4 -1
  143. package/src/entities/user.entity.ts +32 -0
  144. package/src/helpers/cors.helper.ts +1 -1
  145. package/src/helpers/facebook-oauth.helper.ts +17 -0
  146. package/src/helpers/microsoft-oauth.helper.ts +19 -0
  147. package/src/helpers/user-helper.ts +4 -0
  148. package/src/index.ts +2 -0
  149. package/src/interfaces.ts +32 -1
  150. package/src/passport-strategies/facebook-oauth.strategy.ts +115 -0
  151. package/src/passport-strategies/microsoft-oauth.strategy.ts +70 -0
  152. package/src/seeders/seed-data/solid-core-metadata.json +27 -58
  153. package/src/services/api-key.service.ts +77 -35
  154. package/src/services/authentication.service.ts +1947 -1432
  155. package/src/services/chatter-message.service.ts +23 -3
  156. package/src/services/model-metadata.service.ts +1 -1
  157. package/src/services/setting.service.ts +64 -8
  158. package/src/services/settings/default-settings-provider.service.ts +1168 -156
  159. package/src/services/user.service.ts +220 -61
  160. package/src/solid-core.module.ts +25 -8
  161. package/dev-grooming-docs/ozzy-prompts.txt +0 -70
  162. package/docs/grouping-enhancements.md +0 -89
  163. package/docs/seed-changes.md +0 -65
  164. package/docs/test-data-workflow.md +0 -200
  165. package/docs/type-declaration-import-issue.md +0 -24
@@ -0,0 +1,115 @@
1
+ import { Injectable, Logger } from "@nestjs/common";
2
+ import { AuthGuard, PassportStrategy } from "@nestjs/passport";
3
+ import { Strategy } from "passport-facebook";
4
+ import {
5
+ FacebookAuthConfiguration,
6
+ isFacebookOAuthConfigured,
7
+ } from "src/helpers/facebook-oauth.helper";
8
+ import { v4 as uuid } from "uuid";
9
+ import type { SolidCoreSetting } from "../services/settings/default-settings-provider.service";
10
+ import { SettingService } from "../services/setting.service";
11
+ import { UserService } from "../services/user.service";
12
+
13
+ const DUMMY_CLIENT_ID = "DUMMY_CLIENT_ID";
14
+ const DUMMY_CLIENT_SECRET = "DUMMY_CLIENT_SECRET";
15
+ const DUMMY_CALLBACK_URL = "DUMMY_CALLBACK_URL";
16
+
17
+ @Injectable()
18
+ export class FacebookOauthGuard extends AuthGuard("facebook") {}
19
+
20
+ @Injectable()
21
+ export class FacebookOAuthStrategy extends PassportStrategy(
22
+ Strategy,
23
+ "facebook",
24
+ ) {
25
+ private readonly logger = new Logger(FacebookOAuthStrategy.name);
26
+
27
+ constructor(
28
+ private readonly userService: UserService,
29
+ private readonly settingService: SettingService,
30
+ ) {
31
+ // Prefer settings cache (same source used by controller validation), fall back to env.
32
+ const clientID =
33
+ settingService.getConfigValue<SolidCoreSetting>("FACEBOOK_CLIENT_ID") ??
34
+ process.env.IAM_FACEBOOK_OAUTH_CLIENT_ID ??
35
+ DUMMY_CLIENT_ID;
36
+ const clientSecret =
37
+ settingService.getConfigValue<SolidCoreSetting>(
38
+ "FACEBOOK_CLIENT_SECRET",
39
+ ) ??
40
+ process.env.IAM_FACEBOOK_OAUTH_CLIENT_SECRET ??
41
+ DUMMY_CLIENT_SECRET;
42
+ const callbackURL =
43
+ settingService.getConfigValue<SolidCoreSetting>(
44
+ "FACEBOOK_CALLBACK_URL",
45
+ ) ??
46
+ process.env.IAM_FACEBOOK_OAUTH_CALLBACK_URL ??
47
+ DUMMY_CALLBACK_URL;
48
+ const redirectURL =
49
+ settingService.getConfigValue<SolidCoreSetting>(
50
+ "FACEBOOK_REDIRECT_URL",
51
+ ) ?? process.env.IAM_FACEBOOK_OAUTH_REDIRECT_URL;
52
+
53
+ super({
54
+ clientID,
55
+ clientSecret,
56
+ callbackURL,
57
+ scope: ["email"],
58
+ // Facebook Graph API expects "email" and "picture", not "emails"/"photos".
59
+ profileFields: ["id", "name", "email", "picture.type(large)"],
60
+ });
61
+
62
+ const facebookOauth: FacebookAuthConfiguration = {
63
+ clientID,
64
+ clientSecret,
65
+ callbackURL,
66
+ redirectURL,
67
+ };
68
+ if (!isFacebookOAuthConfigured(facebookOauth)) {
69
+ this.logger.debug("Facebook OAuth strategy is not configured");
70
+ } else {
71
+ this.logger.debug(
72
+ `Facebook OAuth configured with callbackURL=${callbackURL}`,
73
+ );
74
+ }
75
+ }
76
+
77
+ async validate(
78
+ _accessToken: string,
79
+ _refreshToken: string,
80
+ profile: any,
81
+ done: any,
82
+ ): Promise<any> {
83
+ const { id, name, emails, photos } = profile;
84
+
85
+ // generate a unique access code.
86
+ const loginAccessCode: string = uuid();
87
+
88
+ const email = emails && emails.length > 0 ? emails[0].value : null;
89
+
90
+ const firstName = name?.givenName || "";
91
+ const lastName = name?.familyName || "";
92
+ const fullName =
93
+ firstName || lastName
94
+ ? `${firstName} ${lastName}`.trim()
95
+ : profile.displayName;
96
+
97
+ const user = {
98
+ provider: "facebook",
99
+ providerId: id,
100
+ email: email,
101
+ name: `${name.givenName} ${name.familyName}`,
102
+ picture: photos?.[0]?.value,
103
+ accessCode: loginAccessCode,
104
+ };
105
+
106
+ // store the access code and the access token in the database.
107
+ await this.userService.resolveUserOnOauthFacebook({
108
+ ...user,
109
+ accessToken: _accessToken,
110
+ refreshToken: null,
111
+ });
112
+
113
+ done(null, user);
114
+ }
115
+ }
@@ -0,0 +1,70 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+ import { AuthGuard, PassportStrategy } from '@nestjs/passport';
3
+ import { Strategy } from 'passport-microsoft';
4
+ import { MicrosoftAuthConfiguration, isMicrosoftOAuthConfigured } from 'src/helpers/microsoft-oauth.helper';
5
+ import { v4 as uuid } from 'uuid';
6
+ import { UserService } from '../services/user.service';
7
+
8
+ const DUMMY_CLIENT_ID = 'DUMMY_CLIENT_ID';
9
+ const DUMMY_CLIENT_SECRET = 'DUMMY_CLIENT_SECRET';
10
+ const DUMMY_TENANT = 'common';
11
+ const DUMMY_CALLBACK_URL = 'DUMMY_CALLBACK_URL';
12
+
13
+ @Injectable()
14
+ export class MicrosoftOauthGuard extends AuthGuard('microsoft') { }
15
+
16
+ @Injectable()
17
+ export class MicrosoftOAuthStrategy extends PassportStrategy(Strategy, 'microsoft') {
18
+ private readonly logger = new Logger(MicrosoftOAuthStrategy.name);
19
+
20
+ constructor(private readonly userService: UserService) {
21
+ // Reading configuration from environment variables (Static approach like Google)
22
+ const clientID = process.env.IAM_MICROSOFT_OAUTH_CLIENT_ID ?? DUMMY_CLIENT_ID;
23
+ const clientSecret = process.env.IAM_MICROSOFT_OAUTH_CLIENT_SECRET ?? DUMMY_CLIENT_SECRET;
24
+ const tenant = process.env.IAM_MICROSOFT_OAUTH_TENANT_ID ?? DUMMY_TENANT;
25
+ const callbackURL = process.env.IAM_MICROSOFT_OAUTH_CALLBACK_URL ?? DUMMY_CALLBACK_URL;
26
+ const redirectURL = process.env.IAM_MICROSOFT_OAUTH_REDIRECT_URL;
27
+
28
+ super({
29
+ clientID,
30
+ clientSecret,
31
+ callbackURL,
32
+ tenant,
33
+ scope: ['user.read'],
34
+ addUPNAsEmail: true,
35
+ });
36
+
37
+ const microsoftOauth: MicrosoftAuthConfiguration = { clientID, clientSecret, tenant, callbackURL, redirectURL };
38
+ if (!isMicrosoftOAuthConfigured(microsoftOauth)) {
39
+ this.logger.debug('Microsoft OAuth strategy is not configured');
40
+ }
41
+ }
42
+
43
+ async validate(_accessToken: string, _refreshToken: string, profile: any, done: any): Promise<any> {
44
+ const { id, displayName, emails, photos } = profile;
45
+
46
+ // generate a unique access code.
47
+ const loginAccessCode: string = uuid();
48
+
49
+ // Handle email fallback logic within the standard validate flow
50
+ const email = emails?.[0]?.value || profile._json?.mail || profile._json?.userPrincipalName;
51
+
52
+ const user = {
53
+ provider: 'microsoft',
54
+ providerId: id,
55
+ email: email,
56
+ name: displayName,
57
+ picture: photos?.[0]?.value || null,
58
+ accessCode: loginAccessCode,
59
+ };
60
+
61
+ // store the access code and the access token in the database.
62
+ await this.userService.resolveUserOnOauthMicrosoft({
63
+ ...user,
64
+ accessToken: _accessToken,
65
+ refreshToken: null
66
+ });
67
+
68
+ done(null, user);
69
+ }
70
+ }
@@ -1511,7 +1511,7 @@
1511
1511
  "encrypt": false,
1512
1512
  "relationType": "many-to-many",
1513
1513
  "relationCoModelSingularName": "roleMetadata",
1514
- "relationCoModelFieldName": "users",
1514
+ "relationCoModelFieldName": "menuItems",
1515
1515
  "relationCreateInverse": true,
1516
1516
  "relationCascade": "set null",
1517
1517
  "relationModelModuleName": "solid-core",
@@ -3780,7 +3780,9 @@
3780
3780
  "audit_insert:audit_insert",
3781
3781
  "audit_update:audit_update",
3782
3782
  "audit_delete:audit_delete",
3783
- "custom:custom"
3783
+ "custom:custom",
3784
+ "note:note",
3785
+ "task:task"
3784
3786
  ]
3785
3787
  },
3786
3788
  {
@@ -3891,6 +3893,21 @@
3891
3893
  "private": false,
3892
3894
  "encrypt": false,
3893
3895
  "isSystem": false
3896
+ },
3897
+ {
3898
+ "name": "status",
3899
+ "displayName": "Message Status",
3900
+ "type": "selectionStatic",
3901
+ "defaultValue": "pending",
3902
+ "length": 256,
3903
+ "required": false,
3904
+ "index": false,
3905
+ "isSystem": false,
3906
+ "selectionValueType": "string",
3907
+ "selectionStaticValues": [
3908
+ "pending:pending",
3909
+ "completed:completed"
3910
+ ]
3894
3911
  }
3895
3912
  ]
3896
3913
  },
@@ -5907,7 +5924,8 @@
5907
5924
  },
5908
5925
  "permissions": [
5909
5926
  "mcp:invoke",
5910
- "agent:invoke"
5927
+ "agent:invoke",
5928
+ "settings:view_encrypted"
5911
5929
  ],
5912
5930
  "roles": [
5913
5931
  {
@@ -5951,6 +5969,7 @@
5951
5969
  "ChatterMessageController.getChatterMessages",
5952
5970
  "ChatterMessageController.postMessage",
5953
5971
  "ChatterMessageController.findMany",
5972
+ "ChatterMessageController.markCompleted",
5954
5973
  "ImportTransactionController.getImportTemplate",
5955
5974
  "ImportTransactionController.getImportInstructions",
5956
5975
  "ImportTransactionController.getImportMappingInfo",
@@ -6408,38 +6427,12 @@
6408
6427
  "modelUserKey": "userActivityHistory"
6409
6428
  },
6410
6429
  {
6411
- "displayName": "App Settings",
6412
- "name": "appSettings-action",
6413
- "type": "custom",
6414
- "domain": "",
6415
- "context": "",
6416
- "customComponent": "/admin/core/solid-core/settings/app-settings",
6417
- "customIsModal": true,
6418
- "serverEndpoint": "",
6419
- "viewUserKey": "",
6420
- "moduleUserKey": "solid-core",
6421
- "modelUserKey": "setting"
6422
- },
6423
- {
6424
- "displayName": "Authentication Settings Action",
6425
- "name": "authenticationSettings-action",
6426
- "type": "custom",
6427
- "domain": "",
6428
- "context": "",
6429
- "customComponent": "/admin/core/solid-core/settings/authentication-settings",
6430
- "customIsModal": true,
6431
- "serverEndpoint": "",
6432
- "viewUserKey": "",
6433
- "moduleUserKey": "solid-core",
6434
- "modelUserKey": "setting"
6435
- },
6436
- {
6437
- "displayName": "Misc Action",
6438
- "name": "miscSettings-action",
6430
+ "displayName": "Settings",
6431
+ "name": "settings-action",
6439
6432
  "type": "custom",
6440
6433
  "domain": "",
6441
6434
  "context": "",
6442
- "customComponent": "/admin/core/solid-core/settings/misc-settings",
6435
+ "customComponent": "/admin/core/settings",
6443
6436
  "customIsModal": true,
6444
6437
  "serverEndpoint": "",
6445
6438
  "viewUserKey": "",
@@ -6920,35 +6913,11 @@
6920
6913
  "displayName": "Settings",
6921
6914
  "name": "settings-menu-item",
6922
6915
  "sequenceNumber": 9,
6923
- "actionUserKey": "",
6916
+ "actionUserKey": "settings-action",
6924
6917
  "moduleUserKey": "solid-core",
6925
6918
  "parentMenuItemUserKey": "",
6926
6919
  "iconName": "settings"
6927
6920
  },
6928
- {
6929
- "displayName": "App Settings",
6930
- "name": "appSettings-menu-item",
6931
- "sequenceNumber": 1,
6932
- "actionUserKey": "appSettings-action",
6933
- "moduleUserKey": "solid-core",
6934
- "parentMenuItemUserKey": "settings-menu-item"
6935
- },
6936
- {
6937
- "displayName": "Authentication Settings",
6938
- "name": "authenticationSettings-menu-item",
6939
- "sequenceNumber": 2,
6940
- "actionUserKey": "authenticationSettings-action",
6941
- "moduleUserKey": "solid-core",
6942
- "parentMenuItemUserKey": "settings-menu-item"
6943
- },
6944
- {
6945
- "displayName": "Misc",
6946
- "name": "miscSettings-menu-item",
6947
- "sequenceNumber": 3,
6948
- "actionUserKey": "miscSettings-action",
6949
- "moduleUserKey": "solid-core",
6950
- "parentMenuItemUserKey": "settings-menu-item"
6951
- },
6952
6921
  {
6953
6922
  "displayName": "Model Sequence",
6954
6923
  "name": "modelSequence-menu-item",
@@ -10518,7 +10487,7 @@
10518
10487
  "edit": true,
10519
10488
  "delete": true,
10520
10489
  "groupBy": "stage",
10521
- "draggable": true,
10490
+ "draggable": false,
10522
10491
  "allowedViews": [
10523
10492
  "list",
10524
10493
  "kanban"
@@ -6,6 +6,7 @@ import {
6
6
  UnauthorizedException,
7
7
  } from '@nestjs/common';
8
8
  import { createHash, randomBytes } from 'crypto';
9
+ import { ERROR_MESSAGES } from 'src/constants/error-messages';
9
10
  import { CreateApiKeyDto } from 'src/dtos/create-api-key.dto';
10
11
  import { UpdateApiKeyDto } from 'src/dtos/update-api-key.dto';
11
12
  import { UserApiKey } from 'src/entities/user-api-key.entity';
@@ -13,6 +14,8 @@ import { User } from 'src/entities/user.entity';
13
14
  import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
14
15
  import { UserApiKeyRepository } from 'src/repository/user-api-key.repository';
15
16
  import { PermissionMetadataService } from 'src/services/permission-metadata.service';
17
+ import { AuthenticationService } from './authentication.service';
18
+ import { UserRepository } from 'src/repository/user.repository';
16
19
 
17
20
  @Injectable()
18
21
  export class ApiKeyService {
@@ -21,53 +24,55 @@ export class ApiKeyService {
21
24
  constructor(
22
25
  private readonly apiKeyRepository: UserApiKeyRepository,
23
26
  private readonly permissionMetadataService: PermissionMetadataService,
27
+ private readonly authenticationService: AuthenticationService,
28
+ private readonly userRepository: UserRepository,
24
29
  ) {}
25
30
 
26
- async generate(userId: number, dto: CreateApiKeyDto): Promise<{ apiKey: string; record: UserApiKey }> {
27
- const user = await this.apiKeyRepository.manager.findOne(User, {
28
- where: { id: userId },
29
- select: ['id', 'isAllowedToGenerateApiKeys'],
30
- });
31
+ async generate(userId: number, dto: CreateApiKeyDto): Promise < { apiKey: string; record: UserApiKey } > {
32
+ const user = await this.apiKeyRepository.manager.findOne(User, {
33
+ where: { id: userId },
34
+ select: ['id', 'isAllowedToGenerateApiKeys'],
35
+ });
31
36
 
32
- if (!user?.isAllowedToGenerateApiKeys) {
33
- throw new ForbiddenException('You are not allowed to generate API keys');
34
- }
37
+ if(!user?.isAllowedToGenerateApiKeys) {
38
+ throw new ForbiddenException('You are not allowed to generate API keys');
39
+ }
35
40
 
36
41
  const rawKey = 'sldx_' + randomBytes(32).toString('hex');
37
- const hashedKey = this.hash(rawKey);
38
- const maskedKey = 'sldx_****' + rawKey.slice(-4);
39
-
40
- const record = this.apiKeyRepository.create({
41
- name: dto.name,
42
- hashedKey,
43
- maskedKey,
44
- isActive: true,
45
- expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,
46
- user,
47
- });
42
+ const hashedKey = this.hash(rawKey);
43
+ const maskedKey = 'sldx_****' + rawKey.slice(-4);
48
44
 
49
- await this.apiKeyRepository.save(record);
45
+ const record = this.apiKeyRepository.create({
46
+ name: dto.name,
47
+ hashedKey,
48
+ maskedKey,
49
+ isActive: true,
50
+ expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,
51
+ user,
52
+ });
50
53
 
51
- // Strip hashedKey from the returned record — maskedKey is all the UI needs
52
- delete (record as any).hashedKey;
54
+ await this.apiKeyRepository.save(record);
53
55
 
54
- return { apiKey: rawKey, record };
55
- }
56
+ // Strip hashedKey from the returned record — maskedKey is all the UI needs
57
+ delete(record as any).hashedKey;
56
58
 
57
- async validate(rawKey: string): Promise<ActiveUserData> {
58
- const hashedKey = this.hash(rawKey);
59
+ return { apiKey: rawKey, record };
60
+ }
59
61
 
60
- // Bypass security rules for auth validation — must find the key regardless of caller context
61
- const keyRecord = await this.apiKeyRepository.findOne({
62
- where: { hashedKey, isActive: true },
63
- relations: ['user', 'user.roles'],
64
- });
62
+ async validate(rawKey: string): Promise < ActiveUserData > {
63
+ const hashedKey = this.hash(rawKey);
65
64
 
66
- if (!keyRecord) {
67
- throw new UnauthorizedException();
68
- }
65
+ // Bypass security rules for auth validation — must find the key regardless of caller context
66
+ const keyRecord = await this.apiKeyRepository.findOne({
67
+ where: { hashedKey, isActive: true },
68
+ relations: ['user', 'user.roles'],
69
+ });
69
70
 
70
- if (keyRecord.expiresAt && keyRecord.expiresAt < new Date()) {
71
+ if(!keyRecord) {
72
+ throw new UnauthorizedException();
73
+ }
74
+
75
+ if(keyRecord.expiresAt && keyRecord.expiresAt < new Date()) {
71
76
  throw new UnauthorizedException('API key expired');
72
77
  }
73
78
 
@@ -105,6 +110,43 @@ export class ApiKeyService {
105
110
  .execute();
106
111
  }
107
112
 
113
+
114
+ async apiKeyMe(apiKey: string) {
115
+
116
+ const hasedKey = this.hash(apiKey);
117
+ const apiKeyRecord = await this.apiKeyRepository.findOne({
118
+ where: {
119
+ hashedKey: hasedKey,
120
+ },
121
+ relations: {
122
+ user: {
123
+ roles: true
124
+ }
125
+ }
126
+ });
127
+
128
+ if (!apiKeyRecord) {
129
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
130
+ }
131
+
132
+ const user = apiKeyRecord.user;
133
+
134
+ const tokens = await this.authenticationService.generateTokens(user);
135
+
136
+
137
+ return {
138
+ user: {
139
+ email: user.email,
140
+ mobile: user.mobile,
141
+ username: user.username,
142
+ forcePasswordChange: user.forcePasswordChange,
143
+ id: user.id,
144
+ roles: user.roles.map((role) => role.name)
145
+ },
146
+ ...tokens
147
+ }
148
+ }
149
+
108
150
  private hash(rawKey: string): string {
109
151
  return createHash('sha256').update(rawKey).digest('hex');
110
152
  }