cloudcommerce 0.0.50 → 0.0.53
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/CHANGELOG.md +45 -0
- package/CONTRIBUTING.md +2 -2
- package/package.json +9 -9
- package/packages/api/lib/index.d.ts +40 -104
- package/packages/api/lib/types/applications.d.ts +10 -62
- package/packages/api/package.json +1 -1
- package/packages/api/src/types/applications.d.ts +10 -62
- package/packages/apps/_app.config.js +80 -0
- package/packages/apps/discounts/lib/discounts.config.d.ts +14 -0
- package/packages/apps/discounts/lib/discounts.config.js +19 -0
- package/packages/apps/discounts/lib/discounts.config.js.map +1 -0
- package/packages/apps/discounts/lib/discounts.d.ts +2 -0
- package/packages/apps/discounts/lib/discounts.js +7 -0
- package/packages/apps/discounts/lib/discounts.js.map +1 -0
- package/packages/apps/discounts/lib/index.d.ts +1 -3
- package/packages/apps/discounts/lib/index.js +1 -8
- package/packages/apps/discounts/lib/index.js.map +1 -1
- package/packages/apps/discounts/package.json +3 -2
- package/packages/apps/discounts/src/discounts.config.ts +25 -0
- package/packages/apps/discounts/src/discounts.ts +8 -0
- package/packages/apps/discounts/src/index.ts +1 -9
- package/packages/cli/config/firebase.json +16 -1
- package/packages/cli/lib/config-gcloud.js +94 -0
- package/packages/cli/lib/create-auth.js +7 -7
- package/packages/cli/lib/index.js +16 -3
- package/packages/cli/package.json +2 -2
- package/packages/cli/src/config-gcloud.ts +103 -0
- package/packages/cli/src/create-auth.ts +7 -7
- package/packages/cli/src/index.ts +17 -4
- package/packages/events/lib/firebase.js +0 -2
- package/packages/events/lib/firebase.js.map +1 -1
- package/packages/events/package.json +1 -1
- package/packages/events/src/firebase.ts +0 -2
- package/packages/firebase/lib/config.js +12 -8
- package/packages/firebase/lib/config.js.map +1 -1
- package/packages/firebase/lib/index.d.ts +0 -1
- package/packages/firebase/lib/index.js +0 -4
- package/packages/firebase/lib/index.js.map +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/firebase/src/config.ts +13 -8
- package/packages/firebase/src/index.ts +0 -4
- package/packages/modules/lib/firebase/call-app-module.js +1 -1
- package/packages/modules/lib/firebase/call-app-module.js.map +1 -1
- package/packages/modules/lib/firebase/handle-module.js.map +1 -1
- package/packages/modules/lib/firebase.js +0 -2
- package/packages/modules/lib/firebase.js.map +1 -1
- package/packages/modules/package.json +2 -2
- package/packages/modules/src/firebase/call-app-module.ts +1 -1
- package/packages/modules/src/firebase/handle-module.ts +3 -3
- package/packages/modules/src/firebase.ts +0 -2
- package/packages/passport/lib/firebase/handle-passport.js +108 -0
- package/packages/passport/lib/firebase/handle-passport.js.map +1 -0
- package/packages/passport/lib/firebase/serve-passport-api.js +41 -0
- package/packages/passport/lib/firebase/serve-passport-api.js.map +1 -0
- package/packages/passport/lib/firebase.js +22 -5
- package/packages/passport/lib/firebase.js.map +1 -1
- package/packages/passport/package.json +1 -1
- package/packages/passport/src/firebase/handle-passport.ts +149 -0
- package/packages/passport/src/firebase/serve-passport-api.ts +62 -0
- package/packages/passport/src/firebase.ts +32 -7
- package/packages/ssr/package.json +1 -1
- package/packages/storefront/package.json +12 -2
- package/packages/types/index.ts +9 -0
- package/packages/types/package.json +1 -1
- package/packages/firebase/lib/handlers/auth-callback.d.ts +0 -3
- package/packages/firebase/lib/handlers/auth-callback.js +0 -45
- package/packages/firebase/lib/handlers/auth-callback.js.map +0 -1
- package/packages/firebase/src/handlers/auth-callback.ts +0 -49
- package/packages/passport/src/firebase/.gitkeep +0 -0
- package/pnpm-lock.yaml +0 -7887
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-disable comma-dangle, no-multi-spaces, key-spacing, max-len */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edit base E-Com Plus Application object here.
|
|
5
|
+
* Ref.: https://developers.e-com.plus/docs/api/#/store/applications/
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default () => {
|
|
9
|
+
return {
|
|
10
|
+
app_id: 9000,
|
|
11
|
+
title: 'My Awesome E-Com Plus App',
|
|
12
|
+
slug: 'my-awesome-app',
|
|
13
|
+
type: 'external',
|
|
14
|
+
state: 'active',
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Uncomment modules above to work with E-Com Plus Mods API on Storefront.
|
|
18
|
+
* Ref.: https://developers.e-com.plus/modules-api/
|
|
19
|
+
*/
|
|
20
|
+
modules: {
|
|
21
|
+
/**
|
|
22
|
+
* Triggered to calculate shipping options, must return values and deadlines.
|
|
23
|
+
* Start editing `routes/ecom/modules/calculate-shipping.js`
|
|
24
|
+
*/
|
|
25
|
+
// calculate_shipping: { enabled: true },
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Triggered to validate and apply discount value, must return discount and conditions.
|
|
29
|
+
* Start editing `routes/ecom/modules/apply-discount.js`
|
|
30
|
+
*/
|
|
31
|
+
// apply_discount: { enabled: true },
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Triggered when listing payments, must return available payment methods.
|
|
35
|
+
* Start editing `routes/ecom/modules/list-payments.js`
|
|
36
|
+
*/
|
|
37
|
+
// list_payments: { enabled: true },
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Triggered when order is being closed, must create payment transaction and return info.
|
|
41
|
+
* Start editing `routes/ecom/modules/create-transaction.js`
|
|
42
|
+
*/
|
|
43
|
+
// create_transaction: { enabled: true },
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
admin_settings: {
|
|
47
|
+
/**
|
|
48
|
+
* JSON schema based fields to be configured by merchant and saved to app `data` / `hidden_data`, such as:
|
|
49
|
+
|
|
50
|
+
webhook_uri: {
|
|
51
|
+
schema: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
maxLength: 255,
|
|
54
|
+
format: 'uri',
|
|
55
|
+
title: 'Notifications URI',
|
|
56
|
+
description: 'Unique notifications URI available on your Custom App dashboard'
|
|
57
|
+
},
|
|
58
|
+
hide: true
|
|
59
|
+
},
|
|
60
|
+
token: {
|
|
61
|
+
schema: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
maxLength: 50,
|
|
64
|
+
title: 'App token'
|
|
65
|
+
},
|
|
66
|
+
hide: true
|
|
67
|
+
},
|
|
68
|
+
opt_in: {
|
|
69
|
+
schema: {
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
default: false,
|
|
72
|
+
title: 'Some config option'
|
|
73
|
+
},
|
|
74
|
+
hide: false
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
*/
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import config from '@cloudcommerce/firebase/lib/config';
|
|
2
|
+
|
|
3
|
+
export default () => {
|
|
4
|
+
const { lang, apps: { discounts: { appId } } } = config.get();
|
|
5
|
+
return {
|
|
6
|
+
app_id: appId,
|
|
7
|
+
title: lang.startsWith('en') ? 'Campaigns and discounts' : 'Campanhas e descontos',
|
|
8
|
+
slug: 'discounts',
|
|
9
|
+
type: 'external',
|
|
10
|
+
state: 'active',
|
|
11
|
+
modules: {
|
|
12
|
+
apply_discount: {
|
|
13
|
+
enabled: true,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
admin_settings: {},
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
// # sourceMappingURL=discounts.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discounts.config.js","sourceRoot":"","sources":["../src/discounts.config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oCAAoC,CAAC;AAExD,eAAe,GAAG,EAAE;IAClB,MAAM,EACJ,IAAI,EACJ,IAAI,EAAE,EACJ,SAAS,EAAE,EAAE,KAAK,EAAE,GACrB,GACF,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;IAEjB,OAAO;QACL,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,uBAAuB;QAClF,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE;YACP,cAAc,EAAE;gBACd,OAAO,EAAE,IAAI;aACd;SACF;QACD,cAAc,EAAE,EACf;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discounts.js","sourceRoot":"","sources":["../src/discounts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,OAAsB,EAAE,EAAE;IAC5D,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcommerce/app-discounts",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.53",
|
|
5
5
|
"description": "E-Com Plus Cloud Commerce app for complex discount rules",
|
|
6
|
-
"main": "lib/
|
|
6
|
+
"main": "lib/discounts.js",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/ecomplus/cloud-commerce.git",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@cloudcommerce/api": "workspace:*",
|
|
23
|
+
"@cloudcommerce/firebase": "workspace:*",
|
|
23
24
|
"firebase-admin": "^11.0.1",
|
|
24
25
|
"firebase-functions": "^3.22.0"
|
|
25
26
|
},
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import config from '@cloudcommerce/firebase/lib/config';
|
|
2
|
+
|
|
3
|
+
export default () => {
|
|
4
|
+
const {
|
|
5
|
+
lang,
|
|
6
|
+
apps: {
|
|
7
|
+
discounts: { appId },
|
|
8
|
+
},
|
|
9
|
+
} = config.get();
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
app_id: appId,
|
|
13
|
+
title: lang.startsWith('en') ? 'Campaigns and discounts' : 'Campanhas e descontos',
|
|
14
|
+
slug: 'discounts',
|
|
15
|
+
type: 'external',
|
|
16
|
+
state: 'active',
|
|
17
|
+
modules: {
|
|
18
|
+
apply_discount: {
|
|
19
|
+
enabled: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
admin_settings: {
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import type { AppModuleBody } from '@cloudcommerce/types';
|
|
3
|
+
import { logger } from 'firebase-functions';
|
|
4
|
+
|
|
5
|
+
export const applyDiscount = async (modBody: AppModuleBody) => {
|
|
6
|
+
logger.info(modBody);
|
|
7
|
+
return {};
|
|
8
|
+
};
|
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { logger } from 'firebase-functions';
|
|
3
|
-
|
|
4
|
-
export const events: AppEventsTopic[] = [];
|
|
5
|
-
|
|
6
|
-
export const applyDiscount = async () => {
|
|
7
|
-
logger.info('Hello discounts app');
|
|
8
|
-
return {};
|
|
9
|
-
};
|
|
1
|
+
export * from './discounts';
|
|
@@ -36,7 +36,22 @@
|
|
|
36
36
|
"firebase.json",
|
|
37
37
|
"**/.*",
|
|
38
38
|
"**/node_modules/**"
|
|
39
|
-
]
|
|
39
|
+
],
|
|
40
|
+
"rewrites": [
|
|
41
|
+
{
|
|
42
|
+
"source": "/api/modules/**",
|
|
43
|
+
"function": "modules"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"source": "/api/passport/**",
|
|
47
|
+
"function": "passport"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"source": "**/!(*(*.)js|*(*.)css|*(*.)ico|*(*.)png|*(*.)gif|*(*.)jpg|*(*.)jpeg|*(*.)webp|*(*.)avif|*(*.)svg|*(*.)woff|*(*.)woff2|*(*.)otf|*(*.)ttf|*(*.)eot)",
|
|
51
|
+
"function": "ssr"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"cleanUrls": true
|
|
40
55
|
},
|
|
41
56
|
"storage": {
|
|
42
57
|
"rules": "storage.rules"
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { $, fs } from 'zx';
|
|
3
|
+
|
|
4
|
+
const serviceAccountId = 'cloud-commerce-gh-actions';
|
|
5
|
+
const getAccountEmail = (projectId) => {
|
|
6
|
+
return `${serviceAccountId}@${projectId}.iam.gserviceaccount.com`;
|
|
7
|
+
};
|
|
8
|
+
const checkServiceAccountExists = async (projectId) => {
|
|
9
|
+
let hasServiceAccount;
|
|
10
|
+
try {
|
|
11
|
+
const { stderr } = await $`gcloud iam service-accounts describe ${getAccountEmail(projectId)}`;
|
|
12
|
+
hasServiceAccount = !/not_?found/i.test(stderr);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return hasServiceAccount;
|
|
17
|
+
};
|
|
18
|
+
const siginGcloudAndSetIAM = async (projectId, pwd) => {
|
|
19
|
+
if (/no credential/i.test((await $`gcloud auth list`).stderr)) {
|
|
20
|
+
await $`gcloud auth login`;
|
|
21
|
+
}
|
|
22
|
+
await $`gcloud config set project ${projectId}`;
|
|
23
|
+
const roles = [
|
|
24
|
+
'roles/firebase.admin',
|
|
25
|
+
'roles/appengine.appAdmin',
|
|
26
|
+
'roles/appengine.appCreator',
|
|
27
|
+
'roles/artifactregistry.admin',
|
|
28
|
+
'roles/cloudfunctions.admin',
|
|
29
|
+
'roles/cloudscheduler.admin',
|
|
30
|
+
'roles/iam.serviceAccountUser',
|
|
31
|
+
'roles/run.viewer',
|
|
32
|
+
'roles/serviceusage.apiKeysViewer',
|
|
33
|
+
'roles/serviceusage.serviceUsageAdmin',
|
|
34
|
+
];
|
|
35
|
+
const serviceAccount = await checkServiceAccountExists(projectId);
|
|
36
|
+
if (!serviceAccount) {
|
|
37
|
+
await $`gcloud iam service-accounts create ${serviceAccountId} \
|
|
38
|
+
--description="A service account with permission to deploy Cloud Commerce from the GitHub repository to Firebase" \
|
|
39
|
+
--display-name="Cloud Commerce GH Actions"`;
|
|
40
|
+
}
|
|
41
|
+
await fs.ensureDir(path.join(pwd, '.cloudcommerce'));
|
|
42
|
+
const pathPolicyIAM = path.join(pwd, '.cloudcommerce', 'policyIAM.json');
|
|
43
|
+
await $`gcloud projects get-iam-policy ${projectId} --format json > ${pathPolicyIAM}`;
|
|
44
|
+
const policyIAM = fs.readJSONSync(pathPolicyIAM);
|
|
45
|
+
const { bindings } = policyIAM;
|
|
46
|
+
let mustUpdatePolicy = false;
|
|
47
|
+
roles.forEach((role) => {
|
|
48
|
+
const roleFound = bindings.find((binding) => binding.role === role);
|
|
49
|
+
const memberServiceAccount = `serviceAccount:${getAccountEmail(projectId)}`;
|
|
50
|
+
if (!roleFound) {
|
|
51
|
+
const newBinding = {
|
|
52
|
+
members: [
|
|
53
|
+
memberServiceAccount,
|
|
54
|
+
],
|
|
55
|
+
role,
|
|
56
|
+
};
|
|
57
|
+
if (role === 'roles/serviceusage.serviceUsageAdmin') {
|
|
58
|
+
const roleExpiration = Date.now() + 1000 * 60 * 60 * 12;
|
|
59
|
+
newBinding.condition = {
|
|
60
|
+
expression: `request.time < timestamp("${new Date(roleExpiration).toISOString()}")`,
|
|
61
|
+
title: 'Enable APIs on first deploy',
|
|
62
|
+
description: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
bindings.push(newBinding);
|
|
66
|
+
mustUpdatePolicy = true;
|
|
67
|
+
} else {
|
|
68
|
+
const serviceAccountHavePermission = roleFound.members.find((account) => account === memberServiceAccount);
|
|
69
|
+
if (!serviceAccountHavePermission) {
|
|
70
|
+
roleFound.members.push(memberServiceAccount);
|
|
71
|
+
mustUpdatePolicy = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
if (mustUpdatePolicy) {
|
|
76
|
+
fs.writeJSONSync(pathPolicyIAM, policyIAM);
|
|
77
|
+
return $`gcloud projects set-iam-policy ${projectId} ${pathPolicyIAM}`;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
const createKeyServiceAccount = async (projectId, pwd) => {
|
|
82
|
+
try {
|
|
83
|
+
const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
|
|
84
|
+
await $`gcloud iam service-accounts keys create ${pathFileKey} \
|
|
85
|
+
--iam-account=${getAccountEmail(projectId)}`;
|
|
86
|
+
return JSON.stringify(fs.readJSONSync(pathFileKey));
|
|
87
|
+
} catch (e) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default siginGcloudAndSetIAM;
|
|
93
|
+
|
|
94
|
+
export { siginGcloudAndSetIAM, createKeyServiceAccount };
|
|
@@ -26,15 +26,15 @@ export default async (storeId, accessToken) => {
|
|
|
26
26
|
username: `cloudcomm${Date.now()}`,
|
|
27
27
|
permissions: {
|
|
28
28
|
applications: ['all'],
|
|
29
|
-
brands: ['
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
brands: ['all'],
|
|
30
|
+
categories: ['all'],
|
|
31
|
+
collections: ['all'],
|
|
32
|
+
grids: ['all'],
|
|
33
|
+
products: ['all'],
|
|
33
34
|
customers: ['all'],
|
|
34
|
-
|
|
35
|
+
carts: ['all'],
|
|
35
36
|
orders: ['GET', 'POST', 'PATCH'],
|
|
36
|
-
|
|
37
|
-
stores: ['GET'],
|
|
37
|
+
stores: ['GET', 'PATCH'],
|
|
38
38
|
},
|
|
39
39
|
}, apiConfig);
|
|
40
40
|
authenticationId = _id;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from 'zx';
|
|
6
6
|
import login from './login.js';
|
|
7
7
|
import build from './build.js';
|
|
8
|
+
import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud.js';
|
|
8
9
|
|
|
9
10
|
const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
|
|
10
11
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
@@ -28,7 +29,7 @@ if (projectId) {
|
|
|
28
29
|
const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
|
|
29
30
|
projectId = firebaserc.projects.default;
|
|
30
31
|
} catch (e) {
|
|
31
|
-
projectId = 'ecom2-
|
|
32
|
+
projectId = 'ecom2-001';
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
}
|
|
@@ -36,13 +37,16 @@ if (projectId) {
|
|
|
36
37
|
export default async () => {
|
|
37
38
|
await fs.copy(path.join(__dirname, '..', 'config'), pwd);
|
|
38
39
|
const options = Object.keys(argv).reduce((opts, key) => {
|
|
39
|
-
if (key !== '_' && key !==
|
|
40
|
+
if (key !== '_' && argv[key] !== false) {
|
|
40
41
|
// eslint-disable-next-line no-param-reassign
|
|
41
42
|
opts += ` --${key} ${argv[key]}`;
|
|
42
43
|
}
|
|
43
44
|
return opts;
|
|
44
45
|
}, '');
|
|
45
46
|
const $firebase = (cmd) => {
|
|
47
|
+
if (cmd === 'deploy') {
|
|
48
|
+
return $`firebase --project=${projectId} ${cmd}${options} --force`;
|
|
49
|
+
}
|
|
46
50
|
return $`firebase --project=${projectId} ${cmd}${options}`;
|
|
47
51
|
};
|
|
48
52
|
if (argv._.includes('serve')) {
|
|
@@ -94,6 +98,15 @@ ECOM_STORE_ID=${storeId}
|
|
|
94
98
|
//
|
|
95
99
|
}
|
|
96
100
|
}
|
|
101
|
+
let serviceAccountJSON = null;
|
|
102
|
+
if (argv.gcloud !== false) {
|
|
103
|
+
try {
|
|
104
|
+
await siginGcloudAndSetIAM(projectId, pwd);
|
|
105
|
+
serviceAccountJSON = await createKeyServiceAccount(projectId, pwd);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
//
|
|
108
|
+
}
|
|
109
|
+
}
|
|
97
110
|
return echo`
|
|
98
111
|
****
|
|
99
112
|
|
|
@@ -103,7 +116,7 @@ Finish by saving the following secrets to your GitHub repository:
|
|
|
103
116
|
|
|
104
117
|
${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
|
|
105
118
|
|
|
106
|
-
${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
|
|
119
|
+
${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = ${chalk.bgMagenta(serviceAccountJSON || '{YOUR_SERVICE_ACCOUNT_JSON}')}
|
|
107
120
|
|
|
108
121
|
-- More info at https://github.com/ecomplus/store#getting-started
|
|
109
122
|
`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcommerce/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.53",
|
|
5
5
|
"description": "E-Com Plus Cloud Commerce CLI tools",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cloudcommerce": "./bin/run.mjs"
|
|
@@ -28,6 +28,6 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@cloudcommerce/api": "workspace:*",
|
|
30
30
|
"md5": "^2.3.0",
|
|
31
|
-
"zx": "^7.0.
|
|
31
|
+
"zx": "^7.0.8"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { $, fs } from 'zx';
|
|
3
|
+
|
|
4
|
+
const serviceAccountId = 'cloud-commerce-gh-actions';
|
|
5
|
+
const getAccountEmail = (projectId: string) => {
|
|
6
|
+
return `${serviceAccountId}@${projectId}.iam.gserviceaccount.com`;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const checkServiceAccountExists = async (projectId: string) => {
|
|
10
|
+
let hasServiceAccount: boolean;
|
|
11
|
+
try {
|
|
12
|
+
const { stderr } = await $`gcloud iam service-accounts describe ${getAccountEmail(projectId)}`;
|
|
13
|
+
hasServiceAccount = !/not_?found/i.test(stderr);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return hasServiceAccount;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const siginGcloudAndSetIAM = async (projectId: string, pwd: string) => {
|
|
21
|
+
if (/no credential/i.test((await $`gcloud auth list`).stderr)) {
|
|
22
|
+
await $`gcloud auth login`;
|
|
23
|
+
}
|
|
24
|
+
await $`gcloud config set project ${projectId}`;
|
|
25
|
+
const roles = [
|
|
26
|
+
'roles/firebase.admin',
|
|
27
|
+
'roles/appengine.appAdmin',
|
|
28
|
+
'roles/appengine.appCreator',
|
|
29
|
+
'roles/artifactregistry.admin',
|
|
30
|
+
'roles/cloudfunctions.admin',
|
|
31
|
+
'roles/cloudscheduler.admin',
|
|
32
|
+
'roles/iam.serviceAccountUser',
|
|
33
|
+
'roles/run.viewer',
|
|
34
|
+
'roles/serviceusage.apiKeysViewer',
|
|
35
|
+
'roles/serviceusage.serviceUsageAdmin',
|
|
36
|
+
];
|
|
37
|
+
const serviceAccount = await checkServiceAccountExists(projectId);
|
|
38
|
+
if (!serviceAccount) {
|
|
39
|
+
await $`gcloud iam service-accounts create ${serviceAccountId} \
|
|
40
|
+
--description="A service account with permission to deploy Cloud Commerce from the GitHub repository to Firebase" \
|
|
41
|
+
--display-name="Cloud Commerce GH Actions"`;
|
|
42
|
+
}
|
|
43
|
+
await fs.ensureDir(path.join(pwd, '.cloudcommerce'));
|
|
44
|
+
const pathPolicyIAM = path.join(pwd, '.cloudcommerce', 'policyIAM.json');
|
|
45
|
+
await $`gcloud projects get-iam-policy ${projectId} --format json > ${pathPolicyIAM}`;
|
|
46
|
+
const policyIAM = fs.readJSONSync(pathPolicyIAM);
|
|
47
|
+
const { bindings } = policyIAM;
|
|
48
|
+
|
|
49
|
+
let mustUpdatePolicy = false;
|
|
50
|
+
roles.forEach((role) => {
|
|
51
|
+
const roleFound = bindings.find((binding) => binding.role === role);
|
|
52
|
+
const memberServiceAccount = `serviceAccount:${getAccountEmail(projectId)}`;
|
|
53
|
+
if (!roleFound) {
|
|
54
|
+
const newBinding: { [key: string]: any } = {
|
|
55
|
+
members: [
|
|
56
|
+
memberServiceAccount,
|
|
57
|
+
],
|
|
58
|
+
role,
|
|
59
|
+
};
|
|
60
|
+
if (role === 'roles/serviceusage.serviceUsageAdmin') {
|
|
61
|
+
const roleExpiration = Date.now() + 1000 * 60 * 60 * 12;
|
|
62
|
+
newBinding.condition = {
|
|
63
|
+
expression: `request.time < timestamp("${new Date(roleExpiration).toISOString()}")`,
|
|
64
|
+
title: 'Enable APIs on first deploy',
|
|
65
|
+
description: null,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
bindings.push(newBinding);
|
|
69
|
+
mustUpdatePolicy = true;
|
|
70
|
+
} else {
|
|
71
|
+
const serviceAccountHavePermission = roleFound.members.find(
|
|
72
|
+
(account: string) => account === memberServiceAccount,
|
|
73
|
+
);
|
|
74
|
+
if (!serviceAccountHavePermission) {
|
|
75
|
+
roleFound.members.push(memberServiceAccount);
|
|
76
|
+
mustUpdatePolicy = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
if (mustUpdatePolicy) {
|
|
81
|
+
fs.writeJSONSync(pathPolicyIAM, policyIAM);
|
|
82
|
+
return $`gcloud projects set-iam-policy ${projectId} ${pathPolicyIAM}`;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const createKeyServiceAccount = async (projectId: string, pwd: string) => {
|
|
88
|
+
try {
|
|
89
|
+
const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
|
|
90
|
+
await $`gcloud iam service-accounts keys create ${pathFileKey} \
|
|
91
|
+
--iam-account=${getAccountEmail(projectId)}`;
|
|
92
|
+
return JSON.stringify(fs.readJSONSync(pathFileKey));
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default siginGcloudAndSetIAM;
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
siginGcloudAndSetIAM,
|
|
102
|
+
createKeyServiceAccount,
|
|
103
|
+
};
|
|
@@ -27,15 +27,15 @@ export default async (storeId: number, accessToken: string) => {
|
|
|
27
27
|
username: `cloudcomm${Date.now()}`,
|
|
28
28
|
permissions: {
|
|
29
29
|
applications: ['all'],
|
|
30
|
-
brands: ['
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
brands: ['all'],
|
|
31
|
+
categories: ['all'],
|
|
32
|
+
collections: ['all'],
|
|
33
|
+
grids: ['all'],
|
|
34
|
+
products: ['all'],
|
|
34
35
|
customers: ['all'],
|
|
35
|
-
|
|
36
|
+
carts: ['all'],
|
|
36
37
|
orders: ['GET', 'POST', 'PATCH'],
|
|
37
|
-
|
|
38
|
-
stores: ['GET'],
|
|
38
|
+
stores: ['GET', 'PATCH'],
|
|
39
39
|
},
|
|
40
40
|
}, apiConfig);
|
|
41
41
|
authenticationId = _id;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from 'zx';
|
|
10
10
|
import login from './login';
|
|
11
11
|
import build from './build';
|
|
12
|
+
import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud';
|
|
12
13
|
|
|
13
14
|
const {
|
|
14
15
|
FIREBASE_PROJECT_ID,
|
|
@@ -40,7 +41,7 @@ if (projectId) {
|
|
|
40
41
|
const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
|
|
41
42
|
projectId = firebaserc.projects.default;
|
|
42
43
|
} catch (e) {
|
|
43
|
-
projectId = 'ecom2-
|
|
44
|
+
projectId = 'ecom2-001';
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -49,13 +50,16 @@ export default async () => {
|
|
|
49
50
|
await fs.copy(path.join(__dirname, '..', 'config'), pwd);
|
|
50
51
|
|
|
51
52
|
const options = Object.keys(argv).reduce((opts, key) => {
|
|
52
|
-
if (key !== '_' && key !==
|
|
53
|
+
if (key !== '_' && argv[key] !== false) {
|
|
53
54
|
// eslint-disable-next-line no-param-reassign
|
|
54
55
|
opts += ` --${key} ${argv[key]}`;
|
|
55
56
|
}
|
|
56
57
|
return opts;
|
|
57
58
|
}, '');
|
|
58
59
|
const $firebase = (cmd: string) => {
|
|
60
|
+
if (cmd === 'deploy') {
|
|
61
|
+
return $`firebase --project=${projectId} ${cmd}${options} --force`;
|
|
62
|
+
}
|
|
59
63
|
return $`firebase --project=${projectId} ${cmd}${options}`;
|
|
60
64
|
};
|
|
61
65
|
|
|
@@ -116,6 +120,16 @@ ECOM_STORE_ID=${storeId}
|
|
|
116
120
|
//
|
|
117
121
|
}
|
|
118
122
|
}
|
|
123
|
+
let serviceAccountJSON : string | null = null;
|
|
124
|
+
if (argv.gcloud !== false) {
|
|
125
|
+
try {
|
|
126
|
+
await siginGcloudAndSetIAM(projectId as string, pwd);
|
|
127
|
+
serviceAccountJSON = await createKeyServiceAccount(projectId as string, pwd);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
//
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
119
133
|
return echo`
|
|
120
134
|
****
|
|
121
135
|
|
|
@@ -125,11 +139,10 @@ Finish by saving the following secrets to your GitHub repository:
|
|
|
125
139
|
|
|
126
140
|
${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
|
|
127
141
|
|
|
128
|
-
${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
|
|
142
|
+
${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = ${chalk.bgMagenta(serviceAccountJSON || '{YOUR_SERVICE_ACCOUNT_JSON}')}
|
|
129
143
|
|
|
130
144
|
-- More info at https://github.com/ecomplus/store#getting-started
|
|
131
145
|
`;
|
|
132
146
|
}
|
|
133
|
-
|
|
134
147
|
return $`echo 'Hello from @cloudcommerce/cli'`;
|
|
135
148
|
};
|
|
@@ -19,8 +19,6 @@ export const onNewOrder = functions.region(region)
|
|
|
19
19
|
logger.warn(`Dropping event ${context.eventId} with age[ms]: ${eventAgeMs}`);
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
// Hide API key for security
|
|
23
|
-
process.env.ECOM_API_KEY = '***';
|
|
24
22
|
const { json } = message;
|
|
25
23
|
logger.info({
|
|
26
24
|
topic: newOrderTopic,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase.js","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AAAA,iDAAiD;AAGjD,OAAO,gCAAgC,CAAC;AACxC,gDAAgD;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,MAAM,MAAM,oCAAoC,CAAC;AAExD,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;AAC7B,aAAa,EAAE,CAAC;AAEhB,MAAM,aAAa,GAAG,KAAK,CAAC;AAC5B,MAAM,aAAa,GAAmB,YAAY,CAAC;AACnD,MAAM,EAAE,oBAAoB,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;AAE1D,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;KAC/C,OAAO,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;KAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9D,IAAI,UAAU,GAAG,aAAa,EAAE;QAC9B,MAAM,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,OAAO,kBAAkB,UAAU,EAAE,CAAC,CAAC;QAC7E,OAAO;KACR;IACD,
|
|
1
|
+
{"version":3,"file":"firebase.js","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AAAA,iDAAiD;AAGjD,OAAO,gCAAgC,CAAC;AACxC,gDAAgD;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,MAAM,MAAM,oCAAoC,CAAC;AAExD,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;AAC7B,aAAa,EAAE,CAAC;AAEhB,MAAM,aAAa,GAAG,KAAK,CAAC;AAC5B,MAAM,aAAa,GAAmB,YAAY,CAAC;AACnD,MAAM,EAAE,oBAAoB,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;AAE1D,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;KAC/C,OAAO,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;KAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9D,IAAI,UAAU,GAAG,aAAa,EAAE;QAC9B,MAAM,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,OAAO,kBAAkB,UAAU,EAAE,CAAC,CAAC;QAC7E,OAAO;KACR;IACD,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,MAAM,CAAC,IAAI,CAAC;QACV,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI;KACL,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|