5htp 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/compiler/common/babel/routes/routes.ts +13 -2
- package/src/compiler/common/index.ts +3 -1
- package/src/compiler/common/plugins/indexage/icones-svg/index.ts +3 -3
- package/src/compiler/index.ts +34 -12
- package/skeleton/Dockerfile +0 -20
- package/skeleton/docker-compose.yml +0 -37
- package/skeleton/identity.yaml +0 -21
- package/skeleton/package.json +0 -48
- package/skeleton/src/client/assets/identity/logo.svg +0 -14
- package/skeleton/src/client/assets/identity/logoAndText.svg +0 -10
- package/skeleton/src/client/assets/identity/logoAndTextBlack.svg +0 -11
- package/skeleton/src/client/assets/illustration/landing/banner.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/candidate/employers.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/candidate/hero.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/candidate/mentors.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/headhunter/hero.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/hero.jpeg +0 -0
- package/skeleton/src/client/assets/illustration/landing/hero.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/hero.xcf +0 -0
- package/skeleton/src/client/assets/illustration/landing/recruiter/onboarding.webp +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/andre.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/emma.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/fei.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/gaetan.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/jordan.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/lery.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/mehdi.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/omkar.png +0 -0
- package/skeleton/src/client/assets/illustration/landing/team/thibaut.png +0 -0
- package/skeleton/src/client/assets/illustration/launch.jpg +0 -0
- package/skeleton/src/client/assets/img/background/header-blur.png +0 -0
- package/skeleton/src/client/assets/img/partners/citron.svg +0 -987
- package/skeleton/src/client/assets/logos/google-play-store.svg +0 -1
- package/skeleton/src/client/assets/logos/googleauth.svg +0 -9
- package/skeleton/src/client/assets/patterns/dots.png +0 -0
- package/skeleton/src/client/assets/patterns/interlaced.png +0 -0
- package/skeleton/src/client/assets/theme.less +0 -231
- package/skeleton/src/client/assets/vars.less +0 -54
- package/skeleton/src/client/context.ts +0 -23
- package/skeleton/src/client/index.ts +0 -59
- package/skeleton/src/client/pages/_messages/400.tsx +0 -45
- package/skeleton/src/client/pages/_messages/401.tsx +0 -39
- package/skeleton/src/client/pages/_messages/403.tsx +0 -43
- package/skeleton/src/client/pages/_messages/404.tsx +0 -42
- package/skeleton/src/client/pages/_messages/500.tsx +0 -42
- package/skeleton/src/client/pages/platform/Header.less +0 -12
- package/skeleton/src/client/pages/platform/Header.tsx +0 -119
- package/skeleton/src/client/pages/platform/_layout/index.less +0 -118
- package/skeleton/src/client/pages/platform/_layout/index.tsx +0 -131
- package/skeleton/src/client/pages/platform/_layout/mobile.less +0 -114
- package/skeleton/src/client/pages/platform/_page.tsx +0 -54
- package/skeleton/src/client/pages/platform/headhunters/index.tsx +0 -88
- package/skeleton/src/client/pages/platform/index.tsx +0 -58
- package/skeleton/src/client/pages/platform/missions/index.tsx +0 -149
- package/skeleton/src/client/pages/preload.json +0 -3
- package/skeleton/src/client/services/metrics/index.ts +0 -59
- package/skeleton/src/client/tsconfig.json +0 -31
- package/skeleton/src/common/config/router.ts +0 -16
- package/skeleton/src/common/forms/company/bookCall.ts +0 -25
- package/skeleton/src/common/forms/company/importJob.ts +0 -26
- package/skeleton/src/common/forms/company/signup.ts +0 -31
- package/skeleton/src/common/forms/headhunter/feedback.ts +0 -31
- package/skeleton/src/common/forms/headhunter/mission/cancel.ts +0 -26
- package/skeleton/src/common/forms/headhunter/mission/candidate/availability.ts +0 -31
- package/skeleton/src/common/forms/headhunter/mission/candidate/education.ts +0 -19
- package/skeleton/src/common/forms/headhunter/mission/candidate/identity.ts +0 -31
- package/skeleton/src/common/forms/headhunter/mission/candidate/others.ts +0 -19
- package/skeleton/src/common/forms/headhunter/mission/candidate/skills.ts +0 -21
- package/skeleton/src/common/forms/headhunter/mission/reject.ts +0 -23
- package/skeleton/src/common/forms/headhunter/mission/search.ts +0 -78
- package/skeleton/src/common/forms/headhunter/signup.ts +0 -34
- package/skeleton/src/common/libs/headhunter/candidate/index.ts +0 -155
- package/skeleton/src/common/libs/headhunter/mission/index.ts +0 -30
- package/skeleton/src/common/libs/hub/index.ts +0 -41
- package/skeleton/src/common/tsconfig.json +0 -10
- package/skeleton/src/server/config/communication.ts +0 -48
- package/skeleton/src/server/config/crosspath.ts +0 -9
- package/skeleton/src/server/config/data.ts +0 -34
- package/skeleton/src/server/config/database.ts +0 -26
- package/skeleton/src/server/config/internal.ts +0 -21
- package/skeleton/src/server/config/user.ts +0 -90
- package/skeleton/src/server/index.ts +0 -111
- package/skeleton/src/server/libs/utils/slug.ts +0 -11
- package/skeleton/src/server/routes/global.ts +0 -33
- package/skeleton/src/server/routes/headhunters.ts +0 -24
- package/skeleton/src/server/routes/missions.ts +0 -50
- package/skeleton/src/server/services/Headhunter/index.ts +0 -127
- package/skeleton/src/server/services/Headhunter/service.json +0 -6
- package/skeleton/src/server/services/Mission/index.ts +0 -174
- package/skeleton/src/server/services/Mission/service.json +0 -6
- package/skeleton/src/server/services/email/sendgrid/index.ts +0 -97
- package/skeleton/src/server/services/email/sendgrid/service.json +0 -6
- package/skeleton/src/server/services/slack/index.ts +0 -105
- package/skeleton/src/server/services/slack/service.json +0 -6
- package/skeleton/src/server/services/users/index.ts +0 -133
- package/skeleton/src/server/services/users/service.json +0 -6
- package/skeleton/src/server/tsconfig.json +0 -32
- package/skeleton/var/typings/routes.d.ts +0 -541
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
|
|
7
|
-
// Core
|
|
8
|
-
import { Router, Users, Mission } from '@app';
|
|
9
|
-
|
|
10
|
-
/*----------------------------------
|
|
11
|
-
- TYPES
|
|
12
|
-
----------------------------------*/
|
|
13
|
-
|
|
14
|
-
/*----------------------------------
|
|
15
|
-
- SIGNUP
|
|
16
|
-
----------------------------------*/
|
|
17
|
-
|
|
18
|
-
Router.get('/missions', async ({ schema, auth }) => {
|
|
19
|
-
|
|
20
|
-
const user = await auth.check('USER');
|
|
21
|
-
|
|
22
|
-
return await Mission.List(user);
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
Router.get('/missions/applications', async ({ schema, auth }) => {
|
|
27
|
-
|
|
28
|
-
const user = await auth.check('USER');
|
|
29
|
-
|
|
30
|
-
const { missionId } = schema.validate({
|
|
31
|
-
missionId: schema.string({ opt: true }),
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return await Mission.Applications(user, missionId);
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
Router.post('/missions/applications/:response(approve|reject)', async ({ schema, auth, request }) => {
|
|
39
|
-
|
|
40
|
-
const user = await auth.check('USER');
|
|
41
|
-
|
|
42
|
-
const { missionId, headhunterId, response } = schema.validate({
|
|
43
|
-
missionId: schema.string(),
|
|
44
|
-
headhunterId: schema.string(),
|
|
45
|
-
response: schema.string()
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
return await Mission.RespondApplication( response, missionId, headhunterId, user );
|
|
49
|
-
|
|
50
|
-
});
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
import got from 'got';
|
|
7
|
-
|
|
8
|
-
// Services
|
|
9
|
-
import { SQL, Router, Fetch } from '@app';
|
|
10
|
-
|
|
11
|
-
// Core
|
|
12
|
-
import Service from '@server/app/service';
|
|
13
|
-
|
|
14
|
-
// App
|
|
15
|
-
import type { Headhunter } from '@/server/models';
|
|
16
|
-
|
|
17
|
-
/*----------------------------------
|
|
18
|
-
- SERVICE TYPES
|
|
19
|
-
----------------------------------*/
|
|
20
|
-
|
|
21
|
-
export type Config = {
|
|
22
|
-
debug?: boolean,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type Hooks = {
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export type Services = {
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/*----------------------------------
|
|
34
|
-
- TYPES
|
|
35
|
-
----------------------------------*/
|
|
36
|
-
|
|
37
|
-
export type HeadhunterWithKPIs = Headhunter & HeadhunterKPIs & {
|
|
38
|
-
url: string,
|
|
39
|
-
name: string,
|
|
40
|
-
onboarded: boolean,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export type HeadhunterKPIs = {
|
|
44
|
-
|
|
45
|
-
activity: number,
|
|
46
|
-
reactivity: number,
|
|
47
|
-
quality: number,
|
|
48
|
-
performance: number,
|
|
49
|
-
|
|
50
|
-
bonus: number,
|
|
51
|
-
levelProgress: number,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/*----------------------------------
|
|
55
|
-
- SERVICE
|
|
56
|
-
----------------------------------*/
|
|
57
|
-
export default class HeadhuntersService extends Service<Config, Hooks, CrossPathCSM, Services> {
|
|
58
|
-
|
|
59
|
-
// Actors
|
|
60
|
-
|
|
61
|
-
/*----------------------------------
|
|
62
|
-
- LIFECYCLE
|
|
63
|
-
----------------------------------*/
|
|
64
|
-
|
|
65
|
-
// Service start
|
|
66
|
-
protected async start() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public async ready() {
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public async shutdown() {
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/*----------------------------------
|
|
80
|
-
- ACTIONS
|
|
81
|
-
----------------------------------*/
|
|
82
|
-
|
|
83
|
-
public async List() {
|
|
84
|
-
return await SQL`
|
|
85
|
-
SELECT *,
|
|
86
|
-
CONCAT(firstName, ' ', lastName) as name
|
|
87
|
-
FROM Headhunter
|
|
88
|
-
ORDER BY created DESC
|
|
89
|
-
`.all();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/* public async List(): Promise<HeadhunterWithKPIs[]> {
|
|
93
|
-
|
|
94
|
-
const headhunterRepo = Headhunting.user.repository;
|
|
95
|
-
|
|
96
|
-
// https://www.notion.so/Headhunter-KPIs-b430f02765d941058b3a64e89a04d8a2
|
|
97
|
-
return await SQL<HeadhunterWithKPIs>`
|
|
98
|
-
SELECT
|
|
99
|
-
CONCAT(firstName, ' ', lastName) as name,
|
|
100
|
-
CONCAT('/admin/headhunters/', airtableId) as url,
|
|
101
|
-
|
|
102
|
-
(password IS NOT NULL) as onboarded,
|
|
103
|
-
|
|
104
|
-
(${headhunterRepo.kpis.activity}) as activity,
|
|
105
|
-
(${headhunterRepo.kpis.reactivity}) as reactivity,
|
|
106
|
-
(${headhunterRepo.kpis.quality}) as quality,
|
|
107
|
-
(${headhunterRepo.kpis.performance}) as performance,
|
|
108
|
-
|
|
109
|
-
(${Headhunting.user.gamification.queries.bonus}) as bonus,
|
|
110
|
-
(${Headhunting.user.gamification.queries.levelProgress}) as levelProgress
|
|
111
|
-
|
|
112
|
-
FROM Headhunter
|
|
113
|
-
ORDER BY performance DESC, quality DESC, activity DESC, reactivity ASC
|
|
114
|
-
LIMIT 100
|
|
115
|
-
`.all();
|
|
116
|
-
}*/
|
|
117
|
-
|
|
118
|
-
public async Suggested() {
|
|
119
|
-
return await SQL<HeadhunterWithKPIs>`
|
|
120
|
-
SELECT
|
|
121
|
-
CONCAT(firstName, ' ', lastName) as name,
|
|
122
|
-
CONCAT('/admin/headhunters/', airtableId) as url
|
|
123
|
-
FROM Headhunter
|
|
124
|
-
LIMIT 20
|
|
125
|
-
`.all();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
import got from 'got';
|
|
7
|
-
import { RemoteProvider } from '5htp-airtable';
|
|
8
|
-
|
|
9
|
-
// Services
|
|
10
|
-
import { SQL, Router, Email } from '@app';
|
|
11
|
-
|
|
12
|
-
// Core
|
|
13
|
-
import Service from '@server/app/service';
|
|
14
|
-
|
|
15
|
-
// App
|
|
16
|
-
|
|
17
|
-
/*----------------------------------
|
|
18
|
-
- SERVICE TYPES
|
|
19
|
-
----------------------------------*/
|
|
20
|
-
|
|
21
|
-
export const ApplicationResponses = ['approve', 'reject'] as const
|
|
22
|
-
export type TApplicationResponse = typeof ApplicationResponses[number]
|
|
23
|
-
|
|
24
|
-
export type Config = {
|
|
25
|
-
debug?: boolean,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type Hooks = {
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type Services = {
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/*----------------------------------
|
|
37
|
-
- SERVICE
|
|
38
|
-
----------------------------------*/
|
|
39
|
-
export default class MissionsService extends Service<Config, Hooks, CrossPathCSM, Services> {
|
|
40
|
-
|
|
41
|
-
private provider = new RemoteProvider(this.app, "@recruiters/system/provider", "missions");
|
|
42
|
-
|
|
43
|
-
/*----------------------------------
|
|
44
|
-
- LIFECYCLE
|
|
45
|
-
----------------------------------*/
|
|
46
|
-
|
|
47
|
-
// Service start
|
|
48
|
-
protected async start() {
|
|
49
|
-
|
|
50
|
-
await this.provider.start();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public async ready() {
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public async shutdown() {
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/*----------------------------------
|
|
64
|
-
- ACTIONS
|
|
65
|
-
----------------------------------*/
|
|
66
|
-
|
|
67
|
-
public async List( user: User ) {
|
|
68
|
-
return await SQL`
|
|
69
|
-
SELECT *
|
|
70
|
-
FROM Mission
|
|
71
|
-
WHERE
|
|
72
|
-
customerSuccess = ${user.slug}
|
|
73
|
-
AND
|
|
74
|
-
Mission.status = 'Active'
|
|
75
|
-
`.all();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public async Applications( user: User, missionId?: string ) {
|
|
79
|
-
return await SQL`
|
|
80
|
-
SELECT
|
|
81
|
-
|
|
82
|
-
dateStart,
|
|
83
|
-
mission as missionId,
|
|
84
|
-
headhunter as headhunterId,
|
|
85
|
-
|
|
86
|
-
CONCAT(Headhunter.firstName, ' ', Headhunter.lastName) as headhunter,
|
|
87
|
-
Mission.title as mission
|
|
88
|
-
FROM AcceptedMission
|
|
89
|
-
|
|
90
|
-
INNER JOIN Headhunter ON Headhunter.email = AcceptedMission.headhunter
|
|
91
|
-
INNER JOIN Mission ON Mission.airtableId = AcceptedMission.mission
|
|
92
|
-
|
|
93
|
-
WHERE
|
|
94
|
-
:${missionId === undefined
|
|
95
|
-
? `Mission.customerSuccess = "${user.slug}"`
|
|
96
|
-
: `Mission.airtableId = "${missionId}"`}
|
|
97
|
-
AND
|
|
98
|
-
AcceptedMission.status = 'approving'
|
|
99
|
-
|
|
100
|
-
`.all();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public async RespondApplication(
|
|
104
|
-
action: TApplicationResponse,
|
|
105
|
-
missionId: string,
|
|
106
|
-
headhunterEmail: string
|
|
107
|
-
) {
|
|
108
|
-
|
|
109
|
-
// retrieve mission information
|
|
110
|
-
const mission = await SQL`
|
|
111
|
-
SELECT title, company
|
|
112
|
-
FROM Mission
|
|
113
|
-
WHERE airtableId = ${missionId};
|
|
114
|
-
`.firstOrFail("Unable to find mission info.");
|
|
115
|
-
|
|
116
|
-
// Update DB
|
|
117
|
-
await SQL.update('AcceptedMission', {
|
|
118
|
-
mission: missionId,
|
|
119
|
-
headhunter: headhunterEmail,
|
|
120
|
-
status: action === 'approve' ? 'accepted' : 'rejected'
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
if (action === 'reject') {
|
|
124
|
-
// Send notification
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Retrieve the current list of headhunters for this mission
|
|
129
|
-
const headhuntersList = await SQL<{ headhunter: string }>`
|
|
130
|
-
SELECT Headhunter.airtableId as headhunter
|
|
131
|
-
FROM AcceptedMission
|
|
132
|
-
INNER JOIN Headhunter ON Headhunter.email = AcceptedMission.headhunter
|
|
133
|
-
WHERE
|
|
134
|
-
AcceptedMission.mission = ${missionId}
|
|
135
|
-
AND
|
|
136
|
-
AcceptedMission.status = 'accepted'
|
|
137
|
-
`.all().then(list =>
|
|
138
|
-
list.map(accepted => accepted.headhunter)
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
// Add the currentheadhunter to the list of headhunterds for this mission
|
|
142
|
-
await this.provider.airtable.update([{
|
|
143
|
-
id: missionId,
|
|
144
|
-
'Headhunters Matched': [...headhuntersList]
|
|
145
|
-
}]);
|
|
146
|
-
|
|
147
|
-
// Send notification
|
|
148
|
-
const missionUrl = Router.url('@recruiters/mission/accepted/' + mission.company + '/' + missionId);
|
|
149
|
-
await Email.send( headhunterEmail,
|
|
150
|
-
`🎉 You've been selected to work on a new mission: ${mission.title}`,
|
|
151
|
-
`
|
|
152
|
-
Hey, I'm pleased to announce your application to work on the mission "${mission.title}" has been approved by our team!
|
|
153
|
-
|
|
154
|
-
You can start working on it starting from now, [directly on our platform](${missionUrl}).
|
|
155
|
-
|
|
156
|
-
Kind regards,
|
|
157
|
-
Your Cross Path Team
|
|
158
|
-
`
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
return true;
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public async RejectApplication( user: User, missionId: string, headhunterId: string ) {
|
|
166
|
-
|
|
167
|
-
// Update Db & Airtable
|
|
168
|
-
|
|
169
|
-
// Send notification
|
|
170
|
-
|
|
171
|
-
return true;
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
const sgMail = require('@sendgrid/mail');
|
|
7
|
-
|
|
8
|
-
// Core
|
|
9
|
-
import { Transporter, TCompleteEmail } from '@server/services/email';
|
|
10
|
-
import type { Application } from "@server/app/index";
|
|
11
|
-
|
|
12
|
-
/*----------------------------------
|
|
13
|
-
- CONFIG
|
|
14
|
-
----------------------------------*/
|
|
15
|
-
|
|
16
|
-
const LogPrefix = "[email][sendgrid]";
|
|
17
|
-
|
|
18
|
-
/*----------------------------------
|
|
19
|
-
- TYPES
|
|
20
|
-
----------------------------------*/
|
|
21
|
-
|
|
22
|
-
export type TConfig = {
|
|
23
|
-
debug: boolean,
|
|
24
|
-
api: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/*----------------------------------
|
|
28
|
-
- TRABSPORTER
|
|
29
|
-
----------------------------------*/
|
|
30
|
-
|
|
31
|
-
export default class SendGridTransporter extends Transporter<TConfig> {
|
|
32
|
-
|
|
33
|
-
public constructor(
|
|
34
|
-
parent: Application,
|
|
35
|
-
config: TConfig,
|
|
36
|
-
services: {},
|
|
37
|
-
app: Application | 'self',
|
|
38
|
-
) {
|
|
39
|
-
super(parent, config, services, app);
|
|
40
|
-
|
|
41
|
-
sgMail.setApiKey( config.api );
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public async send( emails: TCompleteEmail[] ) {
|
|
45
|
-
|
|
46
|
-
if (emails.length !== 1)
|
|
47
|
-
throw new Error(LogPrefix + ` Feature not supported by Mailchimp: can't send a different email for each person.`);
|
|
48
|
-
|
|
49
|
-
const email = emails[0];
|
|
50
|
-
|
|
51
|
-
const to = email.to.map( to => ({
|
|
52
|
-
email: to.email,
|
|
53
|
-
name: to.name,
|
|
54
|
-
type: 'to'
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
if (email.cc)
|
|
58
|
-
for (const person of email.cc)
|
|
59
|
-
to.push({
|
|
60
|
-
email: person.email,
|
|
61
|
-
name: person.name,
|
|
62
|
-
type: 'cc'
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const body = {
|
|
66
|
-
key: this.config.api,
|
|
67
|
-
message: {
|
|
68
|
-
from_email: email.from.email,
|
|
69
|
-
from_name: email.from.name,
|
|
70
|
-
subject: email.subject,
|
|
71
|
-
html: email.html,
|
|
72
|
-
to
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
this.config.debug && console.log(LogPrefix, 'Send request to api:', body);
|
|
77
|
-
|
|
78
|
-
for (const email of emails)
|
|
79
|
-
await sgMail.send({
|
|
80
|
-
to: email.to,
|
|
81
|
-
from: email.from,
|
|
82
|
-
subject: email.subject,
|
|
83
|
-
html: email.html
|
|
84
|
-
}).then((res) => {
|
|
85
|
-
|
|
86
|
-
this.config.debug && console.log(LogPrefix, 'API request reponse:', body, res.statusCode, res.body);
|
|
87
|
-
|
|
88
|
-
return true;
|
|
89
|
-
|
|
90
|
-
}).catch( e => {
|
|
91
|
-
|
|
92
|
-
console.log(LogPrefix, "failed", body, e.response?.statusCode, e, e.response?.body);
|
|
93
|
-
throw new Error(e.response?.body?.errors[0]?.message || e.message || "Send email failed with MailChimp")
|
|
94
|
-
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// npm
|
|
6
|
-
import { WebClient } from '@slack/web-api';
|
|
7
|
-
|
|
8
|
-
// App
|
|
9
|
-
import { Environment } from '@app';
|
|
10
|
-
|
|
11
|
-
// Core
|
|
12
|
-
import Service from '@server/app/service';
|
|
13
|
-
|
|
14
|
-
/*----------------------------------
|
|
15
|
-
- SERVICE CONFIG
|
|
16
|
-
----------------------------------*/
|
|
17
|
-
|
|
18
|
-
const LogPrefix = `[slack]`;
|
|
19
|
-
|
|
20
|
-
export type Config = {
|
|
21
|
-
token: string,
|
|
22
|
-
channels: {
|
|
23
|
-
default: string
|
|
24
|
-
} & {
|
|
25
|
-
[channelName: string]: string
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export type Hook = {
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export type Subservices = {
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/*----------------------------------
|
|
38
|
-
- TYPES
|
|
39
|
-
----------------------------------*/
|
|
40
|
-
|
|
41
|
-
/*----------------------------------
|
|
42
|
-
- SERVICE
|
|
43
|
-
----------------------------------*/
|
|
44
|
-
export default class SlackService<TConfig extends Config = Config>
|
|
45
|
-
extends Service<TConfig, Hook, CrossPath, Subservices> {
|
|
46
|
-
|
|
47
|
-
private api = new WebClient(this.config.token);
|
|
48
|
-
|
|
49
|
-
/*----------------------------------
|
|
50
|
-
- LIFECYCLE
|
|
51
|
-
----------------------------------*/
|
|
52
|
-
|
|
53
|
-
public async start() {
|
|
54
|
-
|
|
55
|
-
if (Environment.profile === 'prod')
|
|
56
|
-
this.sendInChannel('default', `The CrossPath CSM server (${Environment.profile}) has successfully started :partying_face:`);
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public async ready() {
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public async shutdown() {
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/*----------------------------------
|
|
69
|
-
- ACTIONS
|
|
70
|
-
----------------------------------*/
|
|
71
|
-
public async sendInChannel( channelName: keyof typeof this.config.channels, message: string ) {
|
|
72
|
-
|
|
73
|
-
if (this.api === undefined) {
|
|
74
|
-
console.error(LogPrefix, `Slack web api not initialized. It can be because the api token has not been loaded.`);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
console.info(LogPrefix, `Sending message to slack, channel: ${channelName}. Message:\n${message}`);
|
|
79
|
-
|
|
80
|
-
const channelId = this.config.channels[channelName];
|
|
81
|
-
|
|
82
|
-
await this.api.chat.postMessage({
|
|
83
|
-
channel: channelId,
|
|
84
|
-
text: message,
|
|
85
|
-
mrkdwn: true,
|
|
86
|
-
link_names: true
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public async sendToUser( userId: string, message: string ) {
|
|
91
|
-
|
|
92
|
-
if (this.api === undefined) {
|
|
93
|
-
console.error(LogPrefix, `Slack web api not initialized. It can be because the api token has not been loaded.`);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
await this.api.chat.postMessage({
|
|
98
|
-
channel: userId,
|
|
99
|
-
text: message,
|
|
100
|
-
mrkdwn: true,
|
|
101
|
-
link_names: true ,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
}
|