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.
- package/.claude/settings.local.json +11 -0
- package/.dockerignore +11 -0
- package/.github/workflows/_deploy.yml +191 -0
- package/.github/workflows/deploy-dev.yml +30 -0
- package/.github/workflows/deploy-prod.yml +34 -0
- package/CLAUDE.md +114 -0
- package/Dockerfile +61 -0
- package/Dockerfile.dev +24 -0
- package/README.md +1 -0
- package/package.json +61 -0
- package/src/App.ts +40 -0
- package/src/helpers/api-error.ts +21 -0
- package/src/helpers/authority.ts +216 -0
- package/src/helpers/config.ts +4 -0
- package/src/helpers/holded.ts +105 -0
- package/src/helpers/mysql.ts +15 -0
- package/src/helpers/notifications.ts +55 -0
- package/src/helpers/random.ts +18 -0
- package/src/helpers/s3.ts +43 -0
- package/src/helpers/stripe.ts +8 -0
- package/src/index.ts +47 -0
- package/src/v1/common-types.ts +12 -0
- package/src/v1/controllers/admin/accounting-seat-controller.ts +148 -0
- package/src/v1/controllers/admin/billing-cycle-controller.ts +171 -0
- package/src/v1/controllers/admin/invoice-controller.ts +222 -0
- package/src/v1/controllers/admin/license-controller.ts +190 -0
- package/src/v1/controllers/admin/license-limit-controller.ts +160 -0
- package/src/v1/controllers/admin/notification-controller.ts +115 -0
- package/src/v1/controllers/admin/organization-controller.ts +210 -0
- package/src/v1/controllers/admin/organization-license-controller.ts +224 -0
- package/src/v1/controllers/admin/organization-license-limit-controller.ts +196 -0
- package/src/v1/controllers/admin/organization-usage-controller.ts +167 -0
- package/src/v1/controllers/admin/payment-method-controller.ts +173 -0
- package/src/v1/controllers/admin/policy-controller.ts +138 -0
- package/src/v1/controllers/admin/policy-version-controller.ts +143 -0
- package/src/v1/controllers/admin/schedule-controller.ts +181 -0
- package/src/v1/controllers/admin/service-controller.ts +206 -0
- package/src/v1/controllers/admin/service-notification-controller.ts +166 -0
- package/src/v1/controllers/admin/user-controller.ts +282 -0
- package/src/v1/controllers/admin/user-organization-controller.ts +172 -0
- package/src/v1/controllers/admin/user-policy-controller.ts +164 -0
- package/src/v1/controllers/auth/@deprecated oauth-controller.ts +191 -0
- package/src/v1/controllers/auth/identity-token-controller.ts +286 -0
- package/src/v1/controllers/auth/organization-token-controller.ts +277 -0
- package/src/v1/controllers/auth/temp-code-controller.ts +60 -0
- package/src/v1/controllers/billing/billing-controller.ts +805 -0
- package/src/v1/controllers/organizations/public-organization-controller.ts +1796 -0
- package/src/v1/controllers/policies/public-policy-controller.ts +68 -0
- package/src/v1/controllers/services/public-service-controller.ts +177 -0
- package/src/v1/controllers/services/service-controller.ts +474 -0
- package/src/v1/controllers/users/public-user-controller.ts +471 -0
- package/src/v1/daos/@deprecated auth-dao.ts +173 -0
- package/src/v1/daos/accounting-seat-dao.ts +111 -0
- package/src/v1/daos/billing-cycle-dao.ts +107 -0
- package/src/v1/daos/invoice-dao.ts +131 -0
- package/src/v1/daos/license-dao.ts +152 -0
- package/src/v1/daos/license-limit-dao.ts +120 -0
- package/src/v1/daos/organization-dao.ts +109 -0
- package/src/v1/daos/organization-license-dao.ts +117 -0
- package/src/v1/daos/organization-license-limit-dao.ts +157 -0
- package/src/v1/daos/organization-usage-dao.ts +115 -0
- package/src/v1/daos/payment-method-dao.ts +110 -0
- package/src/v1/daos/policy-dao.ts +105 -0
- package/src/v1/daos/policy-version-dao.ts +112 -0
- package/src/v1/daos/redis-dao.ts +38 -0
- package/src/v1/daos/schema.sql +462 -0
- package/src/v1/daos/service-dao.ts +118 -0
- package/src/v1/daos/service-notification-dao.ts +120 -0
- package/src/v1/daos/user-dao.ts +127 -0
- package/src/v1/daos/user-organization-dao.ts +123 -0
- package/src/v1/daos/user-policy-dao.ts +109 -0
- package/src/v1/middlewares/auth/identity-token-middleware.ts +51 -0
- package/src/v1/middlewares/auth/organization-token-middleware.ts +73 -0
- package/src/v1/middlewares/auth/service-token-middleware.ts +167 -0
- package/src/v1/middlewares/authority-middleware.ts +97 -0
- package/src/v1/middlewares/organizations/organization-middleware.ts +94 -0
- package/src/v1/middlewares/static/static-middleware.ts +41 -0
- package/src/v1/middlewares/users/user-middleware.ts +41 -0
- package/src/v1/routes/admin/accounting-seat-router.ts +89 -0
- package/src/v1/routes/admin/admin-router.ts +61 -0
- package/src/v1/routes/admin/billing-cycle-router.ts +89 -0
- package/src/v1/routes/admin/invoice-router.ts +89 -0
- package/src/v1/routes/admin/license-limit-router.ts +89 -0
- package/src/v1/routes/admin/license-router.ts +89 -0
- package/src/v1/routes/admin/notification-router.ts +61 -0
- package/src/v1/routes/admin/organization-license-limit-router.ts +89 -0
- package/src/v1/routes/admin/organization-license-router.ts +89 -0
- package/src/v1/routes/admin/organization-router.ts +89 -0
- package/src/v1/routes/admin/payment-method-router.ts +89 -0
- package/src/v1/routes/admin/policy-router.ts +89 -0
- package/src/v1/routes/admin/policy-version-router.ts +89 -0
- package/src/v1/routes/admin/schedule-router.ts +75 -0
- package/src/v1/routes/admin/service-notification-router.ts +98 -0
- package/src/v1/routes/admin/service-router.ts +89 -0
- package/src/v1/routes/admin/user-organization-router.ts +89 -0
- package/src/v1/routes/admin/user-policy-router.ts +89 -0
- package/src/v1/routes/admin/user-router.ts +89 -0
- package/src/v1/routes/auth/@deprecated auth-router.ts +199 -0
- package/src/v1/routes/auth/identity-token-router.ts +147 -0
- package/src/v1/routes/auth/organization-token-router.ts +70 -0
- package/src/v1/routes/billing/billing-router.ts +227 -0
- package/src/v1/routes/organizations/invoices-router.ts +48 -0
- package/src/v1/routes/organizations/payments-router.ts +104 -0
- package/src/v1/routes/organizations/public-organization-router.ts +319 -0
- package/src/v1/routes/organizations/users-router.ts +139 -0
- package/src/v1/routes/policies/public-policy-router.ts +50 -0
- package/src/v1/routes/services/public-service-router.ts +89 -0
- package/src/v1/routes/services/service-router.ts +197 -0
- package/src/v1/routes/users/public-user-router.ts +230 -0
- package/src/v1/routes/v1-router.ts +50 -0
- package/src/v1/schemas/admin/accounting-seat-schemas.ts +22 -0
- package/src/v1/schemas/admin/billing-cycle-schemas.ts +20 -0
- package/src/v1/schemas/admin/invoice-schemas.ts +41 -0
- package/src/v1/schemas/admin/license-limit-schemas.ts +25 -0
- package/src/v1/schemas/admin/license-schemas.ts +30 -0
- package/src/v1/schemas/admin/organization-license-limit-schemas.ts +29 -0
- package/src/v1/schemas/admin/organization-license-schemas.ts +43 -0
- package/src/v1/schemas/admin/organization-schemas.ts +67 -0
- package/src/v1/schemas/admin/organization-usage-schemas.ts +15 -0
- package/src/v1/schemas/admin/payment-method-schemas.ts +40 -0
- package/src/v1/schemas/admin/policy-schemas.ts +31 -0
- package/src/v1/schemas/admin/service-notification-schemas.ts +23 -0
- package/src/v1/schemas/admin/service-schemas.ts +56 -0
- package/src/v1/schemas/admin/user-organization-schemas.ts +24 -0
- package/src/v1/schemas/admin/user-policy-schemas.ts +17 -0
- package/src/v1/schemas/admin/user-schemas.ts +52 -0
- package/src/v1/schemas/auth/auth-schemas.ts +55 -0
- package/src/v1/schemas/billing/billing-schemas.ts +32 -0
- package/src/v1/schemas/organizations/public-organization-schemas.ts +77 -0
- package/src/v1/schemas/payments/payment-method-schemas.ts +0 -0
- package/src/v1/schemas/services/public-service-schemas.ts +5 -0
- package/src/v1/schemas/services/service-schemas.ts +27 -0
- package/src/v1/schemas/users/public-user-schemas.ts +73 -0
- package/src/v1/types/admin/accounting-seat-types.ts +16 -0
- package/src/v1/types/admin/billing-cycle-types.ts +14 -0
- package/src/v1/types/admin/invoice-types.ts +39 -0
- package/src/v1/types/admin/license-limit-types.ts +16 -0
- package/src/v1/types/admin/license-types.ts +29 -0
- package/src/v1/types/admin/organization-license-limit-types.ts +13 -0
- package/src/v1/types/admin/organization-license-types.ts +21 -0
- package/src/v1/types/admin/organization-types.ts +60 -0
- package/src/v1/types/admin/organization-usage-types.ts +17 -0
- package/src/v1/types/admin/payment-method-types.ts +30 -0
- package/src/v1/types/admin/policy-types.ts +9 -0
- package/src/v1/types/admin/policy-version-types.ts +12 -0
- package/src/v1/types/admin/service-notification-types.ts +20 -0
- package/src/v1/types/admin/service-types.ts +36 -0
- package/src/v1/types/admin/user-organization-types.ts +31 -0
- package/src/v1/types/admin/user-types.ts +44 -0
- package/src/v1/types/auth/@deprecated auth-types.ts +26 -0
- package/src/v1/types/auth/common-types.ts +7 -0
- package/src/v1/types/auth/confirmation-types.ts +5 -0
- package/src/v1/types/auth/identity-token-types.ts +8 -0
- package/src/v1/types/auth/organization-token-types.ts +23 -0
- package/src/v1/types/auth/otp-types.ts +12 -0
- package/src/v1/types/billing/billing-types.ts +37 -0
- package/src/v1/types/billing/ue-types.ts +29 -0
- package/src/v1/types/organizations/public-organization-types.ts +76 -0
- package/src/v1/types/policies/public-policy-types.ts +7 -0
- package/src/v1/types/services/public-service-types.ts +20 -0
- package/src/v1/types/services/service-types.ts +43 -0
- package/src/v1/types/users/public-user-types.ts +15 -0
- package/src/v1/types/users/user-policy-types.ts +11 -0
- package/static/error.html +55 -0
- package/static/grant.html +117 -0
- package/static/login.html +54 -0
- package/static/oauth-client-logo.webp +0 -0
- 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,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
|
+
};
|
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,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;
|