@gnar-engine/cli 1.0.4 → 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.
- package/bootstrap/deploy.localdev.yml +44 -3
- package/bootstrap/secrets.localdev.yml +20 -5
- package/bootstrap/services/control/src/config.js +4 -0
- package/bootstrap/services/notification/Dockerfile +2 -2
- package/bootstrap/services/notification/package.json +14 -32
- package/bootstrap/services/notification/src/app.js +50 -48
- package/bootstrap/services/notification/src/commands/notification.handler.js +96 -0
- package/bootstrap/services/notification/src/config.js +55 -12
- package/bootstrap/services/notification/src/controllers/http.controller.js +87 -0
- package/bootstrap/services/notification/src/controllers/message.controller.js +39 -70
- package/bootstrap/services/notification/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/notification/src/db/migrations/02-notification-service-init.js +23 -0
- package/bootstrap/services/notification/src/policies/notification.policy.js +49 -0
- package/bootstrap/services/notification/src/schema/notification.schema.js +17 -0
- package/bootstrap/services/notification/src/services/notification.service.js +32 -0
- package/bootstrap/services/page/Dockerfile +23 -0
- package/bootstrap/services/page/package.json +16 -0
- package/bootstrap/services/page/src/app.js +50 -0
- package/bootstrap/services/page/src/commands/block.handler.js +94 -0
- package/bootstrap/services/page/src/commands/page.handler.js +167 -0
- package/bootstrap/services/page/src/config.js +62 -0
- package/bootstrap/services/page/src/controllers/block.http.controller.js +87 -0
- package/bootstrap/services/page/src/controllers/message.controller.js +51 -0
- package/bootstrap/services/page/src/controllers/page.http.controller.js +89 -0
- package/bootstrap/services/page/src/policies/block.policy.js +50 -0
- package/bootstrap/services/page/src/policies/page.policy.js +49 -0
- package/bootstrap/services/page/src/schema/page.schema.js +139 -0
- package/bootstrap/services/page/src/services/block.service.js +83 -0
- package/bootstrap/services/page/src/services/page.service.js +83 -0
- package/bootstrap/services/portal/Dockerfile +20 -0
- package/bootstrap/services/portal/README.md +73 -0
- package/bootstrap/services/portal/index.html +13 -0
- package/bootstrap/services/portal/nginx.conf +5 -0
- package/bootstrap/services/portal/package.json +33 -0
- package/bootstrap/services/portal/public/vite.svg +1 -0
- package/bootstrap/services/portal/react-router.config.js +7 -0
- package/bootstrap/services/portal/src/App.jsx +16 -0
- package/bootstrap/services/portal/src/assets/gnar-engine-white-logo.svg +9 -0
- package/bootstrap/services/portal/src/assets/icon-agent.svg +6 -0
- package/bootstrap/services/portal/src/assets/icon-cog.svg +4 -0
- package/bootstrap/services/portal/src/assets/icon-delete.svg +3 -0
- package/bootstrap/services/portal/src/assets/icon-home.svg +3 -0
- package/bootstrap/services/portal/src/assets/icon-padlock.svg +3 -0
- package/bootstrap/services/portal/src/assets/icon-page.svg +6 -0
- package/bootstrap/services/portal/src/assets/icon-reports.svg +3 -0
- package/bootstrap/services/portal/src/assets/icon-user.svg +3 -0
- package/bootstrap/services/portal/src/assets/icon-users.svg +3 -0
- package/bootstrap/services/portal/src/assets/login-green-rad-back-1.jpg +0 -0
- package/bootstrap/services/portal/src/assets/react.svg +1 -0
- package/bootstrap/services/portal/src/components/CrudList/CrudList.jsx +85 -0
- package/bootstrap/services/portal/src/components/CrudList/CrudList.less +59 -0
- package/bootstrap/services/portal/src/components/CustomSelect/CustomSelect.jsx +81 -0
- package/bootstrap/services/portal/src/components/LoginForm/LoginForm.jsx +58 -0
- package/bootstrap/services/portal/src/components/PageBlockSwitch/PageBlockSwitch.jsx +129 -0
- package/bootstrap/services/portal/src/components/Sidebar/Sidebar.jsx +33 -0
- package/bootstrap/services/portal/src/components/Sidebar/Sidebar.less +37 -0
- package/bootstrap/services/portal/src/components/Topbar/Topbar.jsx +19 -0
- package/bootstrap/services/portal/src/components/Topbar/Topbar.less +22 -0
- package/bootstrap/services/portal/src/components/UserInfo/UserInfo.jsx +33 -0
- package/bootstrap/services/portal/src/components/UserInfo/UserInfo.less +21 -0
- package/bootstrap/services/portal/src/css/style.css +711 -0
- package/bootstrap/services/portal/src/data/pages.data.js +10 -0
- package/bootstrap/services/portal/src/elements/CustomSelect/CustomSelect.jsx +65 -0
- package/bootstrap/services/portal/src/elements/CustomSelect/CustomSelect.less +102 -0
- package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.jsx +115 -0
- package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.less +43 -0
- package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.jsx +124 -0
- package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.less +0 -0
- package/bootstrap/services/portal/src/elements/Repeater/Repeater.jsx +52 -0
- package/bootstrap/services/portal/src/elements/Repeater/Repeater.less +70 -0
- package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.jsx +18 -0
- package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.less +37 -0
- package/bootstrap/services/portal/src/elements/SaveButton/SaveButton.jsx +45 -0
- package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.jsx +63 -0
- package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.less +23 -0
- package/bootstrap/services/portal/src/elements/TextInput/TextInput.jsx +17 -0
- package/bootstrap/services/portal/src/layouts/Card/Card.jsx +15 -0
- package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.jsx +29 -0
- package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.less +49 -0
- package/bootstrap/services/portal/src/main.jsx +51 -0
- package/bootstrap/services/portal/src/pages/BlockSinglePage/BlockSinglePage.jsx +277 -0
- package/bootstrap/services/portal/src/pages/BlocksPage/BlocksPage.jsx +23 -0
- package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.jsx +11 -0
- package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.less +0 -0
- package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.jsx +21 -0
- package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.less +51 -0
- package/bootstrap/services/portal/src/pages/PageSinglePage/PageSinglePage.jsx +338 -0
- package/bootstrap/services/portal/src/pages/PagesPage/PagesPage.jsx +23 -0
- package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.jsx +9 -0
- package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.less +0 -0
- package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.jsx +25 -0
- package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.less +0 -0
- package/bootstrap/services/portal/src/services/block.js +28 -0
- package/bootstrap/services/portal/src/services/client.js +70 -0
- package/bootstrap/services/portal/src/services/gravatar.js +14 -0
- package/bootstrap/services/portal/src/services/page.js +28 -0
- package/bootstrap/services/portal/src/services/storage.js +62 -0
- package/bootstrap/services/portal/src/services/user.js +41 -0
- package/bootstrap/services/portal/src/slices/authSlice.js +101 -0
- package/bootstrap/services/portal/src/store/configureStore.js +10 -0
- package/bootstrap/services/portal/src/style/cards.less +57 -0
- package/bootstrap/services/portal/src/style/global.less +204 -0
- package/bootstrap/services/portal/src/style/icons.less +21 -0
- package/bootstrap/services/portal/src/style/inputs.less +52 -0
- package/bootstrap/services/portal/src/style/main.less +28 -0
- package/bootstrap/services/portal/src/utils/utils.js +9 -0
- package/bootstrap/services/portal/vite.config.js +12 -0
- package/bootstrap/services/user/src/app.js +6 -1
- package/bootstrap/services/user/src/commands/user.handler.js +35 -21
- package/bootstrap/services/user/src/config.js +5 -1
- package/bootstrap/services/user/src/policies/user.policy.js +3 -1
- package/bootstrap/services/user/src/tests/commands/user.test.js +31 -0
- package/install-from-clone.sh +30 -0
- package/package.json +1 -1
- package/src/cli.js +2 -0
- package/src/config.js +8 -0
- package/src/dev/commands.js +11 -3
- package/src/dev/dev.service.js +164 -64
- package/src/helpers/helpers.js +24 -0
- package/src/profiles/command.js +41 -0
- package/src/profiles/profiles.client.js +23 -0
- package/src/provisioner/Dockerfile +27 -0
- package/src/provisioner/package.json +19 -0
- package/src/provisioner/src/app.js +56 -0
- package/src/provisioner/src/services/mongodb.js +58 -0
- package/src/provisioner/src/services/mysql.js +51 -0
- package/src/provisioner/src/services/secrets.js +84 -0
- package/src/scaffolder/commands.js +58 -2
- package/src/scaffolder/scaffolder.handler.js +164 -72
- package/templates/entity/src/commands/{{entityName}}.handler.js.hbs +94 -0
- package/templates/entity/src/controllers/{{entityName}}.http.controller.js.hbs +87 -0
- package/templates/entity/src/mysql.db/migrations/03-{{entityName}}-entity-init.js.hbs +23 -0
- package/templates/entity/src/policies/{{entityName}}.policy.js.hbs +49 -0
- package/templates/entity/src/schema/{{entityName}}.schema.js.hbs +17 -0
- package/templates/entity/src/services/mongodb.{{entityName}}.service.js.hbs +70 -0
- package/templates/entity/src/services/mysql.{{entityName}}.service.js.hbs +27 -0
- package/templates/service/src/app.js.hbs +12 -1
- package/templates/service/src/commands/{{serviceName}}.handler.js.hbs +1 -1
- package/templates/service/src/mongodb.config.js.hbs +5 -1
- package/templates/service/src/mysql.config.js.hbs +4 -0
- package/bootstrap/services/notification/Dockerfile.prod +0 -37
- package/bootstrap/services/notification/README.md +0 -3
- package/bootstrap/services/notification/src/commands/command-bus.js +0 -20
- package/bootstrap/services/notification/src/commands/handlers/control.handler.js +0 -18
- package/bootstrap/services/notification/src/commands/handlers/notification.handler.js +0 -157
- package/bootstrap/services/notification/src/services/logger.service.js +0 -16
- package/bootstrap/services/notification/src/services/ses.service.js +0 -23
- package/bootstrap/services/notification/src/templates/admin-order-recieved.hbs +0 -136
- package/bootstrap/services/notification/src/templates/admin-subscription-failed.hbs +0 -87
- package/bootstrap/services/notification/src/templates/customer-order-recieved.hbs +0 -132
- package/bootstrap/services/notification/src/templates/customer-subscription-failed.hbs +0 -77
- package/bootstrap/services/user/src/tests/user.test.js +0 -126
- /package/bootstrap/services/{notification/src/tests/notification.test.js → portal/src/components/CustomSelect/CustomSelect.less} +0 -0
|
@@ -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>
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
const request = require('supertest');
|
|
2
|
-
const url = 'http://localhost';
|
|
3
|
-
|
|
4
|
-
describe('User API', () => {
|
|
5
|
-
|
|
6
|
-
let adminAuthToken;
|
|
7
|
-
let customerAuthToken;
|
|
8
|
-
let userId;
|
|
9
|
-
let testCustomerEmail;
|
|
10
|
-
|
|
11
|
-
beforeAll(async () => {
|
|
12
|
-
// check we are not in production mode
|
|
13
|
-
if (process.env.NODE_ENV === 'production') {
|
|
14
|
-
throw new Error('Do not run tests in production mode!');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
testCustomerEmail = 'customertest13@gnar.co.uk';
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Test authenticate with email and password
|
|
21
|
-
it('POST /authenticate (as admin)', async () => {
|
|
22
|
-
const response = await request(url).post('/authenticate')
|
|
23
|
-
.set('Content-Type', 'application/json')
|
|
24
|
-
.send({
|
|
25
|
-
username: 'root@gnar.co.uk',
|
|
26
|
-
password: 'gn4rlyR00tP0rt4lP4ss'
|
|
27
|
-
});
|
|
28
|
-
console.log(response.body);
|
|
29
|
-
expect(response.status).toBe(200);
|
|
30
|
-
expect(response.body).toHaveProperty('token');
|
|
31
|
-
|
|
32
|
-
adminAuthToken = response.body.token;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Create new customer user (success no auth required)
|
|
36
|
-
it('POST /users (create new customer user no auth required)', async () => {
|
|
37
|
-
const response = await request(url).post('/users')
|
|
38
|
-
.set('Content-Type', 'application/json')
|
|
39
|
-
.send({
|
|
40
|
-
user:
|
|
41
|
-
{
|
|
42
|
-
email: testCustomerEmail,
|
|
43
|
-
password: 'password1234'
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
console.log(response.body);
|
|
47
|
-
expect(response.status).toBe(200);
|
|
48
|
-
expect(response.body.users[0].email).toBe(testCustomerEmail);
|
|
49
|
-
|
|
50
|
-
// Save the new user id
|
|
51
|
-
userId = response.body.users[0].id;
|
|
52
|
-
console.log('New user id: ' + userId);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Test authenticate with new user
|
|
56
|
-
it('POST /authenticate (as new customer user)', async () => {
|
|
57
|
-
const response = await request(url).post('/authenticate')
|
|
58
|
-
.set('Content-Type', 'application/json')
|
|
59
|
-
.send({
|
|
60
|
-
username: testCustomerEmail,
|
|
61
|
-
password: 'password1234'
|
|
62
|
-
});
|
|
63
|
-
console.log(response.body);
|
|
64
|
-
expect(response.status).toBe(200);
|
|
65
|
-
expect(response.body).toHaveProperty('token');
|
|
66
|
-
|
|
67
|
-
customerAuthToken = response.body.token;
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Fetch single customer user (as customer)
|
|
71
|
-
it('GET /users/{id} (as customer)', async () => {
|
|
72
|
-
const response = await request(url).get('/users/' + userId)
|
|
73
|
-
.set('Authorization', 'Bearer ' + customerAuthToken);
|
|
74
|
-
console.log(response.body);
|
|
75
|
-
expect(response.status).toBe(200);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Fetch all users (not authorised as customer)
|
|
79
|
-
it('GET /users (not authorised as customer)', async () => {
|
|
80
|
-
const response = await request(url).get('/users')
|
|
81
|
-
.set('Authorization', 'Bearer ' + customerAuthToken);
|
|
82
|
-
console.log(response.body);
|
|
83
|
-
expect(response.status).toBe(403);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Fetch all users (success as admin)
|
|
87
|
-
it('GET /users (as admin)', async () => {
|
|
88
|
-
const response = await request(url).get('/users')
|
|
89
|
-
.set('Authorization', 'Bearer ' + adminAuthToken);
|
|
90
|
-
console.log(response.body);
|
|
91
|
-
expect(response.status).toBe(200);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Update customer user (as customer)
|
|
95
|
-
it('POST /users/{id} (as customer)', async () => {
|
|
96
|
-
const response = await request(url).post('/users/' + userId)
|
|
97
|
-
.set('Authorization', 'Bearer ' + customerAuthToken)
|
|
98
|
-
.set('Content-Type', 'application/json')
|
|
99
|
-
.send({
|
|
100
|
-
email: 'changedcustomeremail2@gnar.co.uk'
|
|
101
|
-
});
|
|
102
|
-
console.log(response.body);
|
|
103
|
-
expect(response.status).toBe(200);
|
|
104
|
-
expect(response.body.user.email).toBe('changedcustomeremail2@gnar.co.uk');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Update customer user (check cannot elevate role to admin)
|
|
108
|
-
it('POST /users/{id} (as customer)', async () => {
|
|
109
|
-
const response = await request(url).post('/users/' + userId)
|
|
110
|
-
.set('Authorization', 'Bearer ' + customerAuthToken)
|
|
111
|
-
.set('Content-Type', 'application/json')
|
|
112
|
-
.send({
|
|
113
|
-
role: 'service_admin'
|
|
114
|
-
});
|
|
115
|
-
console.log(response.body);
|
|
116
|
-
expect(response.status).toBe(403);
|
|
117
|
-
});-
|
|
118
|
-
|
|
119
|
-
// Delete customer user (as admin)
|
|
120
|
-
it('DELETE /users/{id} (as admin)', async () => {
|
|
121
|
-
const response = await request(url).delete('/users/' + userId)
|
|
122
|
-
.set('Authorization', 'Bearer ' + adminAuthToken);
|
|
123
|
-
console.log(response.body);
|
|
124
|
-
expect(response.status).toBe(200);
|
|
125
|
-
});
|
|
126
|
-
});
|