@hestia-earth/api 0.26.0 → 0.26.2
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/dist/esm/aggregations/model/document.js +1 -0
- package/dist/esm/aggregations/model/model.js +36 -0
- package/dist/esm/analyses/model/document.js +1 -0
- package/dist/esm/analyses/model/model.js +16 -0
- package/dist/esm/api-calls/model/model.js +6 -0
- package/dist/esm/cycles/model/model.js +1 -0
- package/dist/esm/db/model.base.js +5 -0
- package/dist/esm/db/mongoose.model.js +1 -0
- package/dist/esm/earth-engine/model/model.js +11 -0
- package/dist/esm/files/model/document.js +1 -0
- package/dist/esm/files/model/model.js +255 -0
- package/dist/esm/glossary/model/model.js +1 -0
- package/dist/esm/migrations/model/model.js +10 -0
- package/dist/esm/models.js +15 -0
- package/dist/esm/nodes/model/model.js +93 -0
- package/dist/esm/reconciliations/model/document.js +1 -0
- package/dist/esm/reconciliations/model/model.js +19 -0
- package/dist/esm/reconciliations/model/validations.js +62 -0
- package/dist/esm/settings/model/model.js +18 -0
- package/dist/esm/url-shortener/model/model.js +10 -0
- package/dist/esm/users/model/document.js +1 -0
- package/dist/esm/users/model/model.js +107 -0
- package/dist/esm/webhooks/model/document.js +1 -0
- package/dist/esm/webhooks/model/model.js +15 -0
- package/dist/esm/ws.model.js +5 -0
- package/dist/users/model/model.d.ts +1 -0
- package/dist/users/model/model.js +2 -3
- package/package.json +11 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isNumber } from '@hestia-earth/utils';
|
|
2
|
+
import { BaseModel } from '../../db/model.base';
|
|
3
|
+
import { filenameWithoutExt } from '../../files/model/model';
|
|
4
|
+
export class Aggregation extends BaseModel {
|
|
5
|
+
folder;
|
|
6
|
+
filename;
|
|
7
|
+
filepath;
|
|
8
|
+
validatedAt;
|
|
9
|
+
status;
|
|
10
|
+
pipelineStatus;
|
|
11
|
+
metadata;
|
|
12
|
+
productId;
|
|
13
|
+
countryId;
|
|
14
|
+
startYear;
|
|
15
|
+
endYear;
|
|
16
|
+
}
|
|
17
|
+
export const defaultAggregationPeriod = 20;
|
|
18
|
+
export const aggregationFolderFromFilename = (filename) => {
|
|
19
|
+
const name = filenameWithoutExt(filename);
|
|
20
|
+
const parts = name.split('-');
|
|
21
|
+
const timestamp = parts.pop();
|
|
22
|
+
return timestamp.length === 8 ? parts.join('-') : name;
|
|
23
|
+
};
|
|
24
|
+
export const parseAggregationValues = (value) => {
|
|
25
|
+
const [productId, ...parts] = aggregationFolderFromFilename(value).split('-');
|
|
26
|
+
const countryId = parts.filter(v => !isNumber(v)).join('-');
|
|
27
|
+
const endYear = +parts.pop();
|
|
28
|
+
const lastPart = parts.pop();
|
|
29
|
+
const startYear = isNumber(lastPart) ? +lastPart : endYear - defaultAggregationPeriod + 1;
|
|
30
|
+
return {
|
|
31
|
+
productId,
|
|
32
|
+
countryId,
|
|
33
|
+
startYear,
|
|
34
|
+
endYear
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
export var AnalysisType;
|
|
3
|
+
(function (AnalysisType) {
|
|
4
|
+
AnalysisType["gapFilling"] = "gap-filling";
|
|
5
|
+
AnalysisType["quantity"] = "quantity";
|
|
6
|
+
AnalysisType["term"] = "term";
|
|
7
|
+
})(AnalysisType || (AnalysisType = {}));
|
|
8
|
+
export class Analysis extends BaseModel {
|
|
9
|
+
cycleId;
|
|
10
|
+
name;
|
|
11
|
+
indicators;
|
|
12
|
+
cycle;
|
|
13
|
+
impactAssessment;
|
|
14
|
+
quantity;
|
|
15
|
+
term;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getPrimaryProduct = (products) => (products || []).find(product => product.primary === true);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export var EarthEngineCallType;
|
|
2
|
+
(function (EarthEngineCallType) {
|
|
3
|
+
EarthEngineCallType["boundary"] = "boundary";
|
|
4
|
+
EarthEngineCallType["coordinates"] = "coordinates";
|
|
5
|
+
EarthEngineCallType["gadm"] = "gadm";
|
|
6
|
+
})(EarthEngineCallType || (EarthEngineCallType = {}));
|
|
7
|
+
export var EarthEngineType;
|
|
8
|
+
(function (EarthEngineType) {
|
|
9
|
+
EarthEngineType["raster"] = "raster";
|
|
10
|
+
EarthEngineType["vector"] = "vector";
|
|
11
|
+
})(EarthEngineType || (EarthEngineType = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
import { hasPermission, isAdmin, isReviewer, UserPermission, UserRole } from '../../users/model/model';
|
|
3
|
+
export const mb = 1048576;
|
|
4
|
+
export const sizeInMb = (size) => Math.round((size / mb) * 1000) / 1000;
|
|
5
|
+
export const maxFileSizeMb = 100;
|
|
6
|
+
export const maxFileSize = maxFileSizeMb * mb;
|
|
7
|
+
export var SupportedExtensions;
|
|
8
|
+
(function (SupportedExtensions) {
|
|
9
|
+
SupportedExtensions["xlsx"] = "xlsx";
|
|
10
|
+
SupportedExtensions["xls"] = "xls";
|
|
11
|
+
SupportedExtensions["csv"] = "csv";
|
|
12
|
+
SupportedExtensions["json"] = "json";
|
|
13
|
+
SupportedExtensions["draft"] = "txt";
|
|
14
|
+
SupportedExtensions["pdf"] = "pdf";
|
|
15
|
+
})(SupportedExtensions || (SupportedExtensions = {}));
|
|
16
|
+
const maxFileSizeExt = {
|
|
17
|
+
[SupportedExtensions.csv]: maxFileSize,
|
|
18
|
+
[SupportedExtensions.xlsx]: maxFileSize / 2,
|
|
19
|
+
[SupportedExtensions.xls]: maxFileSize / 2,
|
|
20
|
+
[SupportedExtensions.draft]: maxFileSize,
|
|
21
|
+
[SupportedExtensions.json]: maxFileSize,
|
|
22
|
+
[SupportedExtensions.pdf]: maxFileSize / 2
|
|
23
|
+
};
|
|
24
|
+
export const maxFileSizeByFile = (filename) => maxFileSizeExt[fileExt(filename).replace('.', '')];
|
|
25
|
+
export const finalFormatExtensions = [SupportedExtensions.json, SupportedExtensions.csv];
|
|
26
|
+
export var HestiaExtensions;
|
|
27
|
+
(function (HestiaExtensions) {
|
|
28
|
+
HestiaExtensions["nodes"] = "hestia";
|
|
29
|
+
HestiaExtensions["progress"] = "progress";
|
|
30
|
+
HestiaExtensions["log"] = "log";
|
|
31
|
+
HestiaExtensions["jsonLog"] = "jlog";
|
|
32
|
+
HestiaExtensions["error"] = "err";
|
|
33
|
+
HestiaExtensions["json"] = "json";
|
|
34
|
+
HestiaExtensions["jsonld"] = "jsonld";
|
|
35
|
+
HestiaExtensions["contributions"] = "contributions";
|
|
36
|
+
})(HestiaExtensions || (HestiaExtensions = {}));
|
|
37
|
+
export var FileFindFields;
|
|
38
|
+
(function (FileFindFields) {
|
|
39
|
+
FileFindFields["sources"] = "sources";
|
|
40
|
+
FileFindFields["cycles"] = "nbCycles";
|
|
41
|
+
FileFindFields["impactAssessments"] = "nbImpactAssessments";
|
|
42
|
+
FileFindFields["users"] = "user";
|
|
43
|
+
FileFindFields["hestiaData"] = "hestiaDataPath";
|
|
44
|
+
})(FileFindFields || (FileFindFields = {}));
|
|
45
|
+
export var FileProgress;
|
|
46
|
+
(function (FileProgress) {
|
|
47
|
+
FileProgress["convertExcel"] = "convertExcel";
|
|
48
|
+
FileProgress["convertCsv"] = "convertCsv";
|
|
49
|
+
FileProgress["convertJson"] = "convertJson";
|
|
50
|
+
FileProgress["checkExisting"] = "checkExisting";
|
|
51
|
+
FileProgress["extendBibliography"] = "extendBibliography";
|
|
52
|
+
FileProgress["addMetadata"] = "addMetadata";
|
|
53
|
+
FileProgress["validateHestia"] = "validateHestia";
|
|
54
|
+
FileProgress["validateData"] = "validateData";
|
|
55
|
+
FileProgress["copyHestia"] = "copyHestia";
|
|
56
|
+
FileProgress["processJson"] = "processJson";
|
|
57
|
+
FileProgress["indexJson"] = "indexJson";
|
|
58
|
+
})(FileProgress || (FileProgress = {}));
|
|
59
|
+
export var FileStatus;
|
|
60
|
+
(function (FileStatus) {
|
|
61
|
+
FileStatus["convertExcelDone"] = "convertExcelDone";
|
|
62
|
+
FileStatus["convertCsvDone"] = "convertCsvDone";
|
|
63
|
+
FileStatus["convertJsonDone"] = "convertJsonDone";
|
|
64
|
+
FileStatus["checkExistingDone"] = "checkExistingDone";
|
|
65
|
+
FileStatus["extendBibliographyDone"] = "extendBibliographyDone";
|
|
66
|
+
FileStatus["addMetadataDone"] = "addMetadataDone";
|
|
67
|
+
FileStatus["validateHestiaDone"] = "validateHestiaDone";
|
|
68
|
+
FileStatus["validateDataDone"] = "validateDataDone";
|
|
69
|
+
FileStatus["copyHestiaDone"] = "copyHestiaDone";
|
|
70
|
+
FileStatus["processJsonDone"] = "processJsonDone";
|
|
71
|
+
FileStatus["indexJsonDone"] = "indexJsonDone";
|
|
72
|
+
})(FileStatus || (FileStatus = {}));
|
|
73
|
+
export var FileError;
|
|
74
|
+
(function (FileError) {
|
|
75
|
+
FileError["convertExcelError"] = "convertExcelError";
|
|
76
|
+
FileError["convertCsvError"] = "convertCsvError";
|
|
77
|
+
FileError["convertJsonError"] = "convertJsonError";
|
|
78
|
+
FileError["checkExistingError"] = "checkExistingError";
|
|
79
|
+
FileError["extendBibliographyError"] = "extendBibliographyError";
|
|
80
|
+
FileError["addMetadataError"] = "addMetadataError";
|
|
81
|
+
FileError["validateHestiaError"] = "validateHestiaError";
|
|
82
|
+
FileError["validateDataError"] = "validateDataError";
|
|
83
|
+
FileError["copyHestiaError"] = "copyHestiaError";
|
|
84
|
+
FileError["processJsonError"] = "processJsonError";
|
|
85
|
+
FileError["indexJsonError"] = "indexJsonError";
|
|
86
|
+
})(FileError || (FileError = {}));
|
|
87
|
+
export var FilePipelineStatus;
|
|
88
|
+
(function (FilePipelineStatus) {
|
|
89
|
+
FilePipelineStatus["indexEngineDone"] = "indexEngineDone";
|
|
90
|
+
FilePipelineStatus["calculationEngineDone"] = "calculationEngineDone";
|
|
91
|
+
})(FilePipelineStatus || (FilePipelineStatus = {}));
|
|
92
|
+
export var FilePipelineProgress;
|
|
93
|
+
(function (FilePipelineProgress) {
|
|
94
|
+
FilePipelineProgress["indexEngine"] = "indexEngine";
|
|
95
|
+
FilePipelineProgress["calculationEngine"] = "calculationEngine";
|
|
96
|
+
})(FilePipelineProgress || (FilePipelineProgress = {}));
|
|
97
|
+
export var FilePipelineError;
|
|
98
|
+
(function (FilePipelineError) {
|
|
99
|
+
FilePipelineError["indexEngineError"] = "indexEngineError";
|
|
100
|
+
FilePipelineError["calculationEngineError"] = "calculationEngineError";
|
|
101
|
+
})(FilePipelineError || (FilePipelineError = {}));
|
|
102
|
+
export var FileValidationStatus;
|
|
103
|
+
(function (FileValidationStatus) {
|
|
104
|
+
FileValidationStatus["success"] = "success";
|
|
105
|
+
FileValidationStatus["error"] = "error";
|
|
106
|
+
})(FileValidationStatus || (FileValidationStatus = {}));
|
|
107
|
+
export class File extends BaseModel {
|
|
108
|
+
filename;
|
|
109
|
+
filepath;
|
|
110
|
+
folder;
|
|
111
|
+
user;
|
|
112
|
+
assignedUsers;
|
|
113
|
+
authorizedUsers;
|
|
114
|
+
contentType;
|
|
115
|
+
archived;
|
|
116
|
+
status;
|
|
117
|
+
pipelineStatus;
|
|
118
|
+
validationStatus;
|
|
119
|
+
userValidatedAt;
|
|
120
|
+
validatedUser;
|
|
121
|
+
validatedAt;
|
|
122
|
+
schemaVersion;
|
|
123
|
+
schemaOutdated;
|
|
124
|
+
glossaryOutdated;
|
|
125
|
+
comments;
|
|
126
|
+
todos;
|
|
127
|
+
metadata;
|
|
128
|
+
isPrivate;
|
|
129
|
+
skipValidation;
|
|
130
|
+
study;
|
|
131
|
+
fromDraft;
|
|
132
|
+
deleted;
|
|
133
|
+
isOwner;
|
|
134
|
+
isAuthorized;
|
|
135
|
+
isAssignedToMe;
|
|
136
|
+
isValidated;
|
|
137
|
+
isDraft;
|
|
138
|
+
originalPath;
|
|
139
|
+
hestiaPath;
|
|
140
|
+
progressPath;
|
|
141
|
+
studyPath;
|
|
142
|
+
dataPath;
|
|
143
|
+
dataProgressPath;
|
|
144
|
+
dataCsvPath;
|
|
145
|
+
dataRecalculatedCsvPath;
|
|
146
|
+
dataRecalculatedStatusPath;
|
|
147
|
+
logPath;
|
|
148
|
+
errorPath;
|
|
149
|
+
sources;
|
|
150
|
+
nbCycles;
|
|
151
|
+
nbImpactAssessments;
|
|
152
|
+
hestiaDataPath;
|
|
153
|
+
}
|
|
154
|
+
const fileNoExtSearch = (key, ...parts) => {
|
|
155
|
+
const [filepathNoExt] = parts.filter(Boolean).join('/').split('.');
|
|
156
|
+
return {
|
|
157
|
+
[key]: {
|
|
158
|
+
$in: Object.values(SupportedExtensions).map(ext => `${filepathNoExt}.${ext}`)
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
export const filenameSearch = (...parts) => (parts?.length ? fileNoExtSearch('filename', ...parts) : {});
|
|
163
|
+
export const filepathSearch = (...parts) => (parts?.length ? fileNoExtSearch('filepath', ...parts) : {});
|
|
164
|
+
export const fileExt = (path) => {
|
|
165
|
+
const paths = path?.split('/')?.pop()?.split('.');
|
|
166
|
+
return paths.length > 1 ? paths.pop() : null;
|
|
167
|
+
};
|
|
168
|
+
export const isSupportedExt = (path) => Object.values(SupportedExtensions).includes(fileExt(path));
|
|
169
|
+
export const fileToExt = (path, extension = '') => [
|
|
170
|
+
path
|
|
171
|
+
.replace(`.${fileExt(path)}`, '')
|
|
172
|
+
.replace(/^\./g, '')
|
|
173
|
+
.replace(/\.$/g, ''),
|
|
174
|
+
(extension || '').replace(/[.]/g, '')
|
|
175
|
+
]
|
|
176
|
+
.filter(Boolean)
|
|
177
|
+
.join('.');
|
|
178
|
+
export const filenameWithoutExt = (filepath = '') => {
|
|
179
|
+
const filename = filenameFromPath(filepath);
|
|
180
|
+
const file = fileToExt(filename, '');
|
|
181
|
+
return file.endsWith('.') ? file.substring(0, file.length - 1) : file;
|
|
182
|
+
};
|
|
183
|
+
export const validPathChars = 'A-Za-z\\d\\-_';
|
|
184
|
+
const rstripChar = (value) => (value.length > 1 ? value.replace(/(\.|\_)$/g, '') : value);
|
|
185
|
+
export const replaceInvalidChars = (value) => {
|
|
186
|
+
const folder = folderFromPath(value);
|
|
187
|
+
const newFilename = value
|
|
188
|
+
? rstripChar(rstripChar(filenameWithoutExt(value))
|
|
189
|
+
.replace(new RegExp(`[^${validPathChars}]`, 'g'), '_')
|
|
190
|
+
.replace(new RegExp(Object.values(SupportedExtensions)
|
|
191
|
+
.map(v => `(\_${v})`)
|
|
192
|
+
.join('|'), 'g'), '')
|
|
193
|
+
.replace(/[\_]{2,}/g, '_'))
|
|
194
|
+
: null;
|
|
195
|
+
return newFilename
|
|
196
|
+
? value?.includes('.')
|
|
197
|
+
? [normalizeFolder(folder), fileToExt(newFilename, fileExt(value))].filter(Boolean).join('/')
|
|
198
|
+
: newFilename
|
|
199
|
+
: value;
|
|
200
|
+
};
|
|
201
|
+
export const canUseFolder = (value) => !!value && !isFolderUpload(value.toLowerCase());
|
|
202
|
+
export const canUploadFolderFile = (value) => !!value && isSupportedExt(value) && isFolderUpload(value);
|
|
203
|
+
export const isFilenameValid = (filename) => !!filename && filename.split('.').filter(Boolean).length > 1 && isSupportedExt(filename);
|
|
204
|
+
export const isFilepathValid = (filepath) => !!filepath && [isSupportedExt(filepath), canUseFolder(filepath)].every(Boolean);
|
|
205
|
+
export const normalizeFolder = (folder) => folder.replace(new RegExp(`[^${validPathChars}]`, 'g'), '_').replace(/[\_]{2,}/g, '_');
|
|
206
|
+
export const folderFromPath = (path) => (path?.includes('.') ? path.split('/').slice(0, -1).join('/') : path);
|
|
207
|
+
export const rootFolderFromPath = (path) => path.split('/')[0];
|
|
208
|
+
export const filenameFromPath = (path) => path.split('/').pop();
|
|
209
|
+
export const analysesFolder = 'analyses';
|
|
210
|
+
export const glossaryFolder = 'glossary';
|
|
211
|
+
export const termFolder = 'term';
|
|
212
|
+
export const reconciliationFolder = 'reconciliation';
|
|
213
|
+
export const isAnalysis = (path) => rootFolderFromPath(path) === analysesFolder;
|
|
214
|
+
export const isReconciliation = (path) => rootFolderFromPath(path) === reconciliationFolder;
|
|
215
|
+
export const hasReconciliationAccess = (file, user) => 'idRecalculated' in file && hasPermission(UserPermission.reconciliationsRead, user);
|
|
216
|
+
export const isGlossary = (path) => rootFolderFromPath(path) === glossaryFolder;
|
|
217
|
+
export const isTerm = (path) => rootFolderFromPath(path) === termFolder;
|
|
218
|
+
export const aggregationFolder = 'aggregation';
|
|
219
|
+
export const isAggregation = (path) => rootFolderFromPath(path) === aggregationFolder;
|
|
220
|
+
export const isAdminFolder = (path) => !!path && [isTerm, isAnalysis, isAggregation, isReconciliation].some(f => f(path));
|
|
221
|
+
export const isFolderUpload = (path, termsOnly = false) => [isGlossary, isTerm, ...(termsOnly ? [] : [isAggregation, isReconciliation])].some(f => f(path));
|
|
222
|
+
const asString = (v) => (typeof v === 'object' ? v?._id?.toString() || v?.id?.toString() : v?.toString());
|
|
223
|
+
export const userFolder = (user) => asString(user);
|
|
224
|
+
export const isOwner = (file, user) => asString(file?.user) === asString(user);
|
|
225
|
+
export const isAuthorized = ({ authorizedUsers }, user) => (authorizedUsers || []).map(asString).includes(asString(user));
|
|
226
|
+
export const isAssigned = ({ assignedUsers }, user) => (assignedUsers || []).map(asString).includes(asString(user));
|
|
227
|
+
export const isLocked = ({ status, pipelineStatus }) => ![FileStatus.validateDataDone, ...Object.values(FileError)].includes(status) &&
|
|
228
|
+
(status !== FileStatus.indexJsonDone ||
|
|
229
|
+
![FilePipelineStatus.calculationEngineDone, FilePipelineError.calculationEngineError].includes(pipelineStatus));
|
|
230
|
+
export const canForceRemove = (file, user, forceDelete) => (isAdmin(user) && forceDelete === true) || !isLocked(file);
|
|
231
|
+
export const canRemove = (file, user) => isAdmin(user) || !isValidated(file) || file.isPrivate;
|
|
232
|
+
const validateStatuses = [FileStatus.validateDataDone, FileStatus.indexJsonDone, FileError.indexJsonError];
|
|
233
|
+
export const validatedStatuses = [FileStatus.copyHestiaDone, FileStatus.processJsonDone, FileStatus.indexJsonDone];
|
|
234
|
+
export const canValidate = ({ status, isPrivate, archived }, user) => !archived && validateStatuses.includes(status) && (isPrivate || isReviewer(user));
|
|
235
|
+
export const isValidated = ({ validatedAt, status }) => !!validatedAt || validatedStatuses.includes(status);
|
|
236
|
+
const submitStatuses = [FileStatus.validateDataDone];
|
|
237
|
+
export const canSubmit = (file, user) => !file.archived &&
|
|
238
|
+
submitStatuses.includes(file.status) &&
|
|
239
|
+
!file.userValidatedAt &&
|
|
240
|
+
(isOwner(file, user) || isAuthorized(file, user));
|
|
241
|
+
export const isDraft = ({ filepath, filename }) => (filepath || filename || '').endsWith(SupportedExtensions.draft);
|
|
242
|
+
export const canEditComment = (comment, user) => asString(comment?.user) === asString(user);
|
|
243
|
+
export const canCommitHestiaData = (file, user) => !file.archived && isValidated(file) && (isReviewer(user) || user?.canCommitHestiaData);
|
|
244
|
+
const grantAccessByRole = {
|
|
245
|
+
[UserRole.Admin]: () => true,
|
|
246
|
+
[UserRole.Reviewer]: (file, user) => !file.isPrivate || isAssigned(file, user),
|
|
247
|
+
[UserRole.Developer]: () => false,
|
|
248
|
+
[UserRole.Researcher]: () => false
|
|
249
|
+
};
|
|
250
|
+
export const hasAccess = (file, user, allowedRoles) => [
|
|
251
|
+
isAdmin(user),
|
|
252
|
+
hasReconciliationAccess(file, user),
|
|
253
|
+
(!allowedRoles.length || allowedRoles.includes(user.role)) &&
|
|
254
|
+
(isAuthorized(file, user) || grantAccessByRole[user.role]?.(file, user))
|
|
255
|
+
].some(Boolean);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
export var MigrationType;
|
|
3
|
+
(function (MigrationType) {
|
|
4
|
+
MigrationType["glossary"] = "glossary";
|
|
5
|
+
MigrationType["schema"] = "schema";
|
|
6
|
+
})(MigrationType || (MigrationType = {}));
|
|
7
|
+
export class Migration extends BaseModel {
|
|
8
|
+
filenames;
|
|
9
|
+
type;
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './api-calls/model/model';
|
|
2
|
+
export * from './aggregations/model/model';
|
|
3
|
+
export * from './analyses/model/model';
|
|
4
|
+
export * from './cycles/model/model';
|
|
5
|
+
export * from './earth-engine/model/model';
|
|
6
|
+
export * from './files/model/model';
|
|
7
|
+
export * from './glossary/model/model';
|
|
8
|
+
export * from './migrations/model/model';
|
|
9
|
+
export * from './nodes/model/model';
|
|
10
|
+
export * from './reconciliations/model/model';
|
|
11
|
+
export * from './settings/model/model';
|
|
12
|
+
export * from './url-shortener/model/model';
|
|
13
|
+
export * from './users/model/model';
|
|
14
|
+
export * from './webhooks/model/model';
|
|
15
|
+
export * from './ws.model';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SchemaType, NodeType, TermTermType, jsonldPath, isTypeNode, isExpandable } from '@hestia-earth/schema';
|
|
2
|
+
import { dayMs, reduceUndefinedValues, unique } from '@hestia-earth/utils';
|
|
3
|
+
import { fileToExt, SupportedExtensions } from '../../files/model/model';
|
|
4
|
+
import { hasPermission, UserPermission } from '../../users/model/model';
|
|
5
|
+
export const blankNodeTypes = Object.values(SchemaType).filter(t => !isTypeNode(t));
|
|
6
|
+
export var DataState;
|
|
7
|
+
(function (DataState) {
|
|
8
|
+
DataState["original"] = "original";
|
|
9
|
+
DataState["recalculated"] = "recalculated";
|
|
10
|
+
})(DataState || (DataState = {}));
|
|
11
|
+
export const dataStatesTypeMapping = {
|
|
12
|
+
[DataState.original]: Object.values(NodeType),
|
|
13
|
+
[DataState.recalculated]: [NodeType.Cycle, NodeType.ImpactAssessment, NodeType.Site]
|
|
14
|
+
};
|
|
15
|
+
export const allowedDataStates = (type) => Object.values(DataState).filter(dataState => dataStatesTypeMapping[dataState].includes(type));
|
|
16
|
+
export const pathWithState = (type, id, dataState = DataState.original, strictDataState = false) => {
|
|
17
|
+
const state = dataStatesTypeMapping[dataState].includes(type) ? dataState : null;
|
|
18
|
+
return state !== null || !strictDataState
|
|
19
|
+
? [state === DataState.original ? null : state, jsonldPath(type, id)].filter(Boolean).join('/')
|
|
20
|
+
: null;
|
|
21
|
+
};
|
|
22
|
+
export const nodeTypeToParam = (type) => `${(type || '').toLowerCase()}s`;
|
|
23
|
+
export const paramToNodeType = (type) => Object.values(NodeType).find(v => nodeTypeToParam(v) === type);
|
|
24
|
+
const csvValue = (value) => (value || '').replace('[', '').replace(']', '');
|
|
25
|
+
const parseMessage = (message) => {
|
|
26
|
+
try {
|
|
27
|
+
const data = JSON.parse(message);
|
|
28
|
+
return data.message.split(',').reduce((prev, parts) => {
|
|
29
|
+
const [key, value] = parts.split('=');
|
|
30
|
+
const val = csvValue(value);
|
|
31
|
+
return {
|
|
32
|
+
...prev,
|
|
33
|
+
...(key && val ? { [key.trim()]: val } : {})
|
|
34
|
+
};
|
|
35
|
+
}, { logger: data.logger });
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const termTypes = Object.values(TermTermType);
|
|
42
|
+
const parseFilename = (filepath) => {
|
|
43
|
+
const [filename] = filepath.split('.');
|
|
44
|
+
const ext = termTypes.includes(filename) ? SupportedExtensions.xlsx : SupportedExtensions.csv;
|
|
45
|
+
return fileToExt(filename, ext);
|
|
46
|
+
};
|
|
47
|
+
const missingLookupPrefix = 'Missing lookup';
|
|
48
|
+
const parseLookup = ({ column, termid, [missingLookupPrefix]: missingLookup }) => ({
|
|
49
|
+
filename: parseFilename(missingLookup),
|
|
50
|
+
termId: termid,
|
|
51
|
+
column
|
|
52
|
+
});
|
|
53
|
+
export const parseLogMissingLookups = (data) => {
|
|
54
|
+
const lines = data.split('\n').filter(log => log.includes(missingLookupPrefix));
|
|
55
|
+
const messages = lines.map(parseMessage).filter(v => Object.keys(v).length > 1);
|
|
56
|
+
return unique(messages.map(parseLookup));
|
|
57
|
+
};
|
|
58
|
+
const mapTypeToId = (nodes) => nodes.reduce((prev, { '@type': type, '@id': id }) => {
|
|
59
|
+
prev[type] = prev[type] || [];
|
|
60
|
+
prev[type].push(id);
|
|
61
|
+
return prev;
|
|
62
|
+
}, {});
|
|
63
|
+
export const formatForUpload = (nodes, typeToId = mapTypeToId(nodes)) => nodes.map(({ '@type': type, '@id': id, ...node }) => type === NodeType.Term
|
|
64
|
+
? { '@type': type, '@id': id }
|
|
65
|
+
: reduceUndefinedValues({
|
|
66
|
+
...(!id || (typeToId[type] ?? []).includes(id) ? { type, id } : { '@type': type, '@id': id }),
|
|
67
|
+
...Object.fromEntries(Object.entries(node).map(([key, value]) => {
|
|
68
|
+
const newValue = isExpandable(value)
|
|
69
|
+
? Array.isArray(value)
|
|
70
|
+
? formatForUpload(value, typeToId)
|
|
71
|
+
: formatForUpload([value], typeToId)[0]
|
|
72
|
+
: value;
|
|
73
|
+
return [key, newValue];
|
|
74
|
+
}))
|
|
75
|
+
}, true));
|
|
76
|
+
export const setPrivate = ({ source, defaultSource, ...node }) => ({
|
|
77
|
+
...node,
|
|
78
|
+
dataPrivate: true
|
|
79
|
+
});
|
|
80
|
+
export const dataVersionRestrictedDays = 182;
|
|
81
|
+
export const isDataVersionRestricted = (dataVersion) => (new Date().getTime() - new Date(dataVersion).getTime()) / dayMs < dataVersionRestrictedDays;
|
|
82
|
+
export const isDataVersionAuthorised = (user, dataVersion) => dataVersion
|
|
83
|
+
? isDataVersionRestricted(dataVersion)
|
|
84
|
+
?
|
|
85
|
+
hasPermission(UserPermission.aggregationsLatest, user)
|
|
86
|
+
: true
|
|
87
|
+
:
|
|
88
|
+
hasPermission(UserPermission.aggregationsPreview, user);
|
|
89
|
+
export const isNodeAuthorised = (user, node, dataVersion) => !node.aggregated ||
|
|
90
|
+
[
|
|
91
|
+
hasPermission(UserPermission.aggregationsRead, user),
|
|
92
|
+
node.aggregatedDataValidated && isDataVersionAuthorised(user, dataVersion)
|
|
93
|
+
].some(Boolean);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
export { getMainErrorMessage as reconciliationsGetMainErrorMessage, validateProductCorrespondence as reconciliationsValidateProductCorrespondence, validateImpactAssessmentLinks as reconciliationsValidateImpactAssessmentLinks, validateExpectedNodes as reconciliationsValidateExpectedNodes, validatePrivate as reconciliationsValidatePrivate } from './validations';
|
|
3
|
+
export var ReconciliationLevel;
|
|
4
|
+
(function (ReconciliationLevel) {
|
|
5
|
+
ReconciliationLevel["success"] = "success";
|
|
6
|
+
ReconciliationLevel["warning"] = "warning";
|
|
7
|
+
ReconciliationLevel["danger"] = "danger";
|
|
8
|
+
})(ReconciliationLevel || (ReconciliationLevel = {}));
|
|
9
|
+
export class Reconciliation extends BaseModel {
|
|
10
|
+
idExpected;
|
|
11
|
+
idRecalculated;
|
|
12
|
+
dataPrivate;
|
|
13
|
+
name;
|
|
14
|
+
level;
|
|
15
|
+
details;
|
|
16
|
+
error;
|
|
17
|
+
uploadStatus;
|
|
18
|
+
uploadPipelineStatus;
|
|
19
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { NodeType } from '@hestia-earth/schema';
|
|
2
|
+
export const notPrivateError = 'expected-not-private';
|
|
3
|
+
export const EXTRANEOUS = 'extraneous';
|
|
4
|
+
const isExtraneousError = (error) => (typeof error === 'string' ? error : error?.message)?.includes(EXTRANEOUS);
|
|
5
|
+
const isNotPrivateError = (error) => (typeof error === 'string' ? error : error?.message) === notPrivateError;
|
|
6
|
+
const getType = (node) => node?.['@type'] || node?.type;
|
|
7
|
+
const getId = (node) => node?.['@id'] || node?.id;
|
|
8
|
+
const filterByType = (nodeType) => (node) => getType(node) === nodeType;
|
|
9
|
+
const getErrorsFromValidationsObj = validations => Object.entries(validations)
|
|
10
|
+
.filter(([_errorMsg, validationFailed]) => !!validationFailed)
|
|
11
|
+
.map(([errorMsg]) => errorMsg);
|
|
12
|
+
export const validateExpectedNodes = (nodes) => {
|
|
13
|
+
const cycles = nodes.filter(node => getType(node) === NodeType.Cycle);
|
|
14
|
+
const sites = nodes.filter(node => getType(node) === NodeType.Site);
|
|
15
|
+
const impactAssessments = nodes.filter(node => getType(node) === NodeType.ImpactAssessment);
|
|
16
|
+
const cycleId = getId(cycles?.[0]);
|
|
17
|
+
const cycleSiteId = getId(cycles?.[0]?.site);
|
|
18
|
+
const siteId = getId(sites?.[0]);
|
|
19
|
+
return getErrorsFromValidationsObj({
|
|
20
|
+
['More than one Cycle found in expected nodes']: cycles.length > 1,
|
|
21
|
+
['No Cycle found in expected nodes']: cycles.length < 1,
|
|
22
|
+
['Cycle missing name field in expected nodes']: cycles.length && !cycles[0].name,
|
|
23
|
+
['More than one Site found in expected nodes']: sites.length > 1,
|
|
24
|
+
[`Cycle ${cycleId} is not linked to Site ${siteId} in expected nodes`]: cycleSiteId !== siteId,
|
|
25
|
+
...impactAssessments.reduce((acc, ia) => {
|
|
26
|
+
acc[`ImpactAssessment ${getId(ia)} is not linked to Cycle ${cycleId} in expected nodes`] =
|
|
27
|
+
getId(ia?.cycle) !== cycleId;
|
|
28
|
+
return acc;
|
|
29
|
+
}, {})
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const matchedProduct = (impacts) => (product) => impacts.filter(ia => getId(product.term) === getId(ia.product.term)).length > 1;
|
|
33
|
+
export const validateImpactAssessmentLinks = (nodes) => {
|
|
34
|
+
const impactAssessments = nodes.filter(filterByType(NodeType.ImpactAssessment));
|
|
35
|
+
const cycle = nodes.find(filterByType(NodeType.Cycle));
|
|
36
|
+
const cycleId = getId(cycle);
|
|
37
|
+
return getErrorsFromValidationsObj({
|
|
38
|
+
[`Cycle ${cycleId} has no associated impact assessment`]: !impactAssessments.length,
|
|
39
|
+
[`Cycle ${cycleId} has no products`]: !cycle.products?.length,
|
|
40
|
+
[`Cycle ${cycleId} has a product with more than one linked impact assessment`]: cycle.products?.some(matchedProduct(impactAssessments))
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
export const validatePrivate = (cycle) => getErrorsFromValidationsObj({ [notPrivateError]: !cycle.dataPrivate });
|
|
44
|
+
export const validateProductCorrespondence = (expectedProducts, recalculatedProducts, idRecalculated) => {
|
|
45
|
+
const missingProducts = expectedProducts.filter(pExpected => !recalculatedProducts.some(pRecalculated => getId(pRecalculated) === getId(pExpected)));
|
|
46
|
+
const extraneousProducts = recalculatedProducts.filter(pRecalculated => !expectedProducts.some(pExpected => getId(pRecalculated) === getId(pExpected)));
|
|
47
|
+
return [
|
|
48
|
+
[missingProducts, 'missing'],
|
|
49
|
+
[extraneousProducts, EXTRANEOUS]
|
|
50
|
+
]
|
|
51
|
+
.map(([products, errorType]) => products.length
|
|
52
|
+
? `Cycle ${idRecalculated} has ${errorType} impact assessment for products: ${products
|
|
53
|
+
.map(p => p['@id'])
|
|
54
|
+
.join(', ')}`
|
|
55
|
+
: null)
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
};
|
|
58
|
+
export const getMainErrorMessage = errors => errors?.length === 1 && isExtraneousError(errors[0])
|
|
59
|
+
? 'recalculation-error'
|
|
60
|
+
: errors.some(isNotPrivateError)
|
|
61
|
+
? notPrivateError
|
|
62
|
+
: 'invalid-nodes';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
export const cacheKey = 'settings';
|
|
3
|
+
export var SettingKey;
|
|
4
|
+
(function (SettingKey) {
|
|
5
|
+
SettingKey["maintenanceEnabled"] = "maintenanceEnabled";
|
|
6
|
+
SettingKey["readonlyEnabled"] = "readonlyEnabled";
|
|
7
|
+
SettingKey["privateUploadsEnabled"] = "privateUploadsEnabled";
|
|
8
|
+
SettingKey["publicUploadsEnabled"] = "publicUploadsEnabled";
|
|
9
|
+
SettingKey["aggregationEngine"] = "aggregationEngine";
|
|
10
|
+
SettingKey["calculationEngine"] = "calculationEngine";
|
|
11
|
+
SettingKey["users"] = "users";
|
|
12
|
+
SettingKey["dataReleases"] = "dataReleases";
|
|
13
|
+
})(SettingKey || (SettingKey = {}));
|
|
14
|
+
export class Setting extends BaseModel {
|
|
15
|
+
key;
|
|
16
|
+
value;
|
|
17
|
+
metadata;
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseModel } from '../../db/model.base';
|
|
2
|
+
export class UrlShortener extends BaseModel {
|
|
3
|
+
shortId;
|
|
4
|
+
path;
|
|
5
|
+
count;
|
|
6
|
+
}
|
|
7
|
+
export const whitelistedQueryParams = {
|
|
8
|
+
'/explorer': ['sortBy', 'sortOrder', 'page', 'dataVersion', 'type', 'filters']
|
|
9
|
+
};
|
|
10
|
+
export const isShortPathAllowed = (path) => path.split('?')[0] in whitelistedQueryParams;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { NodeType } from '@hestia-earth/schema';
|
|
2
|
+
import { dayMs } from '@hestia-earth/utils';
|
|
3
|
+
import { BaseModel } from '../../db/model.base';
|
|
4
|
+
export const defaultMaxApiCalls = 100;
|
|
5
|
+
export const userPermissionRequestTimeout = 7 * dayMs;
|
|
6
|
+
export var MaxUploads;
|
|
7
|
+
(function (MaxUploads) {
|
|
8
|
+
MaxUploads[MaxUploads["New"] = 1] = "New";
|
|
9
|
+
MaxUploads[MaxUploads["Confirmed"] = 10] = "Confirmed";
|
|
10
|
+
})(MaxUploads || (MaxUploads = {}));
|
|
11
|
+
export var UserRole;
|
|
12
|
+
(function (UserRole) {
|
|
13
|
+
UserRole["Researcher"] = "default";
|
|
14
|
+
UserRole["Developer"] = "developer";
|
|
15
|
+
UserRole["Reviewer"] = "reviewer";
|
|
16
|
+
UserRole["Admin"] = "admin";
|
|
17
|
+
})(UserRole || (UserRole = {}));
|
|
18
|
+
export var UserPermission;
|
|
19
|
+
(function (UserPermission) {
|
|
20
|
+
UserPermission["aggregationsCreate"] = "aggregations-create";
|
|
21
|
+
UserPermission["aggregationsRead"] = "aggregations-read";
|
|
22
|
+
UserPermission["aggregationsPreview"] = "aggregations-preview";
|
|
23
|
+
UserPermission["aggregationsDelete"] = "aggregations-delete";
|
|
24
|
+
UserPermission["aggregationsVerify"] = "aggregations-verify";
|
|
25
|
+
UserPermission["aggregationsLatest"] = "aggregations-latest";
|
|
26
|
+
UserPermission["reconciliationsCreate"] = "reconciliations-create";
|
|
27
|
+
UserPermission["reconciliationsRead"] = "reconciliations-view";
|
|
28
|
+
UserPermission["reconciliationsUpdate"] = "reconciliations-update";
|
|
29
|
+
UserPermission["reconciliationsDelete"] = "reconciliations-delete";
|
|
30
|
+
})(UserPermission || (UserPermission = {}));
|
|
31
|
+
export var UserPermissionRequestStatus;
|
|
32
|
+
(function (UserPermissionRequestStatus) {
|
|
33
|
+
UserPermissionRequestStatus["Approved"] = "approved";
|
|
34
|
+
UserPermissionRequestStatus["Rejected"] = "rejected";
|
|
35
|
+
UserPermissionRequestStatus["Pending"] = "pending";
|
|
36
|
+
})(UserPermissionRequestStatus || (UserPermissionRequestStatus = {}));
|
|
37
|
+
export class User extends BaseModel {
|
|
38
|
+
email;
|
|
39
|
+
firstName;
|
|
40
|
+
lastName;
|
|
41
|
+
displayName;
|
|
42
|
+
password;
|
|
43
|
+
token;
|
|
44
|
+
role = UserRole.Researcher;
|
|
45
|
+
maxUploads = MaxUploads.New;
|
|
46
|
+
maxSkills = 1;
|
|
47
|
+
maxApiCalls = defaultMaxApiCalls;
|
|
48
|
+
dataPrivate = false;
|
|
49
|
+
validFilesCount = 0;
|
|
50
|
+
canCommitHestiaData = false;
|
|
51
|
+
permissions = [];
|
|
52
|
+
permissionsRequests = [];
|
|
53
|
+
emailNotificationsSuccess = false;
|
|
54
|
+
emailNotificationsFailure = false;
|
|
55
|
+
emailNotificationsFeedback = false;
|
|
56
|
+
emailNotificationsDownload = true;
|
|
57
|
+
autoSubmitPrivateSubmissions = false;
|
|
58
|
+
confirmToken;
|
|
59
|
+
confirmedAt;
|
|
60
|
+
lastActiveAt;
|
|
61
|
+
scopusID;
|
|
62
|
+
googleID;
|
|
63
|
+
linkedInID;
|
|
64
|
+
gitlabID;
|
|
65
|
+
gitlabUsername;
|
|
66
|
+
orcid;
|
|
67
|
+
website;
|
|
68
|
+
city;
|
|
69
|
+
country;
|
|
70
|
+
primaryInstitution;
|
|
71
|
+
metadata = {};
|
|
72
|
+
admin;
|
|
73
|
+
name;
|
|
74
|
+
actorId;
|
|
75
|
+
}
|
|
76
|
+
export const name = ({ firstName, lastName }) => [firstName, lastName].filter(Boolean).join(' ');
|
|
77
|
+
export const isAdmin = (user) => user?.role === UserRole.Admin;
|
|
78
|
+
export const isReviewer = (user) => [UserRole.Reviewer, UserRole.Admin].includes(user?.role);
|
|
79
|
+
export const isDeveloper = (user) => [UserRole.Developer, UserRole.Reviewer, UserRole.Admin].includes(user?.role);
|
|
80
|
+
export const hasPermission = (permission, user) => isAdmin(user) || (user?.permissions ?? []).includes(permission);
|
|
81
|
+
export const isPermissionRequestExpired = (request, timeout = userPermissionRequestTimeout) => new Date().getTime() - new Date(request.createdAt).getTime() >= timeout;
|
|
82
|
+
export const isPermissionExpired = (request, now = new Date()) => request.status === UserPermissionRequestStatus.Approved && request.expiryDate && new Date(request.expiryDate) <= now;
|
|
83
|
+
export const contains = (users, user) => users.some(u => u.email === user.email);
|
|
84
|
+
export const actorId = (user) => `${(user._id || user.id).toString()}`;
|
|
85
|
+
const jsonLDContext = (type, domain) => `${domain}/schema/${type}.jsonld`;
|
|
86
|
+
const addIfDefined = (key, value) => (!!value ? { [key]: value } : {});
|
|
87
|
+
const profileData = (user) => user.dataPrivate
|
|
88
|
+
? {}
|
|
89
|
+
: {
|
|
90
|
+
email: user.email,
|
|
91
|
+
firstName: user.firstName,
|
|
92
|
+
lastName: user.lastName,
|
|
93
|
+
name: user.displayName || name(user),
|
|
94
|
+
...addIfDefined('scopusID', user.scopusID),
|
|
95
|
+
...addIfDefined('orcid', user.orcid),
|
|
96
|
+
...addIfDefined('primaryInstitution', user.primaryInstitution),
|
|
97
|
+
...addIfDefined('city', user.city),
|
|
98
|
+
...addIfDefined('country', user.country ? { type: NodeType.Term, name: user.country } : undefined),
|
|
99
|
+
...addIfDefined('website', user.website ? { '@id': user.website } : undefined)
|
|
100
|
+
};
|
|
101
|
+
export const userToActor = (user, domain = 'https://hestia.earth') => ({
|
|
102
|
+
'@context': jsonLDContext(NodeType.Actor, domain),
|
|
103
|
+
'@type': NodeType.Actor,
|
|
104
|
+
'@id': actorId(user),
|
|
105
|
+
dataPrivate: false,
|
|
106
|
+
...profileData(user)
|
|
107
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export var WebhookType;
|
|
2
|
+
(function (WebhookType) {
|
|
3
|
+
WebhookType["Files"] = "files";
|
|
4
|
+
})(WebhookType || (WebhookType = {}));
|
|
5
|
+
export var WebhookEvent;
|
|
6
|
+
(function (WebhookEvent) {
|
|
7
|
+
WebhookEvent["Created"] = "created";
|
|
8
|
+
WebhookEvent["Updated"] = "updated";
|
|
9
|
+
})(WebhookEvent || (WebhookEvent = {}));
|
|
10
|
+
export var WebhookStatus;
|
|
11
|
+
(function (WebhookStatus) {
|
|
12
|
+
WebhookStatus["Active"] = "active";
|
|
13
|
+
WebhookStatus["Inactive"] = "inactive";
|
|
14
|
+
})(WebhookStatus || (WebhookStatus = {}));
|
|
15
|
+
export const webHookTestEvent = 'test';
|
|
@@ -46,6 +46,7 @@ class User extends model_base_1.BaseModel {
|
|
|
46
46
|
token;
|
|
47
47
|
role = UserRole.Researcher;
|
|
48
48
|
maxUploads = MaxUploads.New;
|
|
49
|
+
maxSkills = 1;
|
|
49
50
|
maxApiCalls = exports.defaultMaxApiCalls;
|
|
50
51
|
dataPrivate = false;
|
|
51
52
|
validFilesCount = 0;
|
|
@@ -88,9 +89,7 @@ const hasPermission = (permission, user) => (0, exports.isAdmin)(user) || (user?
|
|
|
88
89
|
exports.hasPermission = hasPermission;
|
|
89
90
|
const isPermissionRequestExpired = (request, timeout = exports.userPermissionRequestTimeout) => new Date().getTime() - new Date(request.createdAt).getTime() >= timeout;
|
|
90
91
|
exports.isPermissionRequestExpired = isPermissionRequestExpired;
|
|
91
|
-
const isPermissionExpired = (request, now = new Date()) => request.status === UserPermissionRequestStatus.Approved &&
|
|
92
|
-
request.expiryDate &&
|
|
93
|
-
new Date(request.expiryDate) <= now;
|
|
92
|
+
const isPermissionExpired = (request, now = new Date()) => request.status === UserPermissionRequestStatus.Approved && request.expiryDate && new Date(request.expiryDate) <= now;
|
|
94
93
|
exports.isPermissionExpired = isPermissionExpired;
|
|
95
94
|
const contains = (users, user) => users.some(u => u.email === user.email);
|
|
96
95
|
exports.contains = contains;
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hestia-earth/api",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Hestia API definitions",
|
|
5
5
|
"main": "dist/models.js",
|
|
6
|
+
"module": "dist/esm/models.js",
|
|
6
7
|
"typings": "dist/models.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/esm/models.js",
|
|
11
|
+
"require": "./dist/models.js",
|
|
12
|
+
"types": "./dist/models.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
7
16
|
"scripts": {
|
|
8
17
|
"build": "rm -rf build && tsc -p tsconfig.build.json",
|
|
9
|
-
"build:module": "rm -rf dist && tsc -p tsconfig.dist.json",
|
|
18
|
+
"build:module": "rm -rf dist && tsc -p tsconfig.dist.json && tsc -p tsconfig.esm.json",
|
|
10
19
|
"build:lambdas": "rm -rf build && tsc -p tsconfig.lambdas.json",
|
|
11
20
|
"validate:jsonld": "hestia-validate-jsonld test/fixtures/nodes",
|
|
12
21
|
"start": "npm run build && node index.js",
|