@gnar-engine/cli 1.0.5 → 1.0.6

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 (47) hide show
  1. package/bootstrap/deploy.localdev.yml +14 -0
  2. package/bootstrap/secrets.localdev.yml +7 -3
  3. package/bootstrap/services/notification/Dockerfile +2 -2
  4. package/bootstrap/services/notification/package.json +14 -32
  5. package/bootstrap/services/notification/src/app.js +50 -48
  6. package/bootstrap/services/notification/src/commands/notification.handler.js +96 -0
  7. package/bootstrap/services/notification/src/config.js +55 -12
  8. package/bootstrap/services/notification/src/controllers/http.controller.js +87 -0
  9. package/bootstrap/services/notification/src/controllers/message.controller.js +39 -70
  10. package/bootstrap/services/notification/src/db/migrations/01-init.js +50 -0
  11. package/bootstrap/services/notification/src/db/migrations/02-notification-service-init.js +23 -0
  12. package/bootstrap/services/notification/src/policies/notification.policy.js +49 -0
  13. package/bootstrap/services/notification/src/schema/notification.schema.js +17 -0
  14. package/bootstrap/services/notification/src/services/notification.service.js +32 -0
  15. package/bootstrap/services/portal/src/services/client.js +3 -0
  16. package/bootstrap/services/user/src/commands/user.handler.js +35 -18
  17. package/bootstrap/services/user/src/tests/commands/user.test.js +15 -6
  18. package/install-from-clone.sh +1 -1
  19. package/package.json +1 -1
  20. package/src/cli.js +0 -6
  21. package/src/config.js +8 -0
  22. package/src/dev/commands.js +2 -2
  23. package/src/dev/dev.service.js +19 -6
  24. package/src/helpers/helpers.js +24 -0
  25. package/src/profiles/command.js +41 -0
  26. package/src/profiles/profiles.client.js +23 -0
  27. package/src/scaffolder/commands.js +57 -1
  28. package/src/scaffolder/scaffolder.handler.js +127 -60
  29. package/templates/entity/src/commands/{{entityName}}.handler.js.hbs +94 -0
  30. package/templates/entity/src/controllers/{{entityName}}.http.controller.js.hbs +87 -0
  31. package/templates/entity/src/mysql.db/migrations/03-{{entityName}}-entity-init.js.hbs +23 -0
  32. package/templates/entity/src/policies/{{entityName}}.policy.js.hbs +49 -0
  33. package/templates/entity/src/schema/{{entityName}}.schema.js.hbs +17 -0
  34. package/templates/entity/src/services/mongodb.{{entityName}}.service.js.hbs +70 -0
  35. package/templates/entity/src/services/mysql.{{entityName}}.service.js.hbs +27 -0
  36. package/bootstrap/services/notification/Dockerfile.prod +0 -37
  37. package/bootstrap/services/notification/README.md +0 -3
  38. package/bootstrap/services/notification/src/commands/command-bus.js +0 -20
  39. package/bootstrap/services/notification/src/commands/handlers/control.handler.js +0 -18
  40. package/bootstrap/services/notification/src/commands/handlers/notification.handler.js +0 -157
  41. package/bootstrap/services/notification/src/services/logger.service.js +0 -16
  42. package/bootstrap/services/notification/src/services/ses.service.js +0 -23
  43. package/bootstrap/services/notification/src/templates/admin-order-recieved.hbs +0 -136
  44. package/bootstrap/services/notification/src/templates/admin-subscription-failed.hbs +0 -87
  45. package/bootstrap/services/notification/src/templates/customer-order-recieved.hbs +0 -132
  46. package/bootstrap/services/notification/src/templates/customer-subscription-failed.hbs +0 -77
  47. package/bootstrap/services/notification/src/tests/notification.test.js +0 -0
@@ -1,157 +0,0 @@
1
- import { logger } from '../../services/logger.service.js';
2
- import { emailSendingService, emailHeaderLogoUrl } from './../../config.js';
3
- import { helpers } from '@gnar-engine/helpers';
4
- import fs from 'fs';
5
- import handlebars from 'handlebars';
6
- import nodemailer from 'nodemailer';
7
- import { getSesClient } from '../../services/ses.service.js';
8
- import { SendEmailCommand } from '@aws-sdk/client-ses';
9
-
10
-
11
- /**
12
- * Send a notification
13
- *
14
- * @param {Object} params
15
- * @param {string} params.templateName - Name of the template file (without extension)
16
- * @param {string} params.to - Recipient email address
17
- * @param {Object} params.params - Parameters to be passed to the template
18
- * @param {string} params.subject - Subject of the email
19
- */
20
- export const sendNotification = async ({ templateName, to, params, subject }) => {
21
- let source;
22
- let template;
23
-
24
- // get the requested template
25
- try {
26
- const workingDir = process.cwd();
27
- const path = workingDir + '/src/templates/' + templateName + '.hbs';
28
- source = fs.readFileSync(path, 'utf8');
29
- } catch (error) {
30
- logger.error('Error reading template file: ' + error.message);
31
- throw new Error('Template not found');
32
- }
33
-
34
- // compile the template
35
- try {
36
- template = handlebars.compile(source);
37
- } catch (error) {
38
- logger.error('Error compiling template: ' + error.message);
39
- throw new Error('Template compilation failed');
40
- }
41
-
42
- // append other params
43
- params = prepareParams(params, templateName);
44
-
45
- // prepare the template
46
- const html = template(params);
47
-
48
- // send the email
49
- switch (emailSendingService) {
50
- case 'SMTP':
51
- await sendSmtpEmail({ to, subject, html });
52
- break;
53
-
54
- case 'SES':
55
- await sendSesEmail({ to, subject, html });
56
- break;
57
-
58
- case 'Direct':
59
- logger.error('Email sending service not implemented: ' + emailSendingService);
60
- throw new Error('Email sending service not implemented');
61
-
62
- default:
63
- logger.error('Invalid email sending service: ' + emailSendingService);
64
- throw new Error('Invalid email sending service');
65
- }
66
- }
67
-
68
- /**
69
- * Send SMTP email
70
- *
71
- * @param {Object} params
72
- * @param {string} params.to - Recipient email address
73
- * @param {string} params.subject - Email subject
74
- * @param {string} params.html - HTML content of the email
75
- */
76
- export const sendSmtpEmail = async ({ to, subject, html }) => {
77
- try {
78
- const transporter = nodemailer.createTransport({
79
- host: process.env.SMTP_HOST,
80
- port: parseInt(process.env.SMTP_PORT || '465'),
81
- secure: true,
82
- auth: {
83
- user: process.env.SMTP_USER,
84
- pass: process.env.SMTP_PASS
85
- }
86
- });
87
-
88
- const mailOptions = {
89
- from: `"Your App Name" <${process.env.SMTP_USER}>`,
90
- to,
91
- subject,
92
- html
93
- };
94
-
95
- await transporter.sendMail(mailOptions);
96
- } catch (error) {
97
- logger.error('SMTP email send error: ' + error.message);
98
- throw new Error('SMTP email failed to send');
99
- }
100
- }
101
-
102
- /**
103
- * Send SES email
104
- *
105
- * @param {Object} params
106
- * @param {string} params.to - Recipient email address
107
- * @param {string} params.subject - Email subject
108
- * @param {string} params.html - HTML content of the email
109
- */
110
- export const sendSesEmail = async ({ to, subject, html }) => {
111
- try {
112
- const sesClient = getSesClient();
113
-
114
- const command = new SendEmailCommand({
115
- Source: process.env.NOTIFICATION_SES_SOURCE_EMAIL,
116
- Destination: {
117
- ToAddresses: [to]
118
- },
119
- Message: {
120
- Subject: {
121
- Data: subject,
122
- Charset: 'UTF-8'
123
- },
124
- Body: {
125
- Html: {
126
- Data: html,
127
- Charset: 'UTF-8'
128
- }
129
- }
130
- }
131
- });
132
-
133
- await sesClient.send(command);
134
- } catch (error) {
135
- logger.error('Error sending email with SES: ' + error.message);
136
- throw new Error('SES email failed to send');
137
- }
138
- }
139
-
140
- /**
141
- * Prepare parameters for the template
142
- *
143
- * @param {Object} params - Parameters to be passed to the template
144
- * @param {string} templateName - Name of the template file (without extension)
145
- * @returns {Object} - Prepared parameters
146
- */
147
- const prepareParams = (params, templateName) => {
148
-
149
- // add shop logo
150
- params.logoUrl = emailHeaderLogoUrl;
151
-
152
- if (params.order?.currency) {
153
- params.currencySymbol = helpers.ecommerce.getCurrencySymbol(params.order.currency);
154
- }
155
-
156
- return params
157
- }
@@ -1,16 +0,0 @@
1
- import pino from 'pino';
2
- import fs from 'fs';
3
- import path from 'path';
4
-
5
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
6
-
7
- // Create a logger instance
8
- export const logger = pino({
9
- level: process.env.LOG_MODE || 'info',
10
- transport: {
11
- target: 'pino-pretty', // Pretty print logs for the console
12
- options: {
13
- colorize: true, // Colorize the logs in the console
14
- }
15
- }
16
- });
@@ -1,23 +0,0 @@
1
- import { SESClient } from '@aws-sdk/client-ses';
2
- import { logger } from './logger.service.js';
3
-
4
- let sesClientInstance = null;
5
-
6
- /**
7
- * Get SES Client Instance
8
- *
9
- * @returns {SESClient} - SESClient instance
10
- * @description Returns a singleton instance of the SESClient
11
- */
12
- export const getSesClient = () => {
13
- if (!sesClientInstance) {
14
- sesClientInstance = new SESClient({
15
- region: process.env.NOTIFICATION_AWS_REGION,
16
- credentials: {
17
- accessKeyId: process.env.NOTIFICATION_AWS_ACCESS_KEY_ID,
18
- secretAccessKey: process.env.NOTIFICATION_AWS_SECRET_ACCESS_KEY
19
- }
20
- });
21
- }
22
- return sesClientInstance;
23
- };
@@ -1,136 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>New Order Notification</title>
6
- <style>
7
- body {
8
- font-family: Arial, sans-serif;
9
- font-size: 14px;
10
- color: #333;
11
- }
12
-
13
- .container {
14
- max-width: 600px;
15
- margin: auto;
16
- padding: 20px;
17
- border: 1px solid #eee;
18
- }
19
-
20
- .logo {
21
- text-align: center;
22
- margin-bottom: 20px;
23
- }
24
-
25
- .logo img {
26
- max-height: 60px;
27
- }
28
-
29
- .header {
30
- text-align: center;
31
- font-size: 20px;
32
- margin-bottom: 20px;
33
- }
34
-
35
- table {
36
- width: 100%;
37
- border-collapse: collapse;
38
- margin-bottom: 20px;
39
- }
40
-
41
- th, td {
42
- padding: 10px;
43
- border: 1px solid #ddd;
44
- text-align: left;
45
- }
46
-
47
- th {
48
- background-color: #f8f8f8;
49
- }
50
-
51
- .totals td {
52
- font-weight: bold;
53
- }
54
-
55
- .footer {
56
- font-size: 12px;
57
- color: #777;
58
- text-align: center;
59
- }
60
- </style>
61
- </head>
62
- <body>
63
- <div class="container">
64
- <div class="logo">
65
- <img src="{{ logoUrl }}" alt="Logo">
66
- </div>
67
-
68
- <div class="header">
69
- New Order Received
70
- </div>
71
-
72
- <p>A new order has been placed by <strong>{{order.billingAddress.firstName}} {{order.billingAddress.lastName}}</strong>.</p>
73
-
74
- <h3>Customer Contact</h3>
75
- <p>
76
- Email: <a href="mailto:{{order.billingAddress.email}}">{{order.billingAddress.email}}</a><br>
77
- Phone: {{order.billingAddress.phone}}
78
- </p>
79
-
80
- <h3>Order Summary</h3>
81
- <table>
82
- <thead>
83
- <tr>
84
- <th>SKU</th>
85
- <th>Type</th>
86
- <th>Price</th>
87
- <th>Qty</th>
88
- </tr>
89
- </thead>
90
- <tbody>
91
- {{#each order.lineItems}}
92
- <tr>
93
- <td>{{sku}}</td>
94
- <td>{{type}}</td>
95
- <td>{{currencySymbol}} {{price.price}}</td>
96
- <td>{{quantity}}</td>
97
- </tr>
98
- {{/each}}
99
- </tbody>
100
- </table>
101
-
102
- <table class="totals">
103
- <tr>
104
- <td>Subtotal:</td>
105
- <td style="text-align: right;">{{currencySymbol}} {{order.subTotal}}</td>
106
- </tr>
107
- <tr>
108
- <td>Tax:</td>
109
- <td style="text-align: right;">{{currencySymbol}} {{order.tax}}</td>
110
- </tr>
111
- <tr>
112
- <td>Shipping:</td>
113
- <td style="text-align: right;">{{currencySymbol}} {{order.shipping}}</td>
114
- </tr>
115
- <tr>
116
- <td>Total:</td>
117
- <td style="text-align: right;"><strong>{{currencySymbol}} {{order.total}}</strong></td>
118
- </tr>
119
- </table>
120
-
121
- <h3>Billing Address</h3>
122
- <p>
123
- {{order.billingAddress.firstName}} {{order.billingAddress.lastName}}<br>
124
- {{order.billingAddress.addressLine1}}<br>
125
- {{order.billingAddress.addressLine2}}<br>
126
- {{order.billingAddress.city}}, {{order.billingAddress.county}}<br>
127
- {{order.billingAddress.postcode}}<br>
128
- {{order.billingAddress.country}}
129
- </p>
130
-
131
- <div class="footer">
132
- This is an automated notification from GnarEngine.
133
- </div>
134
- </div>
135
- </body>
136
- </html>
@@ -1,87 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>Subscription Cancelled - Admin Notification</title>
6
- <style>
7
- body {
8
- font-family: Arial, sans-serif;
9
- font-size: 14px;
10
- color: #333;
11
- }
12
-
13
- .container {
14
- max-width: 600px;
15
- margin: auto;
16
- padding: 20px;
17
- border: 1px solid #eee;
18
- }
19
-
20
- .logo {
21
- text-align: center;
22
- margin-bottom: 20px;
23
- }
24
-
25
- .logo img {
26
- max-height: 60px;
27
- }
28
-
29
- .header {
30
- text-align: center;
31
- font-size: 20px;
32
- margin-bottom: 20px;
33
- color: #e67e22;
34
- }
35
-
36
- .content p {
37
- margin-bottom: 15px;
38
- }
39
-
40
- .details {
41
- border-top: 1px solid #ccc;
42
- padding-top: 10px;
43
- margin-top: 20px;
44
- }
45
-
46
- .details strong {
47
- display: inline-block;
48
- width: 140px;
49
- }
50
-
51
- .footer {
52
- font-size: 12px;
53
- color: #777;
54
- text-align: center;
55
- margin-top: 30px;
56
- }
57
- </style>
58
- </head>
59
- <body>
60
- <div class="container">
61
- <div class="logo">
62
- <img src="{{ logoUrl }}" alt="Logo">
63
- </div>
64
-
65
- <div class="header">
66
- Subscription Cancelled After Failed Payments
67
- </div>
68
-
69
- <div class="content">
70
- <p>A customer's subscription has been <strong>cancelled</strong> after three failed payment attempts.</p>
71
-
72
- <div class="details">
73
- <p><strong>Customer Name:</strong> {{firstName}} {{lastName}}</p>
74
- <p><strong>Email:</strong> {{email}}</p>
75
- <p><strong>Subscription ID:</strong> {{subscriptionId}}</p>
76
- <p><strong>Reason:</strong> Payment failed 3 times</p>
77
- </div>
78
-
79
- <p>Please take any follow-up action if required.</p>
80
- </div>
81
-
82
- <div class="footer">
83
- This is an automated message from your store notification system.
84
- </div>
85
- </div>
86
- </body>
87
- </html>
@@ -1,132 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>Order Received</title>
6
- <style>
7
- body {
8
- font-family: Arial, sans-serif;
9
- font-size: 14px;
10
- color: #333;
11
- }
12
-
13
- .container {
14
- max-width: 600px;
15
- margin: auto;
16
- padding: 20px;
17
- border: 1px solid #eee;
18
- }
19
-
20
- .logo {
21
- text-align: center;
22
- margin-bottom: 20px;
23
- }
24
-
25
- .logo img {
26
- max-height: 60px;
27
- }
28
-
29
- .header {
30
- text-align: center;
31
- font-size: 20px;
32
- margin-bottom: 20px;
33
- }
34
-
35
- table {
36
- width: 100%;
37
- border-collapse: collapse;
38
- margin-bottom: 20px;
39
- }
40
-
41
- th, td {
42
- padding: 10px;
43
- border: 1px solid #ddd;
44
- text-align: left;
45
- }
46
-
47
- th {
48
- background-color: #f8f8f8;
49
- }
50
-
51
- .totals td {
52
- font-weight: bold;
53
- }
54
-
55
- .footer {
56
- font-size: 12px;
57
- color: #777;
58
- text-align: center;
59
- }
60
- </style>
61
- </head>
62
- <body>
63
- <div class="container">
64
- <div class="logo">
65
- <img src="{{ logoUrl }}" alt="Logo">
66
- </div>
67
-
68
- <div class="header">
69
- Thank you for your order, {{order.billingAddress.firstName}}!
70
- </div>
71
-
72
- <p>We've received your order and are now processing it. Here are the details:</p>
73
-
74
- <h3>Order Summary</h3>
75
- <table>
76
- <thead>
77
- <tr>
78
- <th>SKU</th>
79
- <th>Type</th>
80
- <th>Price</th>
81
- <th>Qty</th>
82
- </tr>
83
- </thead>
84
- <tbody>
85
- {{#each order.lineItems}}
86
- <tr>
87
- <td>{{sku}}</td>
88
- <td>{{type}}</td>
89
- <td>{{currencySymbol}} {{price.price}}</td>
90
- <td>{{quantity}}</td>
91
- </tr>
92
- {{/each}}
93
- </tbody>
94
- </table>
95
-
96
- <table class="totals">
97
- <tr>
98
- <td>Subtotal:</td>
99
- <td style="text-align: right;">{{currencySymbol}} {{order.subTotal}}</td>
100
- </tr>
101
- <tr>
102
- <td>Tax:</td>
103
- <td style="text-align: right;">{{currencySymbol}} {{order.tax}}</td>
104
- </tr>
105
- <tr>
106
- <td>Shipping:</td>
107
- <td style="text-align: right;">{{currencySymbol}} {{order.shipping}}</td>
108
- </tr>
109
- <tr>
110
- <td>Total:</td>
111
- <td style="text-align: right;"><strong>{{currencySymbol}} {{order.total}}</strong></td>
112
- </tr>
113
- </table>
114
-
115
- <h3>Billing Information</h3>
116
- <p>
117
- {{order.billingAddress.firstName}} {{order.billingAddress.lastName}}<br>
118
- {{order.billingAddress.addressLine1}}<br>
119
- {{order.billingAddress.addressLine2}}<br>
120
- {{order.billingAddress.city}}, {{order.billingAddress.county}}<br>
121
- {{order.billingAddress.postcode}}<br>
122
- {{order.billingAddress.country}}<br>
123
- Phone: {{order.billingAddress.phone}}<br>
124
- Email: {{order.billingAddress.email}}
125
- </p>
126
-
127
- <div class="footer">
128
- If you have any questions, please contact us at support@gnar.co.uk
129
- </div>
130
- </div>
131
- </body>
132
- </html>
@@ -1,77 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>Subscription Cancelled</title>
6
- <style>
7
- body {
8
- font-family: Arial, sans-serif;
9
- font-size: 14px;
10
- color: #333;
11
- }
12
-
13
- .container {
14
- max-width: 600px;
15
- margin: auto;
16
- padding: 20px;
17
- border: 1px solid #eee;
18
- }
19
-
20
- .logo {
21
- text-align: center;
22
- margin-bottom: 20px;
23
- }
24
-
25
- .logo img {
26
- max-height: 60px;
27
- }
28
-
29
- .header {
30
- text-align: center;
31
- font-size: 20px;
32
- margin-bottom: 20px;
33
- color: #c0392b;
34
- }
35
-
36
- .content p {
37
- margin-bottom: 15px;
38
- }
39
-
40
- .footer {
41
- font-size: 12px;
42
- color: #777;
43
- text-align: center;
44
- margin-top: 30px;
45
- }
46
- </style>
47
- </head>
48
- <body>
49
- <div class="container">
50
- <div class="logo">
51
- <img src="{{ logoUrl }}" alt="Logo">
52
- </div>
53
-
54
- <div class="header">
55
- Your Subscription Has Been Cancelled
56
- </div>
57
-
58
- <div class="content">
59
- <p>Hi {{firstName}},</p>
60
-
61
- <p>Unfortunately, we were unable to process your subscription payment after three attempts.</p>
62
-
63
- <p>As a result, your subscription has now been <strong>cancelled</strong>.</p>
64
-
65
- <p>If you'd like to continue enjoying our services, you'll need to purchase a new subscription.</p>
66
-
67
- <p>You can do this by visiting your account and selecting a new plan that suits you.</p>
68
-
69
- <p>If you believe this was a mistake or have updated your payment information, please contact our support team.</p>
70
- </div>
71
-
72
- <div class="footer">
73
- If you have any questions, feel free to contact us at support@gnar.co.uk
74
- </div>
75
- </div>
76
- </body>
77
- </html>