prow-authority 3.6.3

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 (168) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.dockerignore +11 -0
  3. package/.github/workflows/_deploy.yml +191 -0
  4. package/.github/workflows/deploy-dev.yml +30 -0
  5. package/.github/workflows/deploy-prod.yml +34 -0
  6. package/CLAUDE.md +114 -0
  7. package/Dockerfile +61 -0
  8. package/Dockerfile.dev +24 -0
  9. package/README.md +1 -0
  10. package/package.json +61 -0
  11. package/src/App.ts +40 -0
  12. package/src/helpers/api-error.ts +21 -0
  13. package/src/helpers/authority.ts +216 -0
  14. package/src/helpers/config.ts +4 -0
  15. package/src/helpers/holded.ts +105 -0
  16. package/src/helpers/mysql.ts +15 -0
  17. package/src/helpers/notifications.ts +55 -0
  18. package/src/helpers/random.ts +18 -0
  19. package/src/helpers/s3.ts +43 -0
  20. package/src/helpers/stripe.ts +8 -0
  21. package/src/index.ts +47 -0
  22. package/src/v1/common-types.ts +12 -0
  23. package/src/v1/controllers/admin/accounting-seat-controller.ts +148 -0
  24. package/src/v1/controllers/admin/billing-cycle-controller.ts +171 -0
  25. package/src/v1/controllers/admin/invoice-controller.ts +222 -0
  26. package/src/v1/controllers/admin/license-controller.ts +190 -0
  27. package/src/v1/controllers/admin/license-limit-controller.ts +160 -0
  28. package/src/v1/controllers/admin/notification-controller.ts +115 -0
  29. package/src/v1/controllers/admin/organization-controller.ts +210 -0
  30. package/src/v1/controllers/admin/organization-license-controller.ts +224 -0
  31. package/src/v1/controllers/admin/organization-license-limit-controller.ts +196 -0
  32. package/src/v1/controllers/admin/organization-usage-controller.ts +167 -0
  33. package/src/v1/controllers/admin/payment-method-controller.ts +173 -0
  34. package/src/v1/controllers/admin/policy-controller.ts +138 -0
  35. package/src/v1/controllers/admin/policy-version-controller.ts +143 -0
  36. package/src/v1/controllers/admin/schedule-controller.ts +181 -0
  37. package/src/v1/controllers/admin/service-controller.ts +206 -0
  38. package/src/v1/controllers/admin/service-notification-controller.ts +166 -0
  39. package/src/v1/controllers/admin/user-controller.ts +282 -0
  40. package/src/v1/controllers/admin/user-organization-controller.ts +172 -0
  41. package/src/v1/controllers/admin/user-policy-controller.ts +164 -0
  42. package/src/v1/controllers/auth/@deprecated oauth-controller.ts +191 -0
  43. package/src/v1/controllers/auth/identity-token-controller.ts +286 -0
  44. package/src/v1/controllers/auth/organization-token-controller.ts +277 -0
  45. package/src/v1/controllers/auth/temp-code-controller.ts +60 -0
  46. package/src/v1/controllers/billing/billing-controller.ts +805 -0
  47. package/src/v1/controllers/organizations/public-organization-controller.ts +1796 -0
  48. package/src/v1/controllers/policies/public-policy-controller.ts +68 -0
  49. package/src/v1/controllers/services/public-service-controller.ts +177 -0
  50. package/src/v1/controllers/services/service-controller.ts +474 -0
  51. package/src/v1/controllers/users/public-user-controller.ts +471 -0
  52. package/src/v1/daos/@deprecated auth-dao.ts +173 -0
  53. package/src/v1/daos/accounting-seat-dao.ts +111 -0
  54. package/src/v1/daos/billing-cycle-dao.ts +107 -0
  55. package/src/v1/daos/invoice-dao.ts +131 -0
  56. package/src/v1/daos/license-dao.ts +152 -0
  57. package/src/v1/daos/license-limit-dao.ts +120 -0
  58. package/src/v1/daos/organization-dao.ts +109 -0
  59. package/src/v1/daos/organization-license-dao.ts +117 -0
  60. package/src/v1/daos/organization-license-limit-dao.ts +157 -0
  61. package/src/v1/daos/organization-usage-dao.ts +115 -0
  62. package/src/v1/daos/payment-method-dao.ts +110 -0
  63. package/src/v1/daos/policy-dao.ts +105 -0
  64. package/src/v1/daos/policy-version-dao.ts +112 -0
  65. package/src/v1/daos/redis-dao.ts +38 -0
  66. package/src/v1/daos/schema.sql +462 -0
  67. package/src/v1/daos/service-dao.ts +118 -0
  68. package/src/v1/daos/service-notification-dao.ts +120 -0
  69. package/src/v1/daos/user-dao.ts +127 -0
  70. package/src/v1/daos/user-organization-dao.ts +123 -0
  71. package/src/v1/daos/user-policy-dao.ts +109 -0
  72. package/src/v1/middlewares/auth/identity-token-middleware.ts +51 -0
  73. package/src/v1/middlewares/auth/organization-token-middleware.ts +73 -0
  74. package/src/v1/middlewares/auth/service-token-middleware.ts +167 -0
  75. package/src/v1/middlewares/authority-middleware.ts +97 -0
  76. package/src/v1/middlewares/organizations/organization-middleware.ts +94 -0
  77. package/src/v1/middlewares/static/static-middleware.ts +41 -0
  78. package/src/v1/middlewares/users/user-middleware.ts +41 -0
  79. package/src/v1/routes/admin/accounting-seat-router.ts +89 -0
  80. package/src/v1/routes/admin/admin-router.ts +61 -0
  81. package/src/v1/routes/admin/billing-cycle-router.ts +89 -0
  82. package/src/v1/routes/admin/invoice-router.ts +89 -0
  83. package/src/v1/routes/admin/license-limit-router.ts +89 -0
  84. package/src/v1/routes/admin/license-router.ts +89 -0
  85. package/src/v1/routes/admin/notification-router.ts +61 -0
  86. package/src/v1/routes/admin/organization-license-limit-router.ts +89 -0
  87. package/src/v1/routes/admin/organization-license-router.ts +89 -0
  88. package/src/v1/routes/admin/organization-router.ts +89 -0
  89. package/src/v1/routes/admin/payment-method-router.ts +89 -0
  90. package/src/v1/routes/admin/policy-router.ts +89 -0
  91. package/src/v1/routes/admin/policy-version-router.ts +89 -0
  92. package/src/v1/routes/admin/schedule-router.ts +75 -0
  93. package/src/v1/routes/admin/service-notification-router.ts +98 -0
  94. package/src/v1/routes/admin/service-router.ts +89 -0
  95. package/src/v1/routes/admin/user-organization-router.ts +89 -0
  96. package/src/v1/routes/admin/user-policy-router.ts +89 -0
  97. package/src/v1/routes/admin/user-router.ts +89 -0
  98. package/src/v1/routes/auth/@deprecated auth-router.ts +199 -0
  99. package/src/v1/routes/auth/identity-token-router.ts +147 -0
  100. package/src/v1/routes/auth/organization-token-router.ts +70 -0
  101. package/src/v1/routes/billing/billing-router.ts +227 -0
  102. package/src/v1/routes/organizations/invoices-router.ts +48 -0
  103. package/src/v1/routes/organizations/payments-router.ts +104 -0
  104. package/src/v1/routes/organizations/public-organization-router.ts +319 -0
  105. package/src/v1/routes/organizations/users-router.ts +139 -0
  106. package/src/v1/routes/policies/public-policy-router.ts +50 -0
  107. package/src/v1/routes/services/public-service-router.ts +89 -0
  108. package/src/v1/routes/services/service-router.ts +197 -0
  109. package/src/v1/routes/users/public-user-router.ts +230 -0
  110. package/src/v1/routes/v1-router.ts +50 -0
  111. package/src/v1/schemas/admin/accounting-seat-schemas.ts +22 -0
  112. package/src/v1/schemas/admin/billing-cycle-schemas.ts +20 -0
  113. package/src/v1/schemas/admin/invoice-schemas.ts +41 -0
  114. package/src/v1/schemas/admin/license-limit-schemas.ts +25 -0
  115. package/src/v1/schemas/admin/license-schemas.ts +30 -0
  116. package/src/v1/schemas/admin/organization-license-limit-schemas.ts +29 -0
  117. package/src/v1/schemas/admin/organization-license-schemas.ts +43 -0
  118. package/src/v1/schemas/admin/organization-schemas.ts +67 -0
  119. package/src/v1/schemas/admin/organization-usage-schemas.ts +15 -0
  120. package/src/v1/schemas/admin/payment-method-schemas.ts +40 -0
  121. package/src/v1/schemas/admin/policy-schemas.ts +31 -0
  122. package/src/v1/schemas/admin/service-notification-schemas.ts +23 -0
  123. package/src/v1/schemas/admin/service-schemas.ts +56 -0
  124. package/src/v1/schemas/admin/user-organization-schemas.ts +24 -0
  125. package/src/v1/schemas/admin/user-policy-schemas.ts +17 -0
  126. package/src/v1/schemas/admin/user-schemas.ts +52 -0
  127. package/src/v1/schemas/auth/auth-schemas.ts +55 -0
  128. package/src/v1/schemas/billing/billing-schemas.ts +32 -0
  129. package/src/v1/schemas/organizations/public-organization-schemas.ts +77 -0
  130. package/src/v1/schemas/payments/payment-method-schemas.ts +0 -0
  131. package/src/v1/schemas/services/public-service-schemas.ts +5 -0
  132. package/src/v1/schemas/services/service-schemas.ts +27 -0
  133. package/src/v1/schemas/users/public-user-schemas.ts +73 -0
  134. package/src/v1/types/admin/accounting-seat-types.ts +16 -0
  135. package/src/v1/types/admin/billing-cycle-types.ts +14 -0
  136. package/src/v1/types/admin/invoice-types.ts +39 -0
  137. package/src/v1/types/admin/license-limit-types.ts +16 -0
  138. package/src/v1/types/admin/license-types.ts +29 -0
  139. package/src/v1/types/admin/organization-license-limit-types.ts +13 -0
  140. package/src/v1/types/admin/organization-license-types.ts +21 -0
  141. package/src/v1/types/admin/organization-types.ts +60 -0
  142. package/src/v1/types/admin/organization-usage-types.ts +17 -0
  143. package/src/v1/types/admin/payment-method-types.ts +30 -0
  144. package/src/v1/types/admin/policy-types.ts +9 -0
  145. package/src/v1/types/admin/policy-version-types.ts +12 -0
  146. package/src/v1/types/admin/service-notification-types.ts +20 -0
  147. package/src/v1/types/admin/service-types.ts +36 -0
  148. package/src/v1/types/admin/user-organization-types.ts +31 -0
  149. package/src/v1/types/admin/user-types.ts +44 -0
  150. package/src/v1/types/auth/@deprecated auth-types.ts +26 -0
  151. package/src/v1/types/auth/common-types.ts +7 -0
  152. package/src/v1/types/auth/confirmation-types.ts +5 -0
  153. package/src/v1/types/auth/identity-token-types.ts +8 -0
  154. package/src/v1/types/auth/organization-token-types.ts +23 -0
  155. package/src/v1/types/auth/otp-types.ts +12 -0
  156. package/src/v1/types/billing/billing-types.ts +37 -0
  157. package/src/v1/types/billing/ue-types.ts +29 -0
  158. package/src/v1/types/organizations/public-organization-types.ts +76 -0
  159. package/src/v1/types/policies/public-policy-types.ts +7 -0
  160. package/src/v1/types/services/public-service-types.ts +20 -0
  161. package/src/v1/types/services/service-types.ts +43 -0
  162. package/src/v1/types/users/public-user-types.ts +15 -0
  163. package/src/v1/types/users/user-policy-types.ts +11 -0
  164. package/static/error.html +55 -0
  165. package/static/grant.html +117 -0
  166. package/static/login.html +54 -0
  167. package/static/oauth-client-logo.webp +0 -0
  168. package/tsconfig.json +20 -0
@@ -0,0 +1,216 @@
1
+ import Authority from '@beseif-solutions/prow-authority-for-services';
2
+ import { User } from '../v1/types/admin/user-types';
3
+ import { Organization } from '../v1/types/admin/organization-types';
4
+ import { Service } from '../v1/types/admin/service-types';
5
+ import { Quota } from '../v1/types/services/service-types';
6
+ import { UserOrganization, UserOrganizationRole } from '../v1/types/admin/user-organization-types';
7
+ import nconf from "./config";
8
+
9
+ export enum LicenseLimitNames {
10
+ Seats = `organization.seats`,
11
+ }
12
+
13
+ export enum NotificationEventNames {
14
+ OrganizationAdded = `organization_added`,
15
+ OrganizationRemoved = `organization_removed`,
16
+ MemberAdded = `member_added`,
17
+ MemberRemoved = `member_removed`,
18
+ MemberInvited = `member_invited`,
19
+ BillingChanged = `billing_changed`,
20
+ ServiceAccessWarning = `service_access_warning`,
21
+ ServiceAccessBlocked = `service_access_blocked`,
22
+ LicenseLimitApproaching = `license_limit_approaching`,
23
+ LicenseLimitReached = `license_limit_reached`,
24
+ LicenseUpgraded = `license_upgraded`,
25
+ LicenseDowngraded = `license_downgraded`,
26
+ LicenseDowngradeScheduled = `license_downgrade_scheduled`,
27
+ PowerUpAdded = `powerup_added`,
28
+ PowerUpRemoved = `powerup_removed`,
29
+ InvoiceEmitted = `invoice_emitted`,
30
+ TrialEnded = `trial_ended`,
31
+ TrialEndingSoon = `trial_ending_soon`,
32
+ }
33
+
34
+ export type OrganizationAdded = {
35
+ cta: {
36
+ dashboard: string, // organization dashboard
37
+ preferences: string, // notifications settings
38
+ },
39
+ organization: Organization,
40
+ };
41
+
42
+ export type OrganizationRemoved = {
43
+ cta: {
44
+ dashboard: string, // remaining organizations
45
+ preferences: string, // notifications settings
46
+ },
47
+ organization: Organization,
48
+ };
49
+
50
+ export type MemberAdded = {
51
+ user: User,
52
+ role: string,
53
+ organization: Organization,
54
+ cta: {
55
+ members: string, // manage members
56
+ preferences: string, // notification preferences
57
+ },
58
+ };
59
+
60
+ export type MemberRemoved = {
61
+ user: User,
62
+ organization: Organization,
63
+ cta: {
64
+ members: string, // manage members
65
+ preferences: string, // notification preferences
66
+ },
67
+ };
68
+
69
+ export type MemberInvited = {
70
+ role: string,
71
+ organization: Organization,
72
+ cta: {
73
+ organizations: string, // organization dashboard
74
+ preferences: string, // notification preferences
75
+ },
76
+ };
77
+
78
+ export type BillingChanged = {
79
+ organization: Organization,
80
+ cta: {
81
+ billing: string, // billing settings
82
+ preferences: string, // notification preferences
83
+ },
84
+ };
85
+
86
+ export type ServiceAccessWarning = {
87
+ days: number,
88
+ organization: Organization,
89
+ cta: {
90
+ usage: string, // usage
91
+ preferences: string, // notification preferences
92
+ },
93
+ };
94
+
95
+ export type ServiceAccessBlocked = {
96
+ organization: Organization,
97
+ service: Service,
98
+ cta: {
99
+ usage: string, // usage
100
+ upgrade: string, // upgrade plan
101
+ preferences: string, // notification preferences
102
+ },
103
+ };
104
+
105
+ export type LicenseLimitApproaching = {
106
+ limit: Quota & { percentage: number },
107
+ organization: Organization,
108
+ cta: {
109
+ upgrade: string, // upgrade plan
110
+ preferences: string, // notification preferences
111
+ },
112
+ };
113
+
114
+ export type LicenseLimitReached = {
115
+ limit: Quota,
116
+ organization: Organization,
117
+ cta: {
118
+ upgrade: string, // upgrade plan
119
+ preferences: string, // notification preferences
120
+ },
121
+ };
122
+
123
+ export type LicenseUpgraded = {
124
+ organization: Organization,
125
+ cta: {
126
+ dashboard: string, // organization dashboard
127
+ preferences: string, // notification preferences
128
+ },
129
+ };
130
+
131
+ export type LicenseDowngraded = {
132
+ organization: Organization,
133
+ cta: {
134
+ dashboard: string, // organization dashboard
135
+ preferences: string, // notification preferences
136
+ },
137
+ };
138
+
139
+ export type LicenseDowngradeScheduled = {
140
+ organization: Organization,
141
+ scheduled_date: string, // date when the downgrade takes effect
142
+ cta: {
143
+ subscription: string, // manage subscription
144
+ preferences: string, // notification preferences
145
+ },
146
+ };
147
+
148
+ export type PowerUpAdded = {
149
+ organization: Organization,
150
+ cta: {
151
+ dashboard: string, // organization dashboard
152
+ preferences: string, // notification preferences
153
+ },
154
+ };
155
+
156
+ export type PowerUpRemoved = {
157
+ organization: Organization,
158
+ cta: {
159
+ dashboard: string, // organization dashboard
160
+ preferences: string, // notification preferences
161
+ },
162
+ };
163
+
164
+ export type InvoiceEmitted = {
165
+ organization: Organization,
166
+ invoice: { number: string, amount: number },
167
+ cta: {
168
+ preferences: string, // notification preferences
169
+ },
170
+ };
171
+
172
+ export type TrialEnded = {
173
+ organization: Organization,
174
+ cta: {
175
+ subscription: string, // review/choose plan
176
+ billing: string, // add payment method
177
+ preferences: string, // notification preferences
178
+ },
179
+ };
180
+
181
+ export type TrialEndingSoon = {
182
+ organization: Organization,
183
+ end_date: string, // date the trial ends
184
+ cta: {
185
+ subscription: string, // review/choose plan
186
+ billing: string, // add payment method
187
+ preferences: string, // notification preferences
188
+ },
189
+ };
190
+
191
+ export type ResourceModelName = `organization.seat` | `organization.organization`;
192
+
193
+ export const omnipotentAccess = (user: User, organization: Organization): UserOrganization => ({
194
+ id: 0,
195
+ user: user.id,
196
+ organization: organization.id,
197
+ role: UserOrganizationRole.Owner,
198
+ invite: null,
199
+ invited_by: null,
200
+ preferences: {},
201
+ created_date: organization.created_date,
202
+ modified_date: organization.modified_date,
203
+ enabled: true,
204
+ metadata: { omnipotent: true },
205
+ });
206
+
207
+ const authority = new Authority<{
208
+ license: { limits: LicenseLimitNames },
209
+ notifications: { events: NotificationEventNames },
210
+ }>({
211
+ host: nconf.get(`SERVICES:AUTHORITY:HOST`),
212
+ uuid: nconf.get(`SERVICES:AUTHORITY:UUID`),
213
+ token: nconf.get(`SERVICES:AUTHORITY:TOKEN`),
214
+ });
215
+
216
+ export default authority;
@@ -0,0 +1,4 @@
1
+ import { YamlParser } from '@beseif-solutions/utility-functions/dist/utils/string-utils';
2
+
3
+ const nconf = new YamlParser({ path: __dirname, filename: `../../config/config.yaml` });
4
+ export default nconf;
@@ -0,0 +1,105 @@
1
+ import { Requester } from "@beseif-solutions/utility-functions/dist/utils/http-utils";
2
+ import nconf from "./config";
3
+
4
+ class Holded {
5
+
6
+ private readonly apikey = nconf.get(`SERVICES:HOLDED:APIKEY`);
7
+
8
+ private readonly configuration = {
9
+ baseURL: `https://api.holded.com`,
10
+ headers: {
11
+ "Key": this.apikey,
12
+ },
13
+ } as const;
14
+
15
+ public readonly getInvoice = async (id: string): Promise<{ id: string, docNumber: string }> => {
16
+ try {
17
+ const response = await Requester.get(`/api/invoicing/v1/documents/invoice/${id}`, this.configuration);
18
+ return response;
19
+ } catch (e) { throw e; }
20
+ };
21
+
22
+ public readonly getInvoicePDF = async (id: string): Promise<{ status: number, data: string }> => {
23
+ try {
24
+ const response = await Requester.get(`/api/invoicing/v1/documents/invoice/${id}/pdf`, this.configuration);
25
+ return response;
26
+ } catch (e) { throw e; }
27
+ };
28
+
29
+ public readonly listContacts = async (params: { customId?: string }): Promise<Holded.Contact[]> => {
30
+ try {
31
+ const response = await Requester.get(`/api/invoicing/v1/contacts?${new URLSearchParams(params).toString()}`, this.configuration);
32
+ return response;
33
+ } catch (e) { throw e; }
34
+ };
35
+
36
+ public readonly createContact = async (params: Holded.AddContact): Promise<Holded.Contact> => {
37
+ try {
38
+ const response = await Requester.post(`/api/invoicing/v1/contacts`, params, this.configuration);
39
+ return response;
40
+ } catch (e) { throw e; }
41
+ };
42
+
43
+ public readonly updateContacts = async (id: string, params: Partial<Holded.AddContact>): Promise<Holded.Contact> => {
44
+ try {
45
+ const response = await Requester.put(`/api/invoicing/v1/contacts/${id}`, params, this.configuration);
46
+ return response;
47
+ } catch (e) { throw e; }
48
+ };
49
+
50
+ public readonly createAccount = async (params: { name: string, prefix: number }): Promise<Holded.Account> => {
51
+ try {
52
+ const account = await Requester.post(`/api/accounting/v1/account`, params, this.configuration) as { accountId: string };
53
+
54
+ const response = await Requester.get(`/api/invoicing/v1/expensesaccounts/${account.accountId}`, this.configuration);
55
+ return response;
56
+ } catch (e) { throw e; }
57
+ };
58
+
59
+ public readonly updateAccount = async (id: string, params: { name: string }): Promise<Holded.Account> => {
60
+ try {
61
+ await Requester.put(`/api/invoicing/v1/expensesaccounts/${id}`, params, this.configuration) as { status: number, info: string, id: string };
62
+
63
+ const response = await Requester.get(`/api/invoicing/v1/expensesaccounts/${id}`, this.configuration);
64
+ return response;
65
+ } catch (e) { throw e; }
66
+ };
67
+ }
68
+
69
+ const holded = new Holded();
70
+ export default holded;
71
+
72
+ export namespace Holded {
73
+
74
+ export type Contact = { id: string, clientRecord: { num: number, name: string } };
75
+
76
+ export type AddContact = {
77
+ customId: string,
78
+ name: string,
79
+ code: string,
80
+ email: string,
81
+ phone: string,
82
+ type: `supplier` | `debtor` | `creditor` | `client` | `lead`,
83
+ isperson: boolean,
84
+ clientRecord?: number,
85
+ billAddress: {
86
+ address: string,
87
+ city: string,
88
+ postalCode: string,
89
+ province: string,
90
+ country: string,
91
+ },
92
+ };
93
+
94
+ export type Account = {
95
+ id: string,
96
+ name: string,
97
+ color: string,
98
+ accountNum: number,
99
+ };
100
+
101
+ export type AddAccount = {
102
+ prefix: number,
103
+ name: string,
104
+ };
105
+ }
@@ -0,0 +1,15 @@
1
+ import { MySQL } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
2
+ import nconf from "./config";
3
+
4
+ const mysql = new MySQL({
5
+ host: nconf.get(`SERVICES:RDS:URL`),
6
+ port: nconf.get(`SERVICES:RDS:PORT`),
7
+ user: nconf.get(`SERVICES:RDS:USER`),
8
+ password: nconf.get(`SERVICES:RDS:PASSWORD`),
9
+ database: nconf.get(`SERVICES:RDS:DATABASE`),
10
+ connectionLimit: 5,
11
+ connectTimeout: 10000,
12
+ });
13
+ export default mysql;
14
+
15
+
@@ -0,0 +1,55 @@
1
+ import { Requester } from "@beseif-solutions/utility-functions/dist/utils/http-utils";
2
+ import nconf from "./config";
3
+ import { RequireMinOne } from "@beseif-solutions/utility-functions/dist/utils/typing-utils";
4
+
5
+ type GmailNotification = RequireMinOne<{
6
+ to: string[],
7
+ cc: string[],
8
+ bcc: string[],
9
+ }> & {
10
+ locale?: string,
11
+ template: string,
12
+ arguments: Record<string, any>,
13
+ attachments?: {
14
+ name: string,
15
+ type: string,
16
+ content: string,
17
+ }[],
18
+ };
19
+
20
+ type SlackNotification = {
21
+ channels?: string[],
22
+ messages: string[],
23
+ };
24
+
25
+ class Notifications {
26
+
27
+ private readonly config = async () => ({
28
+ baseURL: nconf.get(`SERVICES:NOTIFICATIONS:URL`),
29
+ headers: {
30
+ [nconf.get(`SERVICES:NOTIFICATIONS:AUTHORIZATION:HEADER`)]: nconf.get(`SERVICES:NOTIFICATIONS:AUTHORIZATION:TOKEN`),
31
+ "Content-Type": `application/json`,
32
+ },
33
+ });
34
+
35
+ public readonly gmail = async (params: GmailNotification): Promise<any> => {
36
+ try {
37
+ return await Requester.post(`/api/v1/gmail`, {
38
+ from: nconf.get(`SERVICES:NOTIFICATIONS:NAME`),
39
+ ...params,
40
+ }, await this.config());
41
+ } catch (e) { throw e; }
42
+ };
43
+
44
+ public readonly slack = async (params: SlackNotification): Promise<any> => {
45
+ try {
46
+ return await Requester.post(`/api/v1/slack`, {
47
+ name: nconf.get(`SERVICES:NOTIFICATIONS:NAME`),
48
+ ...params,
49
+ }, await this.config());
50
+ } catch (e) { throw e; }
51
+ };
52
+ }
53
+
54
+ const notifications = new Notifications();
55
+ export default notifications;
@@ -0,0 +1,18 @@
1
+ import crypto from 'crypto';
2
+
3
+ export const NUMERIC_CHARSET = `0123456789`;
4
+ export const LOWER_CHAR_CHARSET = `abcdefghijklmnopqrstuvwxyz`;
5
+ export const UPPER_CHAR_CHARSET = `ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
6
+ export const SPECIAL_CHARSET = `-./#`;
7
+ export const ALPHA_CHARSET = `${LOWER_CHAR_CHARSET}${UPPER_CHAR_CHARSET}`;
8
+ export const ALPHANUMERIC_CHARSET = `${ALPHA_CHARSET}${NUMERIC_CHARSET}`;
9
+ export const ALL_CHARSET = `${ALPHANUMERIC_CHARSET}${SPECIAL_CHARSET}`;
10
+
11
+ export const generateRandomString = (charset: string, length: number): string => {
12
+ if (length <= 0) { throw new Error(`Length must be greater than 0`); }
13
+ if (!charset) { throw new Error(`Charset cannot be empty`); }
14
+
15
+ return new Array(length).fill(``)
16
+ .map(() => charset[crypto.randomInt(0, charset.length)])
17
+ .join(``);
18
+ };
@@ -0,0 +1,43 @@
1
+ import { S3 } from "@beseif-solutions/utility-functions/dist/utils/file-utils";
2
+ import nconf from "./config";
3
+
4
+ const s3 = new S3({
5
+ keyId: nconf.get(`SERVICES:S3:ACCESSKEY`),
6
+ secret: nconf.get(`SERVICES:S3:SECRETACCESSKEY`),
7
+ region: nconf.get(`SERVICES:S3:REGION`),
8
+ });
9
+
10
+ type Entity = `users` | `organizations` | `services`;
11
+ type Names = `avatar` | `cover`;
12
+
13
+ type Config = {
14
+ entity: Entity,
15
+ uuid: string,
16
+ name: Names,
17
+ };
18
+
19
+ export const uploadFile = async (config: Config, content: string): Promise<string> => {
20
+ try {
21
+ const upload = await s3.upload({
22
+ bucket: nconf.get(`SERVICES:S3:BUCKET`),
23
+ path: `prow-authority/${config.entity}/${config.uuid}`,
24
+ acl: `public-read`,
25
+ name: config.name,
26
+ content: {
27
+ type: `application/x-octet-stream`,
28
+ data: content,
29
+ },
30
+ });
31
+ return upload.url;
32
+ } catch (e) { throw e; }
33
+ };
34
+
35
+ export const deleteFile = async (config: Config): Promise<void> => {
36
+ try {
37
+ await s3.delete({
38
+ bucket: nconf.get(`SERVICES:S3:BUCKET`),
39
+ path: `prow-authority/${config.entity}/${config.uuid}`,
40
+ name: config.name,
41
+ });
42
+ } catch (e) { throw e; }
43
+ };
@@ -0,0 +1,8 @@
1
+ import Stripe from "stripe";
2
+ import nconf from "./config";
3
+
4
+ const stripe = new Stripe(nconf.get(`SERVICES:STRIPE:APIKEY`), {
5
+ apiVersion: `2025-08-27.basil`,
6
+ });
7
+
8
+ export default stripe;
package/src/index.ts ADDED
@@ -0,0 +1,47 @@
1
+ import 'colors';
2
+ import http from 'http';
3
+ import App from './App';
4
+ import nconf from './helpers/config';
5
+
6
+
7
+ console.log(`Starting prow-authority server`.yellow, (new Date()).toLocaleString());
8
+
9
+ const DEFAULT_PORT = 3000;
10
+
11
+ const normalizePort = (val: number | string): number | string | boolean => {
12
+ const p: number = (typeof val === `string`) ? parseInt(val, 10) : val;
13
+ if (isNaN(p)) { return val; } else if (p >= 0) { return p; } else { return false; }
14
+ };
15
+
16
+ const onError = (error: NodeJS.ErrnoException): void => {
17
+ if (error.syscall !== `listen`) { throw error; }
18
+ const bind = (typeof port === `string`) ? `Pipe ` + port : `Port ${port}`;
19
+ switch (error.code) {
20
+ case `EACCES`:
21
+ console.error(`${bind} requires elevated privileges`);
22
+ process.exit(1);
23
+ break;
24
+ case `EADDRINUSE`:
25
+ console.error(`${bind} is already in use`);
26
+ process.exit(1);
27
+ break;
28
+ default:
29
+ throw error;
30
+ }
31
+ };
32
+
33
+ const onListening = (): void => {
34
+ const addr = server.address();
35
+ const bind = (typeof addr === `string`) ? `pipe ${addr}` : `port ${addr.port}`;
36
+ const now = new Date();
37
+ console.log(`${now.toLocaleDateString()} ${now.toLocaleTimeString()}: Listening on ${bind}`.cyan);
38
+ };
39
+
40
+ const port = normalizePort(nconf.get(`SERVICES:PORT`) || DEFAULT_PORT);
41
+ App.set(`port`, port);
42
+
43
+ const server = http.createServer(App);
44
+ server.listen(port);
45
+ server.on(`error`, onError);
46
+ server.on(`listening`, onListening);
47
+
@@ -0,0 +1,12 @@
1
+
2
+ export type Modifiers = {
3
+ order?: {
4
+ by: string | string[],
5
+ direction: `descendent` | `ascendent`,
6
+ },
7
+ limit?: {
8
+ from?: string,
9
+ count: string,
10
+ },
11
+ timeout?: string,
12
+ };
@@ -0,0 +1,148 @@
1
+ import { Date2, Formats } from "@beseif-solutions/utility-functions/dist/utils/date-utils";
2
+ import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
3
+ import { Where } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
4
+ import { newUUIDv4 } from "@beseif-solutions/utility-functions/dist/utils/string-utils";
5
+ // typing-utils not required here
6
+ import { Validator } from "@beseif-solutions/utility-functions/dist/utils/validation-utils";
7
+ import APIError, { StatusCodes } from "../../../helpers/api-error";
8
+ import accountingSeatDao from "../../daos/accounting-seat-dao";
9
+ import { addAccountingSeatSchema, updateAccountingSeatSchema } from "../../schemas/admin/accounting-seat-schemas";
10
+ import { AccountingSeat, DBRecord } from "../../types/admin/accounting-seat-types";
11
+ import { Modifiers } from "../../common-types";
12
+
13
+ type Add = Omit<AccountingSeat, `id` | `uuid`>;
14
+ type Update = Partial<Add>;
15
+
16
+ class AccountingSeatCtrl {
17
+ public readonly get = async (id: number): Promise<AccountingSeat[]> => {
18
+ try {
19
+ const db = await accountingSeatDao.get({ id: id });
20
+ const response = await this.parse(db);
21
+ return response;
22
+ } catch (e) { throw e; }
23
+ };
24
+
25
+ public readonly list = async (params: Where<DBRecord>, options: Modifiers = {}): Promise<AccountingSeat[]> => {
26
+ try {
27
+ const db = await accountingSeatDao.list({ ...params }, options);
28
+ const response = await this.parse(db);
29
+ return response;
30
+ } catch (e) { throw e; }
31
+ };
32
+
33
+ public readonly add = async (data: Add): Promise<AccountingSeat[]> => {
34
+ try {
35
+ await Validator.validateAsync(addAccountingSeatSchema, data);
36
+
37
+ const uuid = await this.getFreeUUID();
38
+
39
+ const { insertId } = await accountingSeatDao.add({
40
+ uuid: uuid,
41
+ organization: data.organization,
42
+ invoice: data.invoice || null,
43
+ date: data.date,
44
+ amount: data.amount,
45
+ done: data.done || false,
46
+ metadata: data.metadata || {},
47
+ internal: data.internal || {},
48
+ } as any);
49
+
50
+ return await this.get(insertId);
51
+ } catch (e) { throw e; }
52
+ };
53
+
54
+ public readonly update = async (id: number, data: Update): Promise<AccountingSeat[]> => {
55
+ try {
56
+ await Validator.validateAsync(updateAccountingSeatSchema, data);
57
+
58
+ const old = (await this.get(id))[0];
59
+ if (!old) {
60
+ throw new APIError({ code: StatusCodes.NOT_FOUND, detail: `Billing seat with id ${id} not found.` });
61
+ }
62
+
63
+ const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as AccountingSeat;
64
+
65
+ const { affectedRows } = await accountingSeatDao.update({ id: id }, {
66
+ uuid: merged.uuid,
67
+ organization: merged.organization,
68
+ invoice: merged.invoice,
69
+ date: merged.date,
70
+ amount: merged.amount,
71
+ done: merged.done,
72
+ metadata: merged.metadata,
73
+ internal: merged.internal,
74
+ } as any);
75
+
76
+ if (affectedRows <= 0) {
77
+ throw new APIError({ code: StatusCodes.INTERNAL_SERVER_ERROR, detail: `Could not update billing seat with id ${id}` });
78
+ }
79
+
80
+ return await this.get(id);
81
+ } catch (e) { throw e; }
82
+ };
83
+
84
+ public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
85
+ try {
86
+ const seat = (await this.get(id))[0];
87
+ if (!seat) {
88
+ throw new APIError({ code: StatusCodes.NOT_FOUND, detail: `Billing seat with id ${id} not found.` });
89
+ }
90
+
91
+ const { affectedRows } = await accountingSeatDao.delete({ id: seat.id });
92
+
93
+ if (affectedRows <= 0) {
94
+ throw new APIError({ code: StatusCodes.INTERNAL_SERVER_ERROR, detail: `Could not delete billing seat with id ${id}` });
95
+ }
96
+
97
+ return { deleted: affectedRows > 0 };
98
+ } catch (e) { throw e; }
99
+ };
100
+
101
+ public readonly deleteIf = async (params: Where<DBRecord>): Promise<{ deleted: boolean }> => {
102
+ try {
103
+ const { affectedRows } = await accountingSeatDao.deleteIf(params);
104
+
105
+ if (affectedRows <= 0) {
106
+ throw new APIError({ code: StatusCodes.INTERNAL_SERVER_ERROR, detail: `Could not delete billing seats` });
107
+ }
108
+
109
+ return { deleted: affectedRows > 0 };
110
+ } catch (e) { throw e; }
111
+ };
112
+
113
+ private readonly getFreeUUID = async (): Promise<string> => {
114
+ try {
115
+ let uuid: string;
116
+ do {
117
+ uuid = newUUIDv4({ case: `lower` });
118
+ const exists = (await accountingSeatDao.list({ uuid: uuid } as any))[0];
119
+ if (!exists) { break; }
120
+ } while (true);
121
+ return uuid;
122
+ } catch (e) { throw e; }
123
+ };
124
+
125
+ private readonly parse = async (records: DBRecord[]): Promise<AccountingSeat[]> => {
126
+ try {
127
+ const response: AccountingSeat[] = [];
128
+ for (const record of records) {
129
+ const p: AccountingSeat = {
130
+ id: record.id,
131
+ uuid: record.uuid,
132
+ organization: record.organization,
133
+ invoice: record.invoice,
134
+ date: new Date2(record.date).format(Formats.ISO),
135
+ amount: parseFloat(record.amount as any),
136
+ done: (record.done as any) === 1,
137
+ metadata: record.metadata,
138
+ internal: record.internal,
139
+ };
140
+ response.push(p);
141
+ }
142
+ return response;
143
+ } catch (e) { throw e; }
144
+ };
145
+ }
146
+
147
+ const accountingSeatController = new AccountingSeatCtrl();
148
+ export default accountingSeatController;