@vario-software/vario-app-framework-backend 2025.37.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/api/Api.js +449 -0
- package/api/ErpApi.js +94 -0
- package/api/helpers/fetch.js +10 -0
- package/api/helpers/gateway.js +19 -0
- package/api/helpers/getResponseStream.js +17 -0
- package/api/helpers/redirectRequest.js +13 -0
- package/api/helpers/vql.js +61 -0
- package/api/modules/eav.js +83 -0
- package/api/modules/migration.js +95 -0
- package/api/modules/textEnum.js +149 -0
- package/api/modules/webhook.js +44 -0
- package/app.js +115 -0
- package/modules/accessToken.js +43 -0
- package/modules/baseUrlCache.js +53 -0
- package/modules/offlineToken.js +44 -0
- package/package.json +23 -0
- package/setup/appAuthentication.js +45 -0
- package/setup/context.js +37 -0
- package/setup/exception.js +49 -0
- package/utils/context.js +82 -0
- package/utils/httpError.js +16 -0
- package/utils/keycloak.js +57 -0
- package/utils/licenses.js +59 -0
- package/utils/logger.js +29 -0
- package/utils/migrator.js +320 -0
- package/utils/permission.js +34 -0
- package/utils/promiseSingletonMap.js +30 -0
- package/utils/token.js +83 -0
package/setup/context.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { runInContext } = require('#backend/utils/context.js');
|
|
2
|
+
|
|
3
|
+
function setupContext(app)
|
|
4
|
+
{
|
|
5
|
+
return (req, res, next) =>
|
|
6
|
+
{
|
|
7
|
+
// Identifier to this context
|
|
8
|
+
const requestId = `${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 8)}`;
|
|
9
|
+
const startTime = performance.now();
|
|
10
|
+
|
|
11
|
+
res.setHeader('x-request-id', requestId);
|
|
12
|
+
|
|
13
|
+
const specificContext = {
|
|
14
|
+
req,
|
|
15
|
+
res,
|
|
16
|
+
app,
|
|
17
|
+
requestId,
|
|
18
|
+
startTime,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
res.on('finish', async () =>
|
|
22
|
+
{
|
|
23
|
+
await app.log(
|
|
24
|
+
`${(performance.now() - specificContext.startTime).toFixed(2)}ms`,
|
|
25
|
+
'setup/context/finish',
|
|
26
|
+
'DEBUG',
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
runInContext(specificContext, () =>
|
|
31
|
+
{
|
|
32
|
+
next();
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = setupContext;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { getResponse, getApp } = require('#backend/utils/context.js');
|
|
2
|
+
const HttpError = require('#backend/utils/httpError.js');
|
|
3
|
+
|
|
4
|
+
function setupException()
|
|
5
|
+
{
|
|
6
|
+
process.on('unhandledRejection', reason => errorHandling(reason));
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
return (error, req, res, next) =>
|
|
10
|
+
{
|
|
11
|
+
errorHandling(error);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function errorHandling(error)
|
|
16
|
+
{
|
|
17
|
+
const response = getResponse();
|
|
18
|
+
const statusCode = error.statusCode ?? 500;
|
|
19
|
+
const message = error.message ?? 'UNKNOWN_ERROR';
|
|
20
|
+
const logLevel = error.logLevel ?? 'ERROR';
|
|
21
|
+
const logService = error.logService ?? 'setup/exception';
|
|
22
|
+
const stackTrace = error.stack?.split('\n').map(line => line.trim());
|
|
23
|
+
const { logInfo, data } = error;
|
|
24
|
+
|
|
25
|
+
if (error instanceof HttpError)
|
|
26
|
+
{
|
|
27
|
+
await getApp()?.log(
|
|
28
|
+
{
|
|
29
|
+
statusCode,
|
|
30
|
+
message,
|
|
31
|
+
logInfo,
|
|
32
|
+
stackTrace,
|
|
33
|
+
},
|
|
34
|
+
logService,
|
|
35
|
+
logLevel,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
{
|
|
40
|
+
console.warn(error);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (response && !response.headersSent)
|
|
44
|
+
{
|
|
45
|
+
response.status(statusCode).send({ error: message, data }).end();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = setupException;
|
package/utils/context.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { AsyncLocalStorage } = require('async_hooks');
|
|
2
|
+
|
|
3
|
+
const asyncLocalStorage = new AsyncLocalStorage();
|
|
4
|
+
|
|
5
|
+
function runInContext(context, callback)
|
|
6
|
+
{
|
|
7
|
+
asyncLocalStorage.run(context, callback);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getContext()
|
|
11
|
+
{
|
|
12
|
+
return asyncLocalStorage.getStore();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getAccessToken()
|
|
16
|
+
{
|
|
17
|
+
const accessToken = getContext()?.accessToken;
|
|
18
|
+
|
|
19
|
+
return accessToken;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getAppToken()
|
|
23
|
+
{
|
|
24
|
+
const appToken = getContext()?.appToken;
|
|
25
|
+
|
|
26
|
+
return appToken;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getTenant()
|
|
30
|
+
{
|
|
31
|
+
const tenant = getAccessToken()?.tenantSubdomain;
|
|
32
|
+
|
|
33
|
+
return tenant;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getExternalUserId()
|
|
37
|
+
{
|
|
38
|
+
const externalUserId = getAccessToken()?.sub;
|
|
39
|
+
|
|
40
|
+
return externalUserId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getRequest()
|
|
44
|
+
{
|
|
45
|
+
const request = getContext()?.req;
|
|
46
|
+
|
|
47
|
+
return request;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getResponse()
|
|
51
|
+
{
|
|
52
|
+
const response = getContext()?.res;
|
|
53
|
+
|
|
54
|
+
return response;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getApp()
|
|
58
|
+
{
|
|
59
|
+
const app = getContext()?.app;
|
|
60
|
+
|
|
61
|
+
return app;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getRequestId()
|
|
65
|
+
{
|
|
66
|
+
const requestId = getContext()?.requestId;
|
|
67
|
+
|
|
68
|
+
return requestId;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
getContext,
|
|
73
|
+
getAppToken,
|
|
74
|
+
getAccessToken,
|
|
75
|
+
getTenant,
|
|
76
|
+
getExternalUserId,
|
|
77
|
+
getRequest,
|
|
78
|
+
getResponse,
|
|
79
|
+
getApp,
|
|
80
|
+
getRequestId,
|
|
81
|
+
runInContext,
|
|
82
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CustomError extends Error
|
|
2
|
+
{
|
|
3
|
+
constructor(message, statusCode, logService, logInfo, logId, logLevel, errorData)
|
|
4
|
+
{
|
|
5
|
+
super(message);
|
|
6
|
+
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.logLevel = logLevel;
|
|
9
|
+
this.logService = logService;
|
|
10
|
+
this.logId = logId;
|
|
11
|
+
this.logInfo = logInfo;
|
|
12
|
+
this.data = errorData;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = CustomError;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const VarioApi = require('#backend/api/Api.js');
|
|
2
|
+
const { getApp } = require('#backend/utils/context.js');
|
|
3
|
+
|
|
4
|
+
async function refreshAccessToken(offlineToken, refreshUrl)
|
|
5
|
+
{
|
|
6
|
+
const app = getApp();
|
|
7
|
+
|
|
8
|
+
const { clientId, clientSecret, appIdentifier } = app.client;
|
|
9
|
+
|
|
10
|
+
const body = new URLSearchParams({
|
|
11
|
+
grant_type: 'refresh_token',
|
|
12
|
+
refresh_token: offlineToken,
|
|
13
|
+
client_id: clientId,
|
|
14
|
+
client_secret: clientSecret,
|
|
15
|
+
}).toString();
|
|
16
|
+
|
|
17
|
+
const refreshOptions = {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
'user-agent': appIdentifier,
|
|
21
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
22
|
+
},
|
|
23
|
+
body,
|
|
24
|
+
suppressLogs: true,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const timer = performance.now();
|
|
28
|
+
|
|
29
|
+
const { data } = await VarioApi.fetch(refreshUrl, refreshOptions).catch(async error =>
|
|
30
|
+
{
|
|
31
|
+
await app.log(
|
|
32
|
+
{
|
|
33
|
+
request: { refreshUrl, refreshOptions, body },
|
|
34
|
+
response: { ...error?.data },
|
|
35
|
+
duration: `${(performance.now() - timer).toFixed(2)}ms`,
|
|
36
|
+
},
|
|
37
|
+
'utils/keycloak',
|
|
38
|
+
'DEBUG',
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
throw error;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await app.log(
|
|
45
|
+
{
|
|
46
|
+
request: { url: refreshUrl, body: '[secret]' },
|
|
47
|
+
response: `[secret(${Object.keys(typeof data === 'object' ? data : {})})]`,
|
|
48
|
+
duration: `${(performance.now() - timer).toFixed(2)}ms`,
|
|
49
|
+
},
|
|
50
|
+
'utils/keycloak',
|
|
51
|
+
'DEBUG',
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = refreshAccessToken;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const { getApp, getContext } = require('#backend/utils/context.js');
|
|
2
|
+
const HttpError = require('#backend/utils/httpError.js');
|
|
3
|
+
|
|
4
|
+
async function checkLicense(licenseKey, silent)
|
|
5
|
+
{
|
|
6
|
+
const licenses = await getLicenses();
|
|
7
|
+
|
|
8
|
+
if (!licenses.includes(licenseKey))
|
|
9
|
+
{
|
|
10
|
+
if (silent)
|
|
11
|
+
{
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
throw new HttpError(
|
|
16
|
+
'ERP_LICENSE_MISSING',
|
|
17
|
+
402,
|
|
18
|
+
'utils/licenses',
|
|
19
|
+
{ key: licenseKey },
|
|
20
|
+
null,
|
|
21
|
+
'ERROR',
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function checkLicenseMiddleware(licenseKey)
|
|
29
|
+
{
|
|
30
|
+
return async (req, res, next) =>
|
|
31
|
+
{
|
|
32
|
+
await checkLicense(licenseKey);
|
|
33
|
+
|
|
34
|
+
next();
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function getLicenses()
|
|
39
|
+
{
|
|
40
|
+
const context = getContext();
|
|
41
|
+
|
|
42
|
+
if (context.licenses)
|
|
43
|
+
{
|
|
44
|
+
return context.licenses;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const app = getApp();
|
|
48
|
+
|
|
49
|
+
const { data } = await app.erp.fetch('/cmn/systems/licenses/', {
|
|
50
|
+
useInternalApi: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return data.map(({ licenseKey }) => licenseKey);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
checkLicense,
|
|
58
|
+
checkLicenseMiddleware,
|
|
59
|
+
};
|
package/utils/logger.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { getTenant, getRequestId, getRequest } = require('#backend/utils/context.js');
|
|
2
|
+
|
|
3
|
+
async function log(message, loggerName, level = 'DEBUG')
|
|
4
|
+
{
|
|
5
|
+
const tenant = getTenant();
|
|
6
|
+
const requestId = getRequestId();
|
|
7
|
+
|
|
8
|
+
switch (level)
|
|
9
|
+
{
|
|
10
|
+
case 'WARNING':
|
|
11
|
+
console.warn({ tenant, message, requestId, loggerName });
|
|
12
|
+
break;
|
|
13
|
+
case 'ERROR':
|
|
14
|
+
console.error({ tenant, message, requestId, loggerName });
|
|
15
|
+
break;
|
|
16
|
+
case 'INFO':
|
|
17
|
+
console.info({ tenant, message, requestId, loggerName });
|
|
18
|
+
break;
|
|
19
|
+
case 'DEBUG':
|
|
20
|
+
console.debug({ tenant, message, requestId, loggerName, requestPath: getRequest().path });
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
console.log({ tenant, message, requestId, loggerName });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
log,
|
|
29
|
+
};
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const { getApp, getContext, getRequest } = require('#backend/utils/context.js');
|
|
2
|
+
const ErpApi = require('#backend/api/ErpApi.js');
|
|
3
|
+
|
|
4
|
+
const Migrator = class
|
|
5
|
+
{
|
|
6
|
+
migrationResults = {};
|
|
7
|
+
|
|
8
|
+
ApiAdapter = ErpApi;
|
|
9
|
+
|
|
10
|
+
constructor(key)
|
|
11
|
+
{
|
|
12
|
+
this.key = key;
|
|
13
|
+
|
|
14
|
+
this.req = getRequest();
|
|
15
|
+
this.app = getApp();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setMigration = async function (key, callback)
|
|
19
|
+
{
|
|
20
|
+
const migration = `${this.key}.${key}`;
|
|
21
|
+
|
|
22
|
+
if (await this.ApiAdapter.migration.get(migration))
|
|
23
|
+
{
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const context = getContext();
|
|
28
|
+
|
|
29
|
+
context.migration = migration;
|
|
30
|
+
|
|
31
|
+
try
|
|
32
|
+
{
|
|
33
|
+
this.migrationResults[key] = await callback(this.methods, this.migrationResults);
|
|
34
|
+
|
|
35
|
+
let note;
|
|
36
|
+
|
|
37
|
+
try
|
|
38
|
+
{
|
|
39
|
+
note = JSON.stringify(this.migrationResults[key]);
|
|
40
|
+
}
|
|
41
|
+
catch (error)
|
|
42
|
+
{
|
|
43
|
+
note = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await this.ApiAdapter.migration.set(migration, note);
|
|
47
|
+
}
|
|
48
|
+
catch (error)
|
|
49
|
+
{
|
|
50
|
+
await this.methods.log(`Migration "${migration}" failed\n\n${error.message}`, 'ERROR', error.message);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
methods = {
|
|
55
|
+
log: async (message, level = 'INFO') =>
|
|
56
|
+
{
|
|
57
|
+
const context = getContext();
|
|
58
|
+
|
|
59
|
+
await this.app.log(
|
|
60
|
+
message,
|
|
61
|
+
`services/maintenance/install/migrations/${context.migration}`,
|
|
62
|
+
level,
|
|
63
|
+
);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
getEavGroup: async groupKey =>
|
|
67
|
+
{
|
|
68
|
+
const eavGroup = await this.ApiAdapter.eav.getGroup(groupKey);
|
|
69
|
+
|
|
70
|
+
await this.methods.log(`EAV-Group "${eavGroup.label}" with id "${eavGroup.id}" successfully read\n`);
|
|
71
|
+
|
|
72
|
+
return eavGroup;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
createEavGroup: async eavGroup =>
|
|
76
|
+
{
|
|
77
|
+
eavGroup = await this.ApiAdapter.eav.setGroup(eavGroup);
|
|
78
|
+
|
|
79
|
+
await this.methods.log(`EAV-Group "${eavGroup.label}" with id "${eavGroup.id}" successfully created\n`);
|
|
80
|
+
|
|
81
|
+
return eavGroup;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
changeEavGroup: async (groupKey, callback) =>
|
|
85
|
+
{
|
|
86
|
+
const eavGroup = await this.ApiAdapter.eav.changeGroup(groupKey, callback);
|
|
87
|
+
|
|
88
|
+
await this.methods.log(`EAV-Group "${eavGroup.label}" with id "${eavGroup.id}" successfully changed\n`);
|
|
89
|
+
|
|
90
|
+
return eavGroup;
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
deleteEavGroup: async groupKey =>
|
|
94
|
+
{
|
|
95
|
+
const eavGroup = await this.ApiAdapter.eav.deleteGroup(groupKey);
|
|
96
|
+
|
|
97
|
+
await this.methods.log(`EAV-Group "${groupKey}" successfully deleted\n`);
|
|
98
|
+
|
|
99
|
+
return eavGroup;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
createTextEnumGroup: async textEnumGroup =>
|
|
103
|
+
{
|
|
104
|
+
textEnumGroup = await this.ApiAdapter.textenum.setGroup(textEnumGroup);
|
|
105
|
+
|
|
106
|
+
await this.methods.log(`Text-Enum-Group "${textEnumGroup.label}" with id "${textEnumGroup.id}" successfully created\n`);
|
|
107
|
+
|
|
108
|
+
return textEnumGroup;
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
registerWebhook: async (destinationQueue, url) =>
|
|
112
|
+
{
|
|
113
|
+
await this.ApiAdapter.webhook.register(destinationQueue, url);
|
|
114
|
+
|
|
115
|
+
await this.methods.log(`Webhook for destination "${destinationQueue}" registered\n`);
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
deregisterWebhook: async (destinationQueue, url) =>
|
|
119
|
+
{
|
|
120
|
+
await this.ApiAdapter.webhook.deregister(destinationQueue, url);
|
|
121
|
+
|
|
122
|
+
await this.methods.log(`Webhook for destination "${destinationQueue}" deregistered\n`);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
createSalesChannelBackend: async label =>
|
|
126
|
+
{
|
|
127
|
+
const { data: salesChannelBackend } = await this.ApiAdapter.fetch('/erp/sales-channels/backend', {
|
|
128
|
+
method: 'POST',
|
|
129
|
+
body: JSON.stringify({
|
|
130
|
+
appId: this.app.client.appIdentifier,
|
|
131
|
+
label,
|
|
132
|
+
type: 'APP',
|
|
133
|
+
active: true,
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await this.methods.log(`Sales-Channel-Backend with id "${salesChannelBackend.id}" successfully created\n`);
|
|
138
|
+
|
|
139
|
+
return salesChannelBackend;
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
createSalesChannel: async (salesChannelBackend, label, description, channelType = 'ECOMMERCE') =>
|
|
143
|
+
{
|
|
144
|
+
const { data: salesChannel } = await this.ApiAdapter.fetch('/erp/sales-channels', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
body: JSON.stringify({
|
|
147
|
+
label,
|
|
148
|
+
description,
|
|
149
|
+
active: true,
|
|
150
|
+
channelType,
|
|
151
|
+
channelBackend: { id: salesChannelBackend.id },
|
|
152
|
+
externalRef: '',
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await this.methods.log(`Sales-Channel with id "${salesChannel.id}" successfully created\n`);
|
|
157
|
+
|
|
158
|
+
return salesChannel;
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
getSalesChannels: async () =>
|
|
162
|
+
{
|
|
163
|
+
const { data: salesChannels } = await this.ApiAdapter.vql({
|
|
164
|
+
statement: `
|
|
165
|
+
SELECT id,
|
|
166
|
+
label
|
|
167
|
+
FROM sales-channel.salesChannels
|
|
168
|
+
WHERE channelBackend.appId = '${this.app.client.appIdentifier}'
|
|
169
|
+
AND channelBackend.type = 'APP'
|
|
170
|
+
`,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return salesChannels;
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
findSalesChannelBackend: async () =>
|
|
177
|
+
{
|
|
178
|
+
const { data: salesChannelBackends } = await this.ApiAdapter.vql({
|
|
179
|
+
statement: `
|
|
180
|
+
SELECT id
|
|
181
|
+
FROM sales-channel.salesChannelBackends
|
|
182
|
+
WHERE appId = '${this.app.client.appIdentifier}'
|
|
183
|
+
AND type = 'APP'
|
|
184
|
+
`,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return salesChannelBackends?.[0];
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
getSalesChannelBackend: async salesChannelBackendId =>
|
|
191
|
+
{
|
|
192
|
+
const { data: salesChannelBackend } = await this.ApiAdapter.fetch(`/erp/sales-channels/backend/${salesChannelBackendId}`);
|
|
193
|
+
|
|
194
|
+
if (salesChannelBackend)
|
|
195
|
+
{
|
|
196
|
+
await this.methods.log(`Use existing Sales-Channel-Backend with id "${salesChannelBackend.id}"\n`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return salesChannelBackend;
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
activateSalesChannelBackend: async salesChannelBackend =>
|
|
203
|
+
{
|
|
204
|
+
await this.ApiAdapter.fetch(`/erp/sales-channels/backend/${salesChannelBackend.id}/activate`, {
|
|
205
|
+
method: 'PUT',
|
|
206
|
+
body: '{}',
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
createMultipartImportPreset: async importMultipartPresetTemplate =>
|
|
211
|
+
{
|
|
212
|
+
const { data: importMultipartPreset } = await this.ApiAdapter.fetch(
|
|
213
|
+
'/cmn/data-import/runs/multi-part',
|
|
214
|
+
{
|
|
215
|
+
useInternalApi: true,
|
|
216
|
+
method: 'POST',
|
|
217
|
+
body: JSON.stringify(importMultipartPresetTemplate),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
await this.methods.log(`Import-Multipart-Preset with id "${importMultipartPreset.id}" successfully created\n`);
|
|
221
|
+
|
|
222
|
+
return importMultipartPreset;
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
createFinanceBackend: async label =>
|
|
226
|
+
{
|
|
227
|
+
const { data: finance } = await this.ApiAdapter.fetch('/erp/finance/backend', {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
body: JSON.stringify({
|
|
230
|
+
label,
|
|
231
|
+
usePerformanceDate: false,
|
|
232
|
+
appId: this.app.client.appIdentifier,
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await this.methods.log(`Finance Backend with id "${finance.id}" successfully created\n`);
|
|
237
|
+
|
|
238
|
+
return finance;
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
changeFinanceBackend: async (label, description) =>
|
|
242
|
+
{
|
|
243
|
+
const body = {
|
|
244
|
+
adhocPreset: {
|
|
245
|
+
queryPredicate: {
|
|
246
|
+
type: 'JUNCTION',
|
|
247
|
+
operator: 'AND',
|
|
248
|
+
children: [
|
|
249
|
+
{
|
|
250
|
+
type: 'FILTER',
|
|
251
|
+
property: 'label',
|
|
252
|
+
operator: 'EQUALS',
|
|
253
|
+
values: [
|
|
254
|
+
label,
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const { data: financeBackend } = await this.ApiAdapter.fetch(
|
|
263
|
+
'/cmn/computed-queries/finance-export/backends',
|
|
264
|
+
{
|
|
265
|
+
method: 'POST',
|
|
266
|
+
useInternalApi: true,
|
|
267
|
+
body,
|
|
268
|
+
},
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const { data: finance } = await this.ApiAdapter.fetch(`/erp/finance/backend/${financeBackend?.data?.[0].id}`, {
|
|
272
|
+
method: 'PUT',
|
|
273
|
+
body: JSON.stringify({
|
|
274
|
+
label,
|
|
275
|
+
description,
|
|
276
|
+
usePerformanceDate: false,
|
|
277
|
+
appId: this.app.client.appIdentifier,
|
|
278
|
+
}),
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await this.methods.log(`Finance Backend with id "${finance.id}" successfully created\n`);
|
|
282
|
+
|
|
283
|
+
return finance;
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
updateMultipartImportPreset: async (id, importMultipartPresetTemplate) =>
|
|
287
|
+
{
|
|
288
|
+
const { data: importMultipartPreset } = await this.app.erp.fetch(
|
|
289
|
+
`/cmn/data-import/runs/multi-part/${id}`,
|
|
290
|
+
{
|
|
291
|
+
useInternalApi: true,
|
|
292
|
+
method: 'PUT',
|
|
293
|
+
body: JSON.stringify(importMultipartPresetTemplate),
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
await this.methods.log(`Import-Multipart-Preset with id "${importMultipartPreset.id}" successfully updated\n`);
|
|
297
|
+
|
|
298
|
+
return importMultipartPreset;
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
addAppScriptingTrigger: async (triggerId, script) =>
|
|
302
|
+
{
|
|
303
|
+
await this.ApiAdapter.fetch(
|
|
304
|
+
'/community/latest/cmn/system/app-scripting-proxy',
|
|
305
|
+
{
|
|
306
|
+
useInternalApi: true,
|
|
307
|
+
method: 'POST',
|
|
308
|
+
body: JSON.stringify({
|
|
309
|
+
appIdentifier: this.app.client.appIdentifier,
|
|
310
|
+
triggerId,
|
|
311
|
+
script,
|
|
312
|
+
}),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
await this.methods.log(`App-Script-Trigger with id "${triggerId}" successfully updated\n`);
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
module.exports = Migrator;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { getAccessToken } = require('#backend/utils/context.js');
|
|
2
|
+
const HttpError = require('#backend/utils/httpError.js');
|
|
3
|
+
|
|
4
|
+
async function checkPermission(verb)
|
|
5
|
+
{
|
|
6
|
+
const { isSuperUser, permissions } = await getAccessToken();
|
|
7
|
+
|
|
8
|
+
if (!(isSuperUser || permissions?.includes(verb)))
|
|
9
|
+
{
|
|
10
|
+
throw new HttpError(
|
|
11
|
+
'APP_AUTHORIZATION_FAILED',
|
|
12
|
+
403,
|
|
13
|
+
'utils/permission',
|
|
14
|
+
{ missingVerb: verb },
|
|
15
|
+
null,
|
|
16
|
+
'ERROR',
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function checkPermissionMiddleware(verb)
|
|
22
|
+
{
|
|
23
|
+
return async (req, res, next) =>
|
|
24
|
+
{
|
|
25
|
+
await checkPermission(verb);
|
|
26
|
+
|
|
27
|
+
next();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
checkPermission,
|
|
33
|
+
checkPermissionMiddleware,
|
|
34
|
+
};
|