@researchdatabox/redbox-core 0.0.1-beta.10213 → 0.0.1-beta.10760
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/CoreController.d.ts +8 -0
- package/dist/CoreController.d.ts.map +1 -1
- package/dist/CoreController.js +87 -52
- package/dist/RecordsService.d.ts +2 -0
- package/dist/RecordsService.d.ts.map +1 -1
- package/dist/SearchService.d.ts +1 -1
- package/dist/SearchService.d.ts.map +1 -1
- package/dist/StorageService.d.ts +2 -0
- package/dist/StorageService.d.ts.map +1 -1
- package/dist/api-routes/groups/branding.d.ts +1 -0
- package/dist/api-routes/groups/branding.d.ts.map +1 -1
- package/dist/api-routes/groups/branding.js +19 -2
- package/dist/api-routes/groups/export.js +2 -2
- package/dist/api-routes/groups/figshare-crosswalks.d.ts +11 -0
- package/dist/api-routes/groups/figshare-crosswalks.d.ts.map +1 -0
- package/dist/api-routes/groups/figshare-crosswalks.js +171 -0
- package/dist/api-routes/groups/figshare-vocabulary.d.ts +12 -0
- package/dist/api-routes/groups/figshare-vocabulary.d.ts.map +1 -0
- package/dist/api-routes/groups/figshare-vocabulary.js +248 -0
- package/dist/api-routes/groups/search.js +4 -4
- package/dist/api-routes/groups/users.js +3 -3
- package/dist/api-routes/index.d.ts +2 -0
- package/dist/api-routes/index.d.ts.map +1 -1
- package/dist/api-routes/index.js +3 -1
- package/dist/api-routes/route-registry.d.ts.map +1 -1
- package/dist/api-routes/route-registry.js +5 -1
- package/dist/api-routes/schemas/common.d.ts +1 -0
- package/dist/api-routes/schemas/common.d.ts.map +1 -1
- package/dist/api-routes/schemas/common.js +3 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +5 -1
- package/dist/config/agendaQueue.config.d.ts +3 -0
- package/dist/config/agendaQueue.config.d.ts.map +1 -1
- package/dist/config/agendaQueue.config.js +13 -1
- package/dist/config/auth.config.d.ts.map +1 -1
- package/dist/config/auth.config.js +4 -1
- package/dist/config/brandingConfigurationDefaults.config.d.ts +1 -1
- package/dist/config/brandingConfigurationDefaults.config.d.ts.map +1 -1
- package/dist/config/brandingConfigurationDefaults.config.js +22 -230
- package/dist/config/dashboardtype.config.d.ts +7 -0
- package/dist/config/dashboardtype.config.d.ts.map +1 -1
- package/dist/config/dashboardtype.config.js +9 -89
- package/dist/config/dashboardview.config.d.ts +7 -0
- package/dist/config/dashboardview.config.d.ts.map +1 -1
- package/dist/config/dashboardview.config.js +9 -134
- package/dist/config/http.config.d.ts +2 -0
- package/dist/config/http.config.d.ts.map +1 -1
- package/dist/config/http.config.js +47 -1
- package/dist/config/jsonld.config.d.ts.map +1 -1
- package/dist/config/jsonld.config.js +2 -21
- package/dist/config/record.config.d.ts.map +1 -1
- package/dist/config/record.config.js +2 -9
- package/dist/config/recordtype.config.d.ts +8 -0
- package/dist/config/recordtype.config.d.ts.map +1 -1
- package/dist/config/recordtype.config.js +10 -660
- package/dist/config/reusableContributorFormDefinitions.config.d.ts.map +1 -1
- package/dist/config/reusableContributorFormDefinitions.config.js +1 -2
- package/dist/config/reusableViewFormDefinitions.config.d.ts.map +1 -1
- package/dist/config/reusableViewFormDefinitions.config.js +12 -1
- package/dist/config/routes.config.d.ts.map +1 -1
- package/dist/config/routes.config.js +12 -3
- package/dist/config/solr.config.d.ts +1 -0
- package/dist/config/solr.config.d.ts.map +1 -1
- package/dist/config/solr.config.js +3 -2
- package/dist/config/static_assets.config.d.ts +2 -0
- package/dist/config/static_assets.config.d.ts.map +1 -1
- package/dist/config/static_assets.config.js +4 -2
- package/dist/config/storage.config.d.ts.map +1 -1
- package/dist/config/storage.config.js +7 -1
- package/dist/config/views.config.d.ts.map +1 -1
- package/dist/config/views.config.js +2 -6
- package/dist/config/vocab.config.d.ts +4 -0
- package/dist/config/vocab.config.d.ts.map +1 -1
- package/dist/config/vocab.config.js +1 -1
- package/dist/config/workflow.config.d.ts +7 -0
- package/dist/config/workflow.config.d.ts.map +1 -1
- package/dist/config/workflow.config.js +9 -194
- package/dist/config/workspacetype.config.d.ts +7 -0
- package/dist/config/workspacetype.config.d.ts.map +1 -1
- package/dist/config/workspacetype.config.js +9 -10
- package/dist/configmodels/DoiPublishing.d.ts +1 -1
- package/dist/configmodels/DoiPublishing.d.ts.map +1 -1
- package/dist/configmodels/FigsharePublishing.d.ts +746 -217
- package/dist/configmodels/FigsharePublishing.d.ts.map +1 -1
- package/dist/configmodels/FigsharePublishing.js +181 -190
- package/dist/constants/export.d.ts +2 -0
- package/dist/constants/export.d.ts.map +1 -0
- package/dist/constants/export.js +8 -0
- package/dist/controllers/AsynchController.d.ts +4 -1
- package/dist/controllers/AsynchController.d.ts.map +1 -1
- package/dist/controllers/AsynchController.js +118 -9
- package/dist/controllers/BrandingAppController.d.ts +2 -0
- package/dist/controllers/BrandingAppController.d.ts.map +1 -1
- package/dist/controllers/BrandingAppController.js +40 -2
- package/dist/controllers/BrandingController.d.ts +8 -0
- package/dist/controllers/BrandingController.d.ts.map +1 -1
- package/dist/controllers/BrandingController.js +45 -1
- package/dist/controllers/ExportController.d.ts.map +1 -1
- package/dist/controllers/ExportController.js +4 -3
- package/dist/controllers/RecordController.d.ts +1 -1
- package/dist/controllers/RecordController.d.ts.map +1 -1
- package/dist/controllers/RecordController.js +47 -21
- package/dist/controllers/UserController.d.ts.map +1 -1
- package/dist/controllers/UserController.js +3 -2
- package/dist/controllers/VocabularyController.js +4 -4
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +7 -1
- package/dist/controllers/webservice/BrandingController.d.ts +1 -0
- package/dist/controllers/webservice/BrandingController.d.ts.map +1 -1
- package/dist/controllers/webservice/BrandingController.js +69 -10
- package/dist/controllers/webservice/ExportController.d.ts.map +1 -1
- package/dist/controllers/webservice/ExportController.js +4 -3
- package/dist/controllers/webservice/FigshareCrosswalkController.d.ts +20 -0
- package/dist/controllers/webservice/FigshareCrosswalkController.d.ts.map +1 -0
- package/dist/controllers/webservice/FigshareCrosswalkController.js +184 -0
- package/dist/controllers/webservice/FigshareVocabularyController.d.ts +21 -0
- package/dist/controllers/webservice/FigshareVocabularyController.d.ts.map +1 -0
- package/dist/controllers/webservice/FigshareVocabularyController.js +223 -0
- package/dist/controllers/webservice/RecordController.d.ts +2 -0
- package/dist/controllers/webservice/RecordController.d.ts.map +1 -1
- package/dist/controllers/webservice/RecordController.js +60 -12
- package/dist/controllers/webservice/UserManagementController.d.ts +5 -3
- package/dist/controllers/webservice/UserManagementController.d.ts.map +1 -1
- package/dist/controllers/webservice/UserManagementController.js +140 -9
- package/dist/controllers/webservice/figshare-vocabulary-errors.d.ts +14 -0
- package/dist/controllers/webservice/figshare-vocabulary-errors.d.ts.map +1 -0
- package/dist/controllers/webservice/figshare-vocabulary-errors.js +39 -0
- package/dist/form-config/index.d.ts +7 -0
- package/dist/form-config/index.d.ts.map +1 -1
- package/dist/form-config/index.js +8 -5
- package/dist/hooks/hookDiscovery.d.ts +20 -0
- package/dist/hooks/hookDiscovery.d.ts.map +1 -0
- package/dist/hooks/hookDiscovery.js +186 -0
- package/dist/hooks/hookResources.d.ts +23 -0
- package/dist/hooks/hookResources.d.ts.map +1 -0
- package/dist/hooks/hookResources.js +136 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +14 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/loader/index.d.ts.map +1 -1
- package/dist/loader/index.js +21 -62
- package/dist/model/storage/BrandingModel.d.ts +2 -0
- package/dist/model/storage/BrandingModel.d.ts.map +1 -1
- package/dist/model/storage/BrandingModel.js +3 -1
- package/dist/services/AgendaQueueService.d.ts.map +1 -1
- package/dist/services/AgendaQueueService.js +6 -2
- package/dist/services/BrandingLogoService.d.ts +20 -1
- package/dist/services/BrandingLogoService.d.ts.map +1 -1
- package/dist/services/BrandingLogoService.js +51 -5
- package/dist/services/BrandingThemeTokens.d.ts.map +1 -1
- package/dist/services/BrandingThemeTokens.js +2 -1
- package/dist/services/EmailService.d.ts +2 -8
- package/dist/services/EmailService.d.ts.map +1 -1
- package/dist/services/EmailService.js +8 -26
- package/dist/services/FigshareService.d.ts.map +1 -1
- package/dist/services/FigshareService.js +5 -4
- package/dist/services/FigshareVocabularyService.d.ts +442 -0
- package/dist/services/FigshareVocabularyService.d.ts.map +1 -0
- package/dist/services/FigshareVocabularyService.js +1802 -0
- package/dist/services/FormVocabularyService.d.ts.map +1 -1
- package/dist/services/FormVocabularyService.js +28 -7
- package/dist/services/I18nEntriesService.d.ts.map +1 -1
- package/dist/services/I18nEntriesService.js +21 -2
- package/dist/services/IntegrationAuditService.js +4 -4
- package/dist/services/NamedQueryService.d.ts.map +1 -1
- package/dist/services/NamedQueryService.js +3 -16
- package/dist/services/RDMPService.d.ts.map +1 -1
- package/dist/services/RDMPService.js +9 -1
- package/dist/services/RecordsService.d.ts +4 -0
- package/dist/services/RecordsService.d.ts.map +1 -1
- package/dist/services/RecordsService.js +62 -45
- package/dist/services/ReportsService.d.ts +0 -5
- package/dist/services/ReportsService.d.ts.map +1 -1
- package/dist/services/ReportsService.js +22 -31
- package/dist/services/SolrSearchService.d.ts +10 -2
- package/dist/services/SolrSearchService.d.ts.map +1 -1
- package/dist/services/SolrSearchService.js +110 -52
- package/dist/services/StandardDatastreamService.d.ts +7 -0
- package/dist/services/StandardDatastreamService.d.ts.map +1 -1
- package/dist/services/StandardDatastreamService.js +127 -27
- package/dist/services/TemplateService.d.ts +0 -14
- package/dist/services/TemplateService.d.ts.map +1 -1
- package/dist/services/TemplateService.js +4 -45
- package/dist/services/UsersService.d.ts.map +1 -1
- package/dist/services/UsersService.js +19 -16
- package/dist/services/ViewUtilsService.d.ts +5 -1
- package/dist/services/ViewUtilsService.d.ts.map +1 -1
- package/dist/services/ViewUtilsService.js +38 -46
- package/dist/services/VocabularyService.d.ts +11 -2
- package/dist/services/VocabularyService.d.ts.map +1 -1
- package/dist/services/VocabularyService.js +46 -20
- package/dist/services/doi-v2/bindings.d.ts.map +1 -1
- package/dist/services/doi-v2/bindings.js +2 -11
- package/dist/services/figshare-v2/assets.d.ts +2 -1
- package/dist/services/figshare-v2/assets.d.ts.map +1 -1
- package/dist/services/figshare-v2/assets.js +144 -89
- package/dist/services/figshare-v2/bindings.d.ts +28 -3
- package/dist/services/figshare-v2/bindings.d.ts.map +1 -1
- package/dist/services/figshare-v2/bindings.js +75 -17
- package/dist/services/figshare-v2/categories.d.ts +142 -0
- package/dist/services/figshare-v2/categories.d.ts.map +1 -0
- package/dist/services/figshare-v2/categories.js +408 -0
- package/dist/services/figshare-v2/config.d.ts +10 -0
- package/dist/services/figshare-v2/config.d.ts.map +1 -1
- package/dist/services/figshare-v2/config.js +39 -1
- package/dist/services/figshare-v2/context.d.ts +18 -1
- package/dist/services/figshare-v2/context.d.ts.map +1 -1
- package/dist/services/figshare-v2/context.js +34 -2
- package/dist/services/figshare-v2/embargo.d.ts.map +1 -1
- package/dist/services/figshare-v2/embargo.js +6 -4
- package/dist/services/figshare-v2/http.d.ts +3 -1
- package/dist/services/figshare-v2/http.d.ts.map +1 -1
- package/dist/services/figshare-v2/http.js +26 -4
- package/dist/services/figshare-v2/metadata.d.ts.map +1 -1
- package/dist/services/figshare-v2/metadata.js +74 -26
- package/dist/services/figshare-v2/observability.d.ts +1 -2
- package/dist/services/figshare-v2/observability.d.ts.map +1 -1
- package/dist/services/figshare-v2/observability.js +7 -47
- package/dist/services/figshare-v2/types.d.ts +13 -0
- package/dist/services/figshare-v2/types.d.ts.map +1 -1
- package/dist/services/figshare-v2/types.js +1 -1
- package/dist/services/figshare-v2/vocabulary-errors.d.ts +39 -0
- package/dist/services/figshare-v2/vocabulary-errors.d.ts.map +1 -0
- package/dist/services/figshare-v2/vocabulary-errors.js +68 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +8 -3
- package/dist/storage/TusStorageManagerDataStore.d.ts.map +1 -1
- package/dist/storage/TusStorageManagerDataStore.js +14 -1
- package/dist/utilities/ContextVariableUtils.d.ts +3 -1
- package/dist/utilities/ContextVariableUtils.d.ts.map +1 -1
- package/dist/utilities/ContextVariableUtils.js +25 -7
- package/dist/utilities/PromiseUtils.d.ts +9 -0
- package/dist/utilities/PromiseUtils.d.ts.map +1 -0
- package/dist/utilities/PromiseUtils.js +27 -0
- package/dist/utilities/RedactionUtils.d.ts +3 -0
- package/dist/utilities/RedactionUtils.d.ts.map +1 -0
- package/dist/utilities/RedactionUtils.js +55 -0
- package/dist/visitor/client.visitor.d.ts +3 -0
- package/dist/visitor/client.visitor.d.ts.map +1 -1
- package/dist/visitor/client.visitor.js +102 -17
- package/dist/visitor/construct.visitor.d.ts +3 -0
- package/dist/visitor/construct.visitor.d.ts.map +1 -1
- package/dist/visitor/construct.visitor.js +51 -38
- package/dist/visitor/json-type-def.visitor.d.ts +1 -0
- package/dist/visitor/json-type-def.visitor.d.ts.map +1 -1
- package/dist/visitor/json-type-def.visitor.js +20 -4
- package/dist/visitor/migrate-config-v4-v5.visitor.d.ts +6 -3
- package/dist/visitor/migrate-config-v4-v5.visitor.d.ts.map +1 -1
- package/dist/visitor/migrate-config-v4-v5.visitor.js +94 -44
- package/dist/visitor/validator.visitor.d.ts.map +1 -1
- package/dist/visitor/validator.visitor.js +1 -1
- package/dist/visitor/visitor-helpers.js +2 -2
- package/dist/waterline-models/BrandingConfig.d.ts +2 -0
- package/dist/waterline-models/BrandingConfig.d.ts.map +1 -1
- package/dist/waterline-models/BrandingConfig.js +6 -1
- package/dist/waterline-models/FigshareVocabularyCategory.d.ts +38 -0
- package/dist/waterline-models/FigshareVocabularyCategory.d.ts.map +1 -0
- package/dist/waterline-models/FigshareVocabularyCategory.js +157 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalk.d.ts +37 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalk.d.ts.map +1 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalk.js +153 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalkMapping.d.ts +37 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalkMapping.d.ts.map +1 -0
- package/dist/waterline-models/FigshareVocabularyCrosswalkMapping.js +138 -0
- package/dist/waterline-models/FigshareVocabularySource.d.ts +45 -0
- package/dist/waterline-models/FigshareVocabularySource.d.ts.map +1 -0
- package/dist/waterline-models/FigshareVocabularySource.js +149 -0
- package/dist/waterline-models/FigshareVocabularySyncRun.d.ts +70 -0
- package/dist/waterline-models/FigshareVocabularySyncRun.d.ts.map +1 -0
- package/dist/waterline-models/FigshareVocabularySyncRun.js +237 -0
- package/dist/waterline-models/Vocabulary.d.ts +3 -1
- package/dist/waterline-models/Vocabulary.d.ts.map +1 -1
- package/dist/waterline-models/Vocabulary.js +9 -3
- package/dist/waterline-models/index.d.ts +10 -0
- package/dist/waterline-models/index.d.ts.map +1 -1
- package/dist/waterline-models/index.js +16 -1
- package/package.json +19 -19
- package/dist/form-config/dataRecord-1.0-draft.d.ts +0 -4
- package/dist/form-config/dataRecord-1.0-draft.d.ts.map +0 -1
- package/dist/form-config/dataRecord-1.0-draft.js +0 -1042
- package/dist/form-config/default-1.0-draft.d.ts +0 -4
- package/dist/form-config/default-1.0-draft.d.ts.map +0 -1
- package/dist/form-config/default-1.0-draft.js +0 -1156
|
@@ -0,0 +1,1802 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Services = void 0;
|
|
40
|
+
const CoreService_1 = require("../CoreService");
|
|
41
|
+
const FigshareVocabularySyncRun_1 = require("../waterline-models/FigshareVocabularySyncRun");
|
|
42
|
+
const TransactionUtils_1 = require("../utilities/TransactionUtils");
|
|
43
|
+
const PromiseUtils_1 = require("../utilities/PromiseUtils");
|
|
44
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
45
|
+
const path = __importStar(require("node:path"));
|
|
46
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
47
|
+
const config_1 = require("./figshare-v2/config");
|
|
48
|
+
const http_1 = require("./figshare-v2/http");
|
|
49
|
+
const categories_1 = require("./figshare-v2/categories");
|
|
50
|
+
const vocabulary_errors_1 = require("./figshare-v2/vocabulary-errors");
|
|
51
|
+
var Services;
|
|
52
|
+
(function (Services) {
|
|
53
|
+
const PREVIEW_TTL_MS = 24 * 60 * 60 * 1000;
|
|
54
|
+
const MAX_MAPPING_BATCH = 2000;
|
|
55
|
+
const MAX_PAGE_SIZE = 200;
|
|
56
|
+
const DEFAULT_BOOTSTRAP_DATA_PATH = 'bootstrap-data';
|
|
57
|
+
const FIGSHARE_IMPORTS_FILE = 'figshare-imports.json';
|
|
58
|
+
const FIGSHARE_IMPORT_TIMEOUT_MS = 120_000;
|
|
59
|
+
const BOOTSTRAP_ACTOR = 'bootstrap-data';
|
|
60
|
+
class FigshareVocabularyService extends CoreService_1.Services.Core.Service {
|
|
61
|
+
_exportedMethods = [
|
|
62
|
+
'discoverTaxonomies',
|
|
63
|
+
'createPreview',
|
|
64
|
+
'getPreview',
|
|
65
|
+
'applyPreview',
|
|
66
|
+
'cloneMirror',
|
|
67
|
+
'listSources',
|
|
68
|
+
'getSource',
|
|
69
|
+
'listSourceCategories',
|
|
70
|
+
'listSyncRuns',
|
|
71
|
+
'listCrosswalks',
|
|
72
|
+
'getCrosswalk',
|
|
73
|
+
'getCrosswalkUsage',
|
|
74
|
+
'createCrosswalk',
|
|
75
|
+
'listCrosswalkLocalEntries',
|
|
76
|
+
'listCrosswalkMappings',
|
|
77
|
+
'saveMappings',
|
|
78
|
+
'approveCrosswalk',
|
|
79
|
+
'deleteCrosswalk',
|
|
80
|
+
'resolveCategories',
|
|
81
|
+
'resolveCrosswalkValues',
|
|
82
|
+
'bootstrapData'
|
|
83
|
+
];
|
|
84
|
+
// ── Infrastructure helpers ────────────────────────────────────────
|
|
85
|
+
getDatastore() {
|
|
86
|
+
return Vocabulary.getDatastore?.() ?? sails.getDatastore?.() ?? null;
|
|
87
|
+
}
|
|
88
|
+
async runQuery(query, connection) {
|
|
89
|
+
return connection ? query.usingConnection(connection) : query;
|
|
90
|
+
}
|
|
91
|
+
async createOne(query, connection) {
|
|
92
|
+
return this.runQuery(query.fetch(), connection);
|
|
93
|
+
}
|
|
94
|
+
nowIso() {
|
|
95
|
+
return new Date().toISOString();
|
|
96
|
+
}
|
|
97
|
+
resolveBrandName(brandId) {
|
|
98
|
+
const brandingService = typeof BrandingService === 'undefined' ? undefined : BrandingService;
|
|
99
|
+
const brand = brandingService?.getBrandById?.(brandId);
|
|
100
|
+
if (brand?.name != null && String(brand.name).trim() !== '') {
|
|
101
|
+
return String(brand.name);
|
|
102
|
+
}
|
|
103
|
+
return String(brandId);
|
|
104
|
+
}
|
|
105
|
+
buildRunContext(brandId, correlationId) {
|
|
106
|
+
const brandName = this.resolveBrandName(brandId);
|
|
107
|
+
return {
|
|
108
|
+
recordOid: '',
|
|
109
|
+
brandId,
|
|
110
|
+
brandName,
|
|
111
|
+
correlationId,
|
|
112
|
+
triggerSource: 'figshare-vocabulary-admin'
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolve a Figshare client for catalogue reads. The client is always built from
|
|
117
|
+
* trusted deployment configuration; a request never supplies a base URL or token.
|
|
118
|
+
*/
|
|
119
|
+
resolveClient(brandId, scope) {
|
|
120
|
+
const brandName = this.resolveBrandName(brandId);
|
|
121
|
+
const config = (0, config_1.resolveFigshareVocabularyConfig)(brandName);
|
|
122
|
+
if (config == null) {
|
|
123
|
+
throw new vocabulary_errors_1.FigshareTransportError('Figshare is not configured for this brand');
|
|
124
|
+
}
|
|
125
|
+
if (scope === 'account' && String(config.connection.token ?? '').trim() === '' && config.runtime.mode !== 'fixture') {
|
|
126
|
+
throw new vocabulary_errors_1.FigshareTransportError('The Figshare account catalogue requires a configured API token', 401);
|
|
127
|
+
}
|
|
128
|
+
const runContext = this.buildRunContext(brandId, `figshare-vocab-${Date.now()}`);
|
|
129
|
+
return config.runtime.mode === 'fixture'
|
|
130
|
+
? (0, http_1.makeFixtureClient)(config)
|
|
131
|
+
: (0, http_1.makeLiveClient)(config, runContext);
|
|
132
|
+
}
|
|
133
|
+
async fetchCatalogue(brandId, scope) {
|
|
134
|
+
const client = this.resolveClient(brandId, scope);
|
|
135
|
+
try {
|
|
136
|
+
return scope === 'account' ? await client.listAccountCategories() : await client.listPublicCategories();
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (error instanceof http_1.FigshareHttpError) {
|
|
140
|
+
// FigshareHttpError already strips the axios request config; keep it that way.
|
|
141
|
+
throw new vocabulary_errors_1.FigshareTransportError(`Figshare category catalogue request failed${error.statusCode == null ? '' : ` (status ${error.statusCode})`}`, error.statusCode);
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
assertScope(scope) {
|
|
147
|
+
const normalized = String(scope ?? '').trim().toLowerCase();
|
|
148
|
+
if (normalized !== 'public' && normalized !== 'account') {
|
|
149
|
+
throw new vocabulary_errors_1.CatalogueInvalidError("scope must be either 'public' or 'account'");
|
|
150
|
+
}
|
|
151
|
+
return normalized;
|
|
152
|
+
}
|
|
153
|
+
parsePaging(limit, offset, defaultLimit = 50) {
|
|
154
|
+
const parsedLimit = Number.parseInt(String(limit ?? defaultLimit), 10);
|
|
155
|
+
const parsedOffset = Number.parseInt(String(offset ?? 0), 10);
|
|
156
|
+
return {
|
|
157
|
+
limit: Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(MAX_PAGE_SIZE, parsedLimit) : defaultLimit,
|
|
158
|
+
offset: Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
// ── Brand-scoped resolution ───────────────────────────────────────
|
|
162
|
+
async requireSource(sourceId, brandId) {
|
|
163
|
+
const source = await FigshareVocabularySource.findOne({
|
|
164
|
+
id: String(sourceId ?? '').trim(),
|
|
165
|
+
branding: brandId
|
|
166
|
+
});
|
|
167
|
+
if (!source) {
|
|
168
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('Figshare source not found');
|
|
169
|
+
}
|
|
170
|
+
return source;
|
|
171
|
+
}
|
|
172
|
+
async requireCrosswalk(crosswalkId, brandId) {
|
|
173
|
+
const crosswalk = await FigshareVocabularyCrosswalk.findOne({
|
|
174
|
+
id: String(crosswalkId ?? '').trim(),
|
|
175
|
+
branding: brandId
|
|
176
|
+
});
|
|
177
|
+
if (!crosswalk) {
|
|
178
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('Figshare crosswalk not found');
|
|
179
|
+
}
|
|
180
|
+
return crosswalk;
|
|
181
|
+
}
|
|
182
|
+
async requireLocalVocabulary(vocabularyId, brandId) {
|
|
183
|
+
const vocabulary = await Vocabulary.findOne({
|
|
184
|
+
id: String(vocabularyId ?? '').trim(),
|
|
185
|
+
branding: brandId
|
|
186
|
+
});
|
|
187
|
+
if (!vocabulary) {
|
|
188
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('Local vocabulary not found');
|
|
189
|
+
}
|
|
190
|
+
if (vocabulary.source === 'external') {
|
|
191
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('A Figshare mirror cannot be used as the local side of a crosswalk');
|
|
192
|
+
}
|
|
193
|
+
return vocabulary;
|
|
194
|
+
}
|
|
195
|
+
async requireRun(runId, brandId) {
|
|
196
|
+
const run = await FigshareVocabularySyncRun.findOne({
|
|
197
|
+
id: String(runId ?? '').trim(),
|
|
198
|
+
branding: brandId
|
|
199
|
+
});
|
|
200
|
+
if (!run) {
|
|
201
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('Synchronisation preview not found');
|
|
202
|
+
}
|
|
203
|
+
return run;
|
|
204
|
+
}
|
|
205
|
+
/** Expiry is enforced synchronously; no scheduled job is introduced. */
|
|
206
|
+
async pruneExpiredRuns(brandId) {
|
|
207
|
+
const now = this.nowIso();
|
|
208
|
+
await FigshareVocabularySyncRun.update({
|
|
209
|
+
branding: brandId,
|
|
210
|
+
state: ['fetching', 'previewed'],
|
|
211
|
+
expiresAt: { '<': now }
|
|
212
|
+
}).set({ state: 'expired' });
|
|
213
|
+
}
|
|
214
|
+
async transitionRun(runId, from, to, patch = {}, connection) {
|
|
215
|
+
if (!(0, FigshareVocabularySyncRun_1.isAllowedSyncRunTransition)(from, to)) {
|
|
216
|
+
throw new vocabulary_errors_1.StalePreviewError(`Synchronisation run cannot move from '${from}' to '${to}'`);
|
|
217
|
+
}
|
|
218
|
+
const updated = await this.runQuery(FigshareVocabularySyncRun.updateOne({ id: runId, state: from }).set({ ...patch, state: to }), connection);
|
|
219
|
+
if (!updated) {
|
|
220
|
+
throw new vocabulary_errors_1.StalePreviewError(`Synchronisation run is no longer '${from}'`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// ── Discovery ─────────────────────────────────────────────────────
|
|
224
|
+
async discoverTaxonomies(input, ctx) {
|
|
225
|
+
const scope = this.assertScope(input?.scope);
|
|
226
|
+
const raw = await this.fetchCatalogue(ctx.brandId, scope);
|
|
227
|
+
return (0, categories_1.groupTaxonomies)((0, categories_1.normalizeFigshareCategories)(raw));
|
|
228
|
+
}
|
|
229
|
+
// ── Preview ───────────────────────────────────────────────────────
|
|
230
|
+
async loadSnapshot(brandId, scope, taxonomyId) {
|
|
231
|
+
const raw = await this.fetchCatalogue(brandId, scope);
|
|
232
|
+
const normalized = (0, categories_1.normalizeFigshareCategories)(raw);
|
|
233
|
+
const filtered = (0, categories_1.filterByTaxonomy)(normalized, taxonomyId);
|
|
234
|
+
if (filtered.rows.length === 0) {
|
|
235
|
+
throw new vocabulary_errors_1.CatalogueInvalidError(`Figshare returned no categories for taxonomy '${taxonomyId}'`);
|
|
236
|
+
}
|
|
237
|
+
(0, categories_1.assertSnapshotWithinLimits)(filtered.rows);
|
|
238
|
+
return { rows: filtered.rows, warnings: filtered.warnings };
|
|
239
|
+
}
|
|
240
|
+
async loadExistingCategories(sourceId) {
|
|
241
|
+
const categories = await FigshareVocabularyCategory.find({ source: sourceId });
|
|
242
|
+
return categories.map((category) => ({
|
|
243
|
+
sourceId: category.sourceId,
|
|
244
|
+
categoryId: category.categoryId,
|
|
245
|
+
title: '',
|
|
246
|
+
contentHash: category.contentHash,
|
|
247
|
+
historical: category.historical === true
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
async loadLocalEntries(vocabularyId) {
|
|
251
|
+
const entries = await VocabularyEntry.find({ vocabulary: vocabularyId });
|
|
252
|
+
return entries.map((entry) => ({
|
|
253
|
+
id: String(entry.id),
|
|
254
|
+
label: String(entry.label ?? ''),
|
|
255
|
+
labelLower: String(entry.labelLower ?? ''),
|
|
256
|
+
value: String(entry.value ?? ''),
|
|
257
|
+
valueLower: String(entry.valueLower ?? ''),
|
|
258
|
+
identifier: entry.identifier
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* A brand may only mirror a given catalogue once, so an import that names no explicit
|
|
263
|
+
* source still has to bind the existing mirror instead of creating a second one.
|
|
264
|
+
*/
|
|
265
|
+
async findSourceForCatalogue(brandId, scope, taxonomyId) {
|
|
266
|
+
return await FigshareVocabularySource.findOne({
|
|
267
|
+
branding: brandId,
|
|
268
|
+
scope,
|
|
269
|
+
taxonomyId
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Likewise, a local vocabulary is crosswalked to a mirror at most once; re-running the
|
|
274
|
+
* wizard for an existing pairing resynchronises that crosswalk rather than forking it.
|
|
275
|
+
*/
|
|
276
|
+
async findCrosswalkForPairing(brandId, localVocabularyId, sourceId) {
|
|
277
|
+
return await FigshareVocabularyCrosswalk.findOne({
|
|
278
|
+
branding: brandId,
|
|
279
|
+
localVocabulary: localVocabularyId,
|
|
280
|
+
figshareSource: sourceId
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Resolve which of the mutually exclusive preview modes was requested.
|
|
285
|
+
*
|
|
286
|
+
* Four shapes are accepted: an explicit crosswalk resync, a mirror-only resync
|
|
287
|
+
* (`sourceId` with no local target), an existing local vocabulary, and a new clone.
|
|
288
|
+
*/
|
|
289
|
+
async resolvePreviewMode(input, brandId, scope) {
|
|
290
|
+
const createLocalClone = input.createLocalClone === true;
|
|
291
|
+
const normalizedScope = scope ?? this.assertScope(input?.scope);
|
|
292
|
+
const crosswalkId = String(input.crosswalkId ?? '').trim();
|
|
293
|
+
const sourceId = String(input.sourceId ?? '').trim();
|
|
294
|
+
const localVocabularyId = String(input.localVocabularyId ?? '').trim();
|
|
295
|
+
if (crosswalkId) {
|
|
296
|
+
if (localVocabularyId || createLocalClone) {
|
|
297
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('A crosswalk resync cannot also select a local vocabulary or request a clone');
|
|
298
|
+
}
|
|
299
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, brandId);
|
|
300
|
+
const source = await this.requireSource(String(crosswalk.figshareSource), brandId);
|
|
301
|
+
const localVocabulary = await this.requireLocalVocabulary(String(crosswalk.localVocabulary), brandId);
|
|
302
|
+
return { source, crosswalk, localVocabulary, createLocalClone: false };
|
|
303
|
+
}
|
|
304
|
+
if (localVocabularyId && createLocalClone) {
|
|
305
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('Select an existing local vocabulary or create a clone, not both');
|
|
306
|
+
}
|
|
307
|
+
if (createLocalClone && String(input.localCloneName ?? '').trim() === '') {
|
|
308
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('localCloneName is required when creating an editable clone');
|
|
309
|
+
}
|
|
310
|
+
const source = sourceId
|
|
311
|
+
? await this.requireSource(sourceId, brandId)
|
|
312
|
+
: await this.findSourceForCatalogue(brandId, normalizedScope, String(input.taxonomyId ?? '').trim());
|
|
313
|
+
// Refreshing an existing mirror is a complete request on its own; only a brand new
|
|
314
|
+
// mirror needs to be told what it should be crosswalked to.
|
|
315
|
+
if (!localVocabularyId && !createLocalClone && !source) {
|
|
316
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('Select an existing local vocabulary or request an editable clone');
|
|
317
|
+
}
|
|
318
|
+
const localVocabulary = localVocabularyId ? await this.requireLocalVocabulary(localVocabularyId, brandId) : null;
|
|
319
|
+
const crosswalk = source && localVocabulary
|
|
320
|
+
? await this.findCrosswalkForPairing(brandId, String(localVocabulary.id), String(source.id))
|
|
321
|
+
: null;
|
|
322
|
+
return { source, crosswalk, localVocabulary, createLocalClone };
|
|
323
|
+
}
|
|
324
|
+
async createPreview(input, ctx) {
|
|
325
|
+
await this.pruneExpiredRuns(ctx.brandId);
|
|
326
|
+
const scope = this.assertScope(input?.scope);
|
|
327
|
+
const taxonomyId = String(input?.taxonomyId ?? '').trim();
|
|
328
|
+
if (!taxonomyId) {
|
|
329
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('taxonomyId is required');
|
|
330
|
+
}
|
|
331
|
+
const mode = await this.resolvePreviewMode(input, ctx.brandId, scope);
|
|
332
|
+
if (mode.source && mode.source.scope !== scope) {
|
|
333
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('The requested scope does not match the existing Figshare source');
|
|
334
|
+
}
|
|
335
|
+
if (mode.source && mode.source.taxonomyId !== taxonomyId) {
|
|
336
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('The requested taxonomy does not match the existing Figshare source');
|
|
337
|
+
}
|
|
338
|
+
const snapshot = await this.loadSnapshot(ctx.brandId, scope, taxonomyId);
|
|
339
|
+
const remoteHash = (0, categories_1.hashSnapshot)(snapshot.rows);
|
|
340
|
+
const existing = mode.source ? await this.loadExistingCategories(String(mode.source.id)) : [];
|
|
341
|
+
const diff = (0, categories_1.classifyChanges)(existing, snapshot.rows);
|
|
342
|
+
const historicalSourceIds = new Set(diff.rows.filter((row) => row.changeClass === 'removed').map((row) => row.sourceId));
|
|
343
|
+
let proposals = [];
|
|
344
|
+
let unresolvedLocalEntryIds = [];
|
|
345
|
+
if (mode.createLocalClone) {
|
|
346
|
+
// Clone entries do not exist yet; propose identity by remote sourceId and let
|
|
347
|
+
// apply bind them to the entry ids created inside the same transaction.
|
|
348
|
+
proposals = snapshot.rows.map((row) => ({
|
|
349
|
+
proposalId: `clone:${row.sourceId}`,
|
|
350
|
+
localEntryId: '',
|
|
351
|
+
localLabel: row.title,
|
|
352
|
+
localValue: row.sourceId,
|
|
353
|
+
targetSourceId: row.sourceId,
|
|
354
|
+
targetCategoryId: row.categoryId,
|
|
355
|
+
targetTitle: row.title,
|
|
356
|
+
matchType: 'identity',
|
|
357
|
+
preselected: true,
|
|
358
|
+
historical: false,
|
|
359
|
+
evidence: { rule: 'clone-identity', normalizerVersion: categories_1.FIGSHARE_NORMALIZER_VERSION }
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
else if (mode.localVocabulary) {
|
|
363
|
+
const localEntries = await this.loadLocalEntries(String(mode.localVocabulary.id));
|
|
364
|
+
const result = (0, categories_1.buildProposals)(localEntries, snapshot.rows, { historicalSourceIds });
|
|
365
|
+
proposals = result.proposals;
|
|
366
|
+
unresolvedLocalEntryIds = result.unresolvedLocalEntryIds;
|
|
367
|
+
}
|
|
368
|
+
const summary = {
|
|
369
|
+
...diff.summary,
|
|
370
|
+
proposed: proposals.length,
|
|
371
|
+
preselected: proposals.filter((proposal) => proposal.preselected).length,
|
|
372
|
+
unresolved: unresolvedLocalEntryIds.length,
|
|
373
|
+
historicalWarnings: diff.summary.removed
|
|
374
|
+
};
|
|
375
|
+
const expiresAt = new Date(Date.now() + PREVIEW_TTL_MS).toISOString();
|
|
376
|
+
const run = await FigshareVocabularySyncRun.create({
|
|
377
|
+
branding: ctx.brandId,
|
|
378
|
+
source: mode.source ? String(mode.source.id) : null,
|
|
379
|
+
scope,
|
|
380
|
+
taxonomyId,
|
|
381
|
+
localVocabulary: mode.localVocabulary ? String(mode.localVocabulary.id) : null,
|
|
382
|
+
crosswalk: mode.crosswalk ? String(mode.crosswalk.id) : null,
|
|
383
|
+
createLocalClone: mode.createLocalClone,
|
|
384
|
+
localCloneName: String(input.localCloneName ?? '').trim() || undefined,
|
|
385
|
+
localCloneSlug: String(input.localCloneSlug ?? '').trim() || undefined,
|
|
386
|
+
normalizerVersion: categories_1.FIGSHARE_NORMALIZER_VERSION,
|
|
387
|
+
state: 'previewed',
|
|
388
|
+
baseHash: mode.source ? String(mode.source.remoteHash ?? '') : '',
|
|
389
|
+
remoteHash,
|
|
390
|
+
normalizedSnapshot: snapshot.rows,
|
|
391
|
+
diff: { rows: diff.rows, summary: diff.summary },
|
|
392
|
+
proposals,
|
|
393
|
+
summary,
|
|
394
|
+
warnings: [...snapshot.warnings, ...unresolvedLocalEntryIds.map((id) => ({ code: 'unresolved-local-entry', localEntryId: id }))],
|
|
395
|
+
expiresAt,
|
|
396
|
+
requestedBy: ctx.userId
|
|
397
|
+
}).fetch();
|
|
398
|
+
return this.toSyncPreview(run);
|
|
399
|
+
}
|
|
400
|
+
toSyncPreview(run) {
|
|
401
|
+
return {
|
|
402
|
+
runId: String(run.id),
|
|
403
|
+
state: String(run.state),
|
|
404
|
+
scope: run.scope,
|
|
405
|
+
taxonomyId: run.taxonomyId,
|
|
406
|
+
sourceId: run.source == null ? null : String(run.source),
|
|
407
|
+
localVocabularyId: run.localVocabulary == null ? null : String(run.localVocabulary),
|
|
408
|
+
crosswalkId: run.crosswalk == null ? null : String(run.crosswalk),
|
|
409
|
+
createLocalClone: run.createLocalClone === true,
|
|
410
|
+
baseHash: String(run.baseHash ?? ''),
|
|
411
|
+
remoteHash: String(run.remoteHash ?? ''),
|
|
412
|
+
expiresAt: run.expiresAt,
|
|
413
|
+
normalizerVersion: run.normalizerVersion,
|
|
414
|
+
summary: (run.summary ?? {}),
|
|
415
|
+
warnings: (run.warnings ?? [])
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
async getPreview(runId, query, ctx) {
|
|
419
|
+
const run = await this.requireRun(runId, ctx.brandId);
|
|
420
|
+
if ((run.state === 'previewed' || run.state === 'fetching') && new Date(run.expiresAt).getTime() <= Date.now()) {
|
|
421
|
+
await this.transitionRun(String(run.id), String(run.state), 'expired');
|
|
422
|
+
throw new vocabulary_errors_1.PreviewExpiredError();
|
|
423
|
+
}
|
|
424
|
+
const view = query?.view === 'diff' ? 'diff' : 'proposals';
|
|
425
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset);
|
|
426
|
+
const search = String(query?.q ?? '').trim().toLowerCase();
|
|
427
|
+
let records;
|
|
428
|
+
if (view === 'diff') {
|
|
429
|
+
const diffRows = (run.diff?.rows ?? []);
|
|
430
|
+
records = diffRows.filter((row) => {
|
|
431
|
+
if (query?.changeClass && row.changeClass !== query.changeClass) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (search && !`${row.sourceId} ${row.title}`.toLowerCase().includes(search)) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
const proposals = (run.proposals ?? []);
|
|
442
|
+
records = proposals.filter((proposal) => {
|
|
443
|
+
if (query?.matchType && proposal.matchType !== query.matchType) {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
if (query?.historicalOnly === true && !proposal.historical) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (query?.unresolvedOnly === true && proposal.preselected) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (search) {
|
|
453
|
+
const haystack = `${proposal.localLabel} ${proposal.localValue} ${proposal.targetSourceId} ${proposal.targetTitle}`.toLowerCase();
|
|
454
|
+
if (!haystack.includes(search)) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return true;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
const unresolvedIds = (run.warnings ?? [])
|
|
462
|
+
.filter((warning) => warning?.code === 'unresolved-local-entry' && warning.localEntryId)
|
|
463
|
+
.map((warning) => String(warning.localEntryId));
|
|
464
|
+
const unresolvedEntries = unresolvedIds.length === 0
|
|
465
|
+
? []
|
|
466
|
+
: (await VocabularyEntry.find({ id: unresolvedIds })).map((entry) => ({
|
|
467
|
+
localEntryId: String(entry.id),
|
|
468
|
+
localLabel: String(entry.label ?? ''),
|
|
469
|
+
localValue: String(entry.value ?? '')
|
|
470
|
+
}));
|
|
471
|
+
return {
|
|
472
|
+
...this.toSyncPreview(run),
|
|
473
|
+
page: {
|
|
474
|
+
view,
|
|
475
|
+
records: records.slice(offset, offset + limit),
|
|
476
|
+
total: records.length,
|
|
477
|
+
limit,
|
|
478
|
+
offset
|
|
479
|
+
},
|
|
480
|
+
unresolved: unresolvedEntries
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
// ── Apply ─────────────────────────────────────────────────────────
|
|
484
|
+
dedupeLabel(title, sourceId, usedLabels) {
|
|
485
|
+
// VocabularyEntry enforces a unique label per vocabulary while Figshare freely
|
|
486
|
+
// repeats titles across a taxonomy, so collisions are disambiguated by code.
|
|
487
|
+
const base = title.trim() || sourceId;
|
|
488
|
+
if (!usedLabels.has(base.toLowerCase())) {
|
|
489
|
+
usedLabels.add(base.toLowerCase());
|
|
490
|
+
return base;
|
|
491
|
+
}
|
|
492
|
+
let candidate = `${base} (${sourceId})`;
|
|
493
|
+
let suffix = 2;
|
|
494
|
+
while (usedLabels.has(candidate.toLowerCase())) {
|
|
495
|
+
candidate = `${base} (${sourceId}-${suffix})`;
|
|
496
|
+
suffix += 1;
|
|
497
|
+
}
|
|
498
|
+
usedLabels.add(candidate.toLowerCase());
|
|
499
|
+
return candidate;
|
|
500
|
+
}
|
|
501
|
+
async applyPreview(runId, decisions, ctx) {
|
|
502
|
+
const run = await this.requireRun(runId, ctx.brandId);
|
|
503
|
+
if (run.state === 'applied') {
|
|
504
|
+
// A completed run is idempotent: replay the stored result without writing.
|
|
505
|
+
return (run.result ?? {});
|
|
506
|
+
}
|
|
507
|
+
if (run.state === 'applying') {
|
|
508
|
+
throw new vocabulary_errors_1.StalePreviewError('This preview is already being applied');
|
|
509
|
+
}
|
|
510
|
+
if (run.state !== 'previewed') {
|
|
511
|
+
throw new vocabulary_errors_1.StalePreviewError(`This preview is '${run.state}' and can no longer be applied`);
|
|
512
|
+
}
|
|
513
|
+
if (new Date(run.expiresAt).getTime() <= Date.now()) {
|
|
514
|
+
await this.transitionRun(String(run.id), 'previewed', 'expired');
|
|
515
|
+
throw new vocabulary_errors_1.PreviewExpiredError();
|
|
516
|
+
}
|
|
517
|
+
if (String(decisions?.remoteHash ?? '') !== String(run.remoteHash ?? '')) {
|
|
518
|
+
throw new vocabulary_errors_1.StalePreviewError('The reviewed remote snapshot no longer matches this preview');
|
|
519
|
+
}
|
|
520
|
+
const existingSource = run.source ? await this.requireSource(String(run.source), ctx.brandId) : null;
|
|
521
|
+
if (existingSource && String(existingSource.remoteHash ?? '') !== String(run.baseHash ?? '')) {
|
|
522
|
+
throw new vocabulary_errors_1.StalePreviewError('The Figshare mirror changed since this preview was generated');
|
|
523
|
+
}
|
|
524
|
+
const existingCrosswalk = run.crosswalk ? await this.requireCrosswalk(String(run.crosswalk), ctx.brandId) : null;
|
|
525
|
+
if (existingCrosswalk && decisions?.expectedRevision != null
|
|
526
|
+
&& Number(decisions.expectedRevision) !== Number(existingCrosswalk.workingRevision)) {
|
|
527
|
+
throw new vocabulary_errors_1.CrosswalkRevisionError();
|
|
528
|
+
}
|
|
529
|
+
await this.transitionRun(String(run.id), 'previewed', 'applying');
|
|
530
|
+
const createdIds = {
|
|
531
|
+
vocabularies: [],
|
|
532
|
+
sources: [],
|
|
533
|
+
crosswalks: []
|
|
534
|
+
};
|
|
535
|
+
try {
|
|
536
|
+
const result = await (0, TransactionUtils_1.runWithOptionalTransaction)(this.getDatastore(), async (connection) => this.applyPreviewWork(run, decisions, ctx, existingSource, existingCrosswalk, createdIds, connection), {
|
|
537
|
+
logger: sails.log,
|
|
538
|
+
unsupportedAdapterWarning: 'Transactions are not supported by this datastore adapter. Falling back to compensating cleanup for Figshare vocabulary apply.'
|
|
539
|
+
});
|
|
540
|
+
await this.transitionRun(String(run.id), 'applying', 'applied', {
|
|
541
|
+
appliedBy: ctx.userId,
|
|
542
|
+
appliedAt: result.appliedAt,
|
|
543
|
+
source: result.sourceId,
|
|
544
|
+
crosswalk: result.crosswalkId ?? null,
|
|
545
|
+
localVocabulary: result.localVocabularyId ?? null,
|
|
546
|
+
result: result
|
|
547
|
+
});
|
|
548
|
+
return result;
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
551
|
+
await this.compensate(createdIds);
|
|
552
|
+
await this.transitionRun(String(run.id), 'applying', 'failed', {
|
|
553
|
+
errorCode: error?.code ?? 'apply-failed',
|
|
554
|
+
errorDetail: error?.message ?? 'Figshare vocabulary apply failed'
|
|
555
|
+
});
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/** Best-effort cleanup for datastores without transaction support. */
|
|
560
|
+
async compensate(created) {
|
|
561
|
+
try {
|
|
562
|
+
for (const crosswalkId of created.crosswalks) {
|
|
563
|
+
await FigshareVocabularyCrosswalkMapping.destroy({ crosswalk: crosswalkId });
|
|
564
|
+
await FigshareVocabularyCrosswalk.destroyOne({ id: crosswalkId });
|
|
565
|
+
}
|
|
566
|
+
for (const sourceId of created.sources) {
|
|
567
|
+
await FigshareVocabularyCategory.destroy({ source: sourceId });
|
|
568
|
+
await FigshareVocabularySource.destroyOne({ id: sourceId });
|
|
569
|
+
}
|
|
570
|
+
for (const vocabularyId of created.vocabularies) {
|
|
571
|
+
await VocabularyEntry.destroy({ vocabulary: vocabularyId });
|
|
572
|
+
await Vocabulary.destroyOne({ id: vocabularyId });
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
catch (cleanupError) {
|
|
576
|
+
sails.log.error('Figshare vocabulary apply compensation failed', cleanupError);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async applyPreviewWork(run, decisions, ctx, existingSource, existingCrosswalk, createdIds, connection) {
|
|
580
|
+
const snapshot = (run.normalizedSnapshot ?? []);
|
|
581
|
+
const appliedAt = this.nowIso();
|
|
582
|
+
// 1. Source + external mirror vocabulary.
|
|
583
|
+
let source = existingSource;
|
|
584
|
+
let mirrorVocabularyId;
|
|
585
|
+
if (source) {
|
|
586
|
+
mirrorVocabularyId = String(source.vocabulary);
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
const mirrorName = `Figshare ${run.scope} taxonomy ${run.taxonomyId}`;
|
|
590
|
+
const mirror = await this.createOne(Vocabulary.create({
|
|
591
|
+
name: mirrorName,
|
|
592
|
+
description: `Read-only mirror of the Figshare ${run.scope} category catalogue for taxonomy ${run.taxonomyId}`,
|
|
593
|
+
type: 'tree',
|
|
594
|
+
source: 'external',
|
|
595
|
+
sourceId: `${run.scope}:${run.taxonomyId}`,
|
|
596
|
+
figshareSourceKey: `${ctx.brandId}:${run.scope}:${run.taxonomyId}`,
|
|
597
|
+
branding: ctx.brandId
|
|
598
|
+
}), connection);
|
|
599
|
+
mirrorVocabularyId = String(mirror.id);
|
|
600
|
+
createdIds.vocabularies.push(mirrorVocabularyId);
|
|
601
|
+
source = await this.createOne(FigshareVocabularySource.create({
|
|
602
|
+
branding: ctx.brandId,
|
|
603
|
+
vocabulary: mirrorVocabularyId,
|
|
604
|
+
scope: run.scope,
|
|
605
|
+
taxonomyId: run.taxonomyId,
|
|
606
|
+
displayName: mirrorName,
|
|
607
|
+
createdBy: ctx.userId,
|
|
608
|
+
updatedBy: ctx.userId
|
|
609
|
+
}), connection);
|
|
610
|
+
createdIds.sources.push(String(source.id));
|
|
611
|
+
}
|
|
612
|
+
const sourceId = String(source.id);
|
|
613
|
+
// 2/3. Upsert category relationships and mirrored entries, then mark omissions historical.
|
|
614
|
+
const mirrorStats = await this.syncMirror(sourceId, mirrorVocabularyId, snapshot, appliedAt, connection);
|
|
615
|
+
// 4. Optional independent local clone.
|
|
616
|
+
let localVocabularyId = run.localVocabulary == null ? null : String(run.localVocabulary);
|
|
617
|
+
let cloneCreated = false;
|
|
618
|
+
let cloneEntryBySourceId = new Map();
|
|
619
|
+
if (run.createLocalClone === true && !localVocabularyId) {
|
|
620
|
+
const clone = await this.createCloneVocabulary(String(run.localCloneName ?? '').trim(), String(run.localCloneSlug ?? '').trim(), snapshot, ctx, connection);
|
|
621
|
+
localVocabularyId = clone.vocabularyId;
|
|
622
|
+
cloneEntryBySourceId = clone.entryBySourceId;
|
|
623
|
+
cloneCreated = true;
|
|
624
|
+
createdIds.vocabularies.push(localVocabularyId);
|
|
625
|
+
}
|
|
626
|
+
// 5. Crosswalk and mapping edges.
|
|
627
|
+
let crosswalkId = existingCrosswalk ? String(existingCrosswalk.id) : null;
|
|
628
|
+
let crosswalkRevision = existingCrosswalk ? Number(existingCrosswalk.workingRevision) : null;
|
|
629
|
+
let mappingStats = { created: 0, removed: 0 };
|
|
630
|
+
if (localVocabularyId) {
|
|
631
|
+
if (!crosswalkId) {
|
|
632
|
+
// A clone knows its own name up front; an existing local vocabulary has to be
|
|
633
|
+
// read back so the crosswalk is labelled after it rather than a generic stand-in.
|
|
634
|
+
let localLabel = String(run.localCloneName ?? '').trim();
|
|
635
|
+
if (!localLabel) {
|
|
636
|
+
const localVocabulary = await this.runQuery(Vocabulary.findOne({ id: localVocabularyId }), connection);
|
|
637
|
+
localLabel = String(localVocabulary?.name ?? '').trim();
|
|
638
|
+
}
|
|
639
|
+
const crosswalkName = await this.uniqueCrosswalkName(`${localLabel || 'Crosswalk'} → Figshare taxonomy ${run.taxonomyId}`, ctx.brandId, connection);
|
|
640
|
+
const crosswalk = await this.createOne(FigshareVocabularyCrosswalk.create({
|
|
641
|
+
branding: ctx.brandId,
|
|
642
|
+
name: crosswalkName,
|
|
643
|
+
localVocabulary: localVocabularyId,
|
|
644
|
+
figshareSource: sourceId,
|
|
645
|
+
status: 'draft',
|
|
646
|
+
workingRevision: 1,
|
|
647
|
+
updatedBy: ctx.userId
|
|
648
|
+
}), connection);
|
|
649
|
+
crosswalkId = String(crosswalk.id);
|
|
650
|
+
crosswalkRevision = 1;
|
|
651
|
+
createdIds.crosswalks.push(crosswalkId);
|
|
652
|
+
}
|
|
653
|
+
mappingStats = await this.writeMappingEdges(crosswalkId, crosswalkRevision ?? 1, run, decisions, sourceId, localVocabularyId, cloneEntryBySourceId, ctx, connection);
|
|
654
|
+
}
|
|
655
|
+
// 6. Source cursor.
|
|
656
|
+
await this.runQuery(FigshareVocabularySource.updateOne({ id: sourceId }).set({
|
|
657
|
+
remoteHash: String(run.remoteHash ?? ''),
|
|
658
|
+
lastSyncedAt: appliedAt,
|
|
659
|
+
lastSyncRun: String(run.id),
|
|
660
|
+
updatedBy: ctx.userId
|
|
661
|
+
}), connection);
|
|
662
|
+
return {
|
|
663
|
+
runId: String(run.id),
|
|
664
|
+
state: 'applied',
|
|
665
|
+
sourceId,
|
|
666
|
+
vocabularyId: mirrorVocabularyId,
|
|
667
|
+
localVocabularyId,
|
|
668
|
+
crosswalkId,
|
|
669
|
+
crosswalkRevision,
|
|
670
|
+
categories: mirrorStats,
|
|
671
|
+
mappings: mappingStats,
|
|
672
|
+
cloneCreated,
|
|
673
|
+
appliedAt
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
async syncMirror(sourceId, mirrorVocabularyId, snapshot, appliedAt, connection) {
|
|
677
|
+
const existingCategories = await this.runQuery(FigshareVocabularyCategory.find({ source: sourceId }), connection);
|
|
678
|
+
const existingBySourceId = new Map(existingCategories.map((category) => [category.sourceId, category]));
|
|
679
|
+
const existingEntries = await this.runQuery(VocabularyEntry.find({ vocabulary: mirrorVocabularyId }), connection);
|
|
680
|
+
const usedLabels = new Set(existingEntries.map((entry) => String(entry.labelLower ?? '')));
|
|
681
|
+
const entryIdByCategoryId = new Map(existingCategories.map((category) => [category.sourceId, String(category.entry)]));
|
|
682
|
+
const stats = { created: 0, updated: 0, historical: 0, reappeared: 0 };
|
|
683
|
+
const entryIdBySourceId = new Map();
|
|
684
|
+
for (const row of snapshot) {
|
|
685
|
+
const existing = existingBySourceId.get(row.sourceId);
|
|
686
|
+
if (!existing) {
|
|
687
|
+
const label = this.dedupeLabel(row.title, row.sourceId, usedLabels);
|
|
688
|
+
const entry = await this.createOne(VocabularyEntry.create({
|
|
689
|
+
vocabulary: mirrorVocabularyId,
|
|
690
|
+
label,
|
|
691
|
+
value: row.sourceId,
|
|
692
|
+
identifier: row.sourceId,
|
|
693
|
+
order: 0,
|
|
694
|
+
historical: false
|
|
695
|
+
}), connection);
|
|
696
|
+
entryIdBySourceId.set(row.sourceId, String(entry.id));
|
|
697
|
+
await this.createOne(FigshareVocabularyCategory.create({
|
|
698
|
+
source: sourceId,
|
|
699
|
+
entry: String(entry.id),
|
|
700
|
+
sourceId: row.sourceId,
|
|
701
|
+
categoryId: row.categoryId,
|
|
702
|
+
taxonomyId: row.taxonomyId,
|
|
703
|
+
parentSourceId: row.parentSourceId ?? undefined,
|
|
704
|
+
path: row.path,
|
|
705
|
+
selectable: row.selectable,
|
|
706
|
+
historical: false,
|
|
707
|
+
firstSeenAt: appliedAt,
|
|
708
|
+
lastSeenAt: appliedAt,
|
|
709
|
+
contentHash: row.contentHash
|
|
710
|
+
}), connection);
|
|
711
|
+
stats.created += 1;
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
const entryId = String(existing.entry);
|
|
715
|
+
entryIdBySourceId.set(row.sourceId, entryId);
|
|
716
|
+
const wasHistorical = existing.historical === true;
|
|
717
|
+
if (wasHistorical) {
|
|
718
|
+
stats.reappeared += 1;
|
|
719
|
+
}
|
|
720
|
+
else if (existing.contentHash !== row.contentHash) {
|
|
721
|
+
stats.updated += 1;
|
|
722
|
+
}
|
|
723
|
+
if (wasHistorical || existing.contentHash !== row.contentHash) {
|
|
724
|
+
await this.runQuery(VocabularyEntry.updateOne({ id: entryId }).set({
|
|
725
|
+
label: this.relabelExisting(row, existingEntries, entryId, usedLabels),
|
|
726
|
+
historical: false
|
|
727
|
+
}), connection);
|
|
728
|
+
}
|
|
729
|
+
await this.runQuery(FigshareVocabularyCategory.updateOne({ id: String(existing.id) }).set({
|
|
730
|
+
categoryId: row.categoryId,
|
|
731
|
+
taxonomyId: row.taxonomyId,
|
|
732
|
+
parentSourceId: row.parentSourceId ?? undefined,
|
|
733
|
+
path: row.path,
|
|
734
|
+
selectable: row.selectable,
|
|
735
|
+
historical: false,
|
|
736
|
+
lastSeenAt: appliedAt,
|
|
737
|
+
contentHash: row.contentHash
|
|
738
|
+
}), connection);
|
|
739
|
+
}
|
|
740
|
+
// Remote omission never hard-deletes: retain identity and audit evidence.
|
|
741
|
+
const remoteSourceIds = new Set(snapshot.map((row) => row.sourceId));
|
|
742
|
+
for (const existing of existingCategories) {
|
|
743
|
+
if (remoteSourceIds.has(existing.sourceId) || existing.historical === true) {
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
await this.runQuery(FigshareVocabularyCategory.updateOne({ id: String(existing.id) }).set({ historical: true }), connection);
|
|
747
|
+
await this.runQuery(VocabularyEntry.updateOne({ id: String(existing.entry) }).set({ historical: true }), connection);
|
|
748
|
+
stats.historical += 1;
|
|
749
|
+
}
|
|
750
|
+
// Parents are rebuilt after every entry exists so ordering never matters.
|
|
751
|
+
for (const row of snapshot) {
|
|
752
|
+
const entryId = entryIdBySourceId.get(row.sourceId) ?? entryIdByCategoryId.get(row.sourceId);
|
|
753
|
+
if (!entryId) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const parentEntryId = row.parentSourceId == null
|
|
757
|
+
? null
|
|
758
|
+
: entryIdBySourceId.get(row.parentSourceId) ?? entryIdByCategoryId.get(row.parentSourceId) ?? null;
|
|
759
|
+
await this.runQuery(VocabularyEntry.updateOne({ id: entryId }).set({ parent: parentEntryId }), connection);
|
|
760
|
+
}
|
|
761
|
+
return stats;
|
|
762
|
+
}
|
|
763
|
+
relabelExisting(row, existingEntries, entryId, usedLabels) {
|
|
764
|
+
const current = existingEntries.find((entry) => String(entry.id) === entryId);
|
|
765
|
+
const currentLabelLower = String(current?.labelLower ?? '');
|
|
766
|
+
if (currentLabelLower === row.title.toLowerCase()) {
|
|
767
|
+
return row.title;
|
|
768
|
+
}
|
|
769
|
+
usedLabels.delete(currentLabelLower);
|
|
770
|
+
return this.dedupeLabel(row.title, row.sourceId, usedLabels);
|
|
771
|
+
}
|
|
772
|
+
async createCloneVocabulary(name, slug, snapshot, ctx, connection) {
|
|
773
|
+
if (!name) {
|
|
774
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('A clone name is required to create an editable local vocabulary');
|
|
775
|
+
}
|
|
776
|
+
const clone = await this.createOne(Vocabulary.create({
|
|
777
|
+
name,
|
|
778
|
+
...(slug ? { slug } : {}),
|
|
779
|
+
description: 'Editable local copy of a Figshare category catalogue',
|
|
780
|
+
type: 'tree',
|
|
781
|
+
source: 'local',
|
|
782
|
+
branding: ctx.brandId
|
|
783
|
+
}), connection);
|
|
784
|
+
const vocabularyId = String(clone.id);
|
|
785
|
+
const usedLabels = new Set();
|
|
786
|
+
const entryBySourceId = new Map();
|
|
787
|
+
for (const row of snapshot) {
|
|
788
|
+
const entry = await this.createOne(VocabularyEntry.create({
|
|
789
|
+
vocabulary: vocabularyId,
|
|
790
|
+
label: this.dedupeLabel(row.title, row.sourceId, usedLabels),
|
|
791
|
+
value: row.sourceId,
|
|
792
|
+
identifier: row.sourceId,
|
|
793
|
+
order: 0,
|
|
794
|
+
historical: false
|
|
795
|
+
}), connection);
|
|
796
|
+
entryBySourceId.set(row.sourceId, String(entry.id));
|
|
797
|
+
}
|
|
798
|
+
// Parent references are rebuilt against clone entry ids once all entries exist.
|
|
799
|
+
for (const row of snapshot) {
|
|
800
|
+
const entryId = entryBySourceId.get(row.sourceId);
|
|
801
|
+
const parentId = row.parentSourceId == null ? null : entryBySourceId.get(row.parentSourceId) ?? null;
|
|
802
|
+
if (!entryId || parentId == null) {
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
await this.runQuery(VocabularyEntry.updateOne({ id: entryId }).set({ parent: parentId }), connection);
|
|
806
|
+
}
|
|
807
|
+
return { vocabularyId, entryBySourceId };
|
|
808
|
+
}
|
|
809
|
+
async uniqueCrosswalkName(base, brandId, connection) {
|
|
810
|
+
let candidate = base;
|
|
811
|
+
let suffix = 2;
|
|
812
|
+
// The unique { branding, name } index makes collisions a hard failure, so probe first.
|
|
813
|
+
while (await this.runQuery(FigshareVocabularyCrosswalk.findOne({ branding: brandId, name: candidate }), connection)) {
|
|
814
|
+
candidate = `${base} (${suffix})`;
|
|
815
|
+
suffix += 1;
|
|
816
|
+
}
|
|
817
|
+
return candidate;
|
|
818
|
+
}
|
|
819
|
+
async writeMappingEdges(crosswalkId, revision, run, decisions, sourceId, localVocabularyId, cloneEntryBySourceId, ctx, connection) {
|
|
820
|
+
const categories = await this.runQuery(FigshareVocabularyCategory.find({ source: sourceId }), connection);
|
|
821
|
+
const categoryBySourceId = new Map(categories.map((category) => [category.sourceId, category]));
|
|
822
|
+
const approvedProposalIds = new Set((decisions?.approvedProposalIds ?? []).map((id) => String(id)));
|
|
823
|
+
const proposals = (run.proposals ?? []);
|
|
824
|
+
const desiredEdges = new Map();
|
|
825
|
+
const addEdge = (localEntryId, categorySourceId, matchType) => {
|
|
826
|
+
const category = categoryBySourceId.get(categorySourceId);
|
|
827
|
+
if (!localEntryId || !category) {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
desiredEdges.set(`${localEntryId}::${String(category.id)}`, {
|
|
831
|
+
localEntryId,
|
|
832
|
+
categoryId: String(category.id),
|
|
833
|
+
matchType
|
|
834
|
+
});
|
|
835
|
+
};
|
|
836
|
+
for (const proposal of proposals) {
|
|
837
|
+
if (!approvedProposalIds.has(proposal.proposalId)) {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const localEntryId = proposal.localEntryId
|
|
841
|
+
|| cloneEntryBySourceId.get(proposal.targetSourceId)
|
|
842
|
+
|| '';
|
|
843
|
+
addEdge(localEntryId, proposal.targetSourceId, proposal.matchType);
|
|
844
|
+
}
|
|
845
|
+
const manualMappings = decisions?.manualMappings ?? [];
|
|
846
|
+
if (manualMappings.length > MAX_MAPPING_BATCH) {
|
|
847
|
+
throw new vocabulary_errors_1.CatalogueInvalidError(`manualMappings exceeds the maximum batch size of ${MAX_MAPPING_BATCH}`);
|
|
848
|
+
}
|
|
849
|
+
for (const mapping of manualMappings) {
|
|
850
|
+
const localEntryId = String(mapping.localEntryId ?? '').trim()
|
|
851
|
+
|| cloneEntryBySourceId.get(String(mapping.localEntryKey ?? '').trim())
|
|
852
|
+
|| '';
|
|
853
|
+
for (const targetSourceId of mapping.figshareSourceIds ?? []) {
|
|
854
|
+
addEdge(localEntryId, String(targetSourceId).trim(), 'manual');
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (desiredEdges.size > 0) {
|
|
858
|
+
const localEntryIds = Array.from(new Set(Array.from(desiredEdges.values()).map((edge) => edge.localEntryId)));
|
|
859
|
+
const localEntries = await this.runQuery(VocabularyEntry.find({ id: localEntryIds, vocabulary: localVocabularyId }), connection);
|
|
860
|
+
const validLocalEntryIds = new Set(localEntries.map((entry) => String(entry.id)));
|
|
861
|
+
for (const edge of desiredEdges.values()) {
|
|
862
|
+
if (!validLocalEntryIds.has(edge.localEntryId)) {
|
|
863
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('A mapping references a local entry outside the crosswalk local vocabulary');
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
const existingEdges = await this.runQuery(FigshareVocabularyCrosswalkMapping.find({ crosswalk: crosswalkId, revision }), connection);
|
|
868
|
+
const existingKeys = new Set(existingEdges.map((edge) => `${String(edge.localEntry)}::${String(edge.figshareCategory)}`));
|
|
869
|
+
let created = 0;
|
|
870
|
+
for (const [key, edge] of desiredEdges) {
|
|
871
|
+
if (existingKeys.has(key)) {
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
await this.createOne(FigshareVocabularyCrosswalkMapping.create({
|
|
875
|
+
crosswalk: crosswalkId,
|
|
876
|
+
revision,
|
|
877
|
+
localEntry: edge.localEntryId,
|
|
878
|
+
figshareCategory: edge.categoryId,
|
|
879
|
+
status: 'proposed',
|
|
880
|
+
matchType: edge.matchType
|
|
881
|
+
}), connection);
|
|
882
|
+
created += 1;
|
|
883
|
+
}
|
|
884
|
+
await this.runQuery(FigshareVocabularyCrosswalk.updateOne({ id: crosswalkId }).set({ updatedBy: ctx.userId }), connection);
|
|
885
|
+
return { created, removed: 0 };
|
|
886
|
+
}
|
|
887
|
+
// ── Sources ───────────────────────────────────────────────────────
|
|
888
|
+
async listSources(query, ctx) {
|
|
889
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset, 25);
|
|
890
|
+
const where = { branding: ctx.brandId };
|
|
891
|
+
if (query?.scope === 'public' || query?.scope === 'account') {
|
|
892
|
+
where.scope = query.scope;
|
|
893
|
+
}
|
|
894
|
+
const search = String(query?.q ?? '').trim();
|
|
895
|
+
if (search) {
|
|
896
|
+
where.displayName = { contains: search };
|
|
897
|
+
}
|
|
898
|
+
const total = await FigshareVocabularySource.count(where);
|
|
899
|
+
const sources = await FigshareVocabularySource.find(where)
|
|
900
|
+
.sort('displayName ASC')
|
|
901
|
+
.skip(offset)
|
|
902
|
+
.limit(limit);
|
|
903
|
+
const data = await Promise.all(sources.map((source) => this.describeSource(source)));
|
|
904
|
+
return { data, meta: { total, limit, offset } };
|
|
905
|
+
}
|
|
906
|
+
async getSource(sourceId, ctx) {
|
|
907
|
+
return this.describeSource(await this.requireSource(sourceId, ctx.brandId));
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Search the mirrored categories of one source so an operator can pick a manual
|
|
911
|
+
* crosswalk target. Historical targets stay hidden unless explicitly requested:
|
|
912
|
+
* mapping to a retired Figshare category is a deliberate act, not a default.
|
|
913
|
+
*/
|
|
914
|
+
async listSourceCategories(sourceId, query, ctx) {
|
|
915
|
+
const source = await this.requireSource(sourceId, ctx.brandId);
|
|
916
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset, 25);
|
|
917
|
+
const where = { source: String(source.id) };
|
|
918
|
+
if (query?.includeHistorical !== true) {
|
|
919
|
+
where.historical = false;
|
|
920
|
+
}
|
|
921
|
+
if (query?.selectableOnly === true) {
|
|
922
|
+
where.selectable = true;
|
|
923
|
+
}
|
|
924
|
+
const categories = await FigshareVocabularyCategory.find(where);
|
|
925
|
+
const titleByEntryId = await this.loadCategoryTitles(categories);
|
|
926
|
+
const search = String(query?.q ?? '').trim().toLowerCase();
|
|
927
|
+
const rows = categories
|
|
928
|
+
.map((category) => ({
|
|
929
|
+
id: String(category.id),
|
|
930
|
+
sourceId: String(category.sourceId),
|
|
931
|
+
categoryId: Number(category.categoryId),
|
|
932
|
+
title: titleByEntryId.get(String(category.entry)) ?? String(category.sourceId),
|
|
933
|
+
parentSourceId: category.parentSourceId,
|
|
934
|
+
selectable: category.selectable !== false,
|
|
935
|
+
historical: category.historical === true
|
|
936
|
+
}))
|
|
937
|
+
.filter((row) => !search
|
|
938
|
+
|| `${row.title} ${row.sourceId} ${row.categoryId}`.toLowerCase().includes(search))
|
|
939
|
+
.sort((left, right) => left.sourceId.localeCompare(right.sourceId, undefined, { numeric: true }));
|
|
940
|
+
return {
|
|
941
|
+
data: rows.slice(offset, offset + limit),
|
|
942
|
+
meta: { total: rows.length, limit, offset }
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
/** Mirrored category titles live on the linked vocabulary entry, not the category row. */
|
|
946
|
+
async loadCategoryTitles(categories) {
|
|
947
|
+
if (categories.length === 0) {
|
|
948
|
+
return new Map();
|
|
949
|
+
}
|
|
950
|
+
const entryIds = Array.from(new Set(categories.map((category) => String(category.entry))));
|
|
951
|
+
const entries = await VocabularyEntry.find({ id: entryIds });
|
|
952
|
+
return new Map(entries.map((entry) => [String(entry.id), String(entry.label ?? '')]));
|
|
953
|
+
}
|
|
954
|
+
async describeSource(source) {
|
|
955
|
+
const sourceId = String(source.id);
|
|
956
|
+
const [mirroredCount, historicalCount, crosswalkCount] = await Promise.all([
|
|
957
|
+
FigshareVocabularyCategory.count({ source: sourceId, historical: false }),
|
|
958
|
+
FigshareVocabularyCategory.count({ source: sourceId, historical: true }),
|
|
959
|
+
FigshareVocabularyCrosswalk.count({ figshareSource: sourceId })
|
|
960
|
+
]);
|
|
961
|
+
const vocabulary = await Vocabulary.findOne({ id: String(source.vocabulary) });
|
|
962
|
+
return {
|
|
963
|
+
id: sourceId,
|
|
964
|
+
displayName: source.displayName,
|
|
965
|
+
scope: source.scope,
|
|
966
|
+
taxonomyId: source.taxonomyId,
|
|
967
|
+
vocabularyId: String(source.vocabulary),
|
|
968
|
+
vocabularyName: vocabulary?.name ?? '',
|
|
969
|
+
lastSyncedAt: source.lastSyncedAt ?? null,
|
|
970
|
+
archived: source.archived === true,
|
|
971
|
+
mirroredCount,
|
|
972
|
+
historicalCount,
|
|
973
|
+
crosswalkCount
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
async listSyncRuns(query, ctx) {
|
|
977
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset, 25);
|
|
978
|
+
const where = { branding: ctx.brandId };
|
|
979
|
+
const sourceId = String(query?.sourceId ?? '').trim();
|
|
980
|
+
if (sourceId) {
|
|
981
|
+
where.source = sourceId;
|
|
982
|
+
}
|
|
983
|
+
const total = await FigshareVocabularySyncRun.count(where);
|
|
984
|
+
const runs = await FigshareVocabularySyncRun.find(where)
|
|
985
|
+
.sort('createdAt DESC')
|
|
986
|
+
.skip(offset)
|
|
987
|
+
.limit(limit);
|
|
988
|
+
return {
|
|
989
|
+
data: runs.map((run) => ({
|
|
990
|
+
id: String(run.id),
|
|
991
|
+
state: run.state,
|
|
992
|
+
scope: run.scope,
|
|
993
|
+
taxonomyId: run.taxonomyId,
|
|
994
|
+
sourceId: run.source == null ? null : String(run.source),
|
|
995
|
+
summary: run.summary ?? {},
|
|
996
|
+
requestedBy: run.requestedBy,
|
|
997
|
+
appliedBy: run.appliedBy ?? null,
|
|
998
|
+
appliedAt: run.appliedAt ?? null,
|
|
999
|
+
expiresAt: run.expiresAt,
|
|
1000
|
+
errorCode: run.errorCode ?? null
|
|
1001
|
+
})),
|
|
1002
|
+
meta: { total, limit, offset }
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Create an independent editable local vocabulary from an existing mirror plus a
|
|
1007
|
+
* draft identity crosswalk. Later mirror synchronisation never edits clone terms.
|
|
1008
|
+
*/
|
|
1009
|
+
async cloneMirror(sourceId, cloneInput, ctx) {
|
|
1010
|
+
const source = await this.requireSource(sourceId, ctx.brandId);
|
|
1011
|
+
const categories = await FigshareVocabularyCategory.find({
|
|
1012
|
+
source: String(source.id),
|
|
1013
|
+
historical: false
|
|
1014
|
+
});
|
|
1015
|
+
if (categories.length === 0) {
|
|
1016
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('The Figshare mirror has no current categories to clone');
|
|
1017
|
+
}
|
|
1018
|
+
const snapshot = categories.map((category) => ({
|
|
1019
|
+
sourceId: category.sourceId,
|
|
1020
|
+
categoryId: category.categoryId,
|
|
1021
|
+
taxonomyId: category.taxonomyId,
|
|
1022
|
+
title: '',
|
|
1023
|
+
parentSourceId: category.parentSourceId ?? null,
|
|
1024
|
+
path: category.path ?? [category.sourceId],
|
|
1025
|
+
selectable: category.selectable !== false,
|
|
1026
|
+
hasChildren: false,
|
|
1027
|
+
contentHash: category.contentHash
|
|
1028
|
+
}));
|
|
1029
|
+
const entries = await VocabularyEntry.find({
|
|
1030
|
+
id: categories.map((category) => String(category.entry))
|
|
1031
|
+
});
|
|
1032
|
+
const labelByEntryId = new Map(entries.map((entry) => [String(entry.id), String(entry.label ?? '')]));
|
|
1033
|
+
for (const [index, category] of categories.entries()) {
|
|
1034
|
+
snapshot[index].title = labelByEntryId.get(String(category.entry)) ?? category.sourceId;
|
|
1035
|
+
}
|
|
1036
|
+
const createdIds = {
|
|
1037
|
+
vocabularies: [],
|
|
1038
|
+
sources: [],
|
|
1039
|
+
crosswalks: []
|
|
1040
|
+
};
|
|
1041
|
+
try {
|
|
1042
|
+
return await (0, TransactionUtils_1.runWithOptionalTransaction)(this.getDatastore(), async (connection) => {
|
|
1043
|
+
const clone = await this.createCloneVocabulary(String(cloneInput?.name ?? '').trim(), String(cloneInput?.slug ?? '').trim(), snapshot, ctx, connection);
|
|
1044
|
+
createdIds.vocabularies.push(clone.vocabularyId);
|
|
1045
|
+
const crosswalkName = await this.uniqueCrosswalkName(`${String(cloneInput.name).trim()} → ${source.displayName}`, ctx.brandId, connection);
|
|
1046
|
+
const crosswalk = await this.createOne(FigshareVocabularyCrosswalk.create({
|
|
1047
|
+
branding: ctx.brandId,
|
|
1048
|
+
name: crosswalkName,
|
|
1049
|
+
localVocabulary: clone.vocabularyId,
|
|
1050
|
+
figshareSource: String(source.id),
|
|
1051
|
+
status: 'draft',
|
|
1052
|
+
workingRevision: 1,
|
|
1053
|
+
updatedBy: ctx.userId
|
|
1054
|
+
}), connection);
|
|
1055
|
+
createdIds.crosswalks.push(String(crosswalk.id));
|
|
1056
|
+
const cloneEntries = Array.from(clone.entryBySourceId.entries()).map(([entrySourceId, entryId]) => ({
|
|
1057
|
+
id: entryId,
|
|
1058
|
+
label: '',
|
|
1059
|
+
labelLower: '',
|
|
1060
|
+
value: entrySourceId,
|
|
1061
|
+
valueLower: entrySourceId.toLowerCase(),
|
|
1062
|
+
sourceId: entrySourceId
|
|
1063
|
+
}));
|
|
1064
|
+
const identity = (0, categories_1.buildIdentityProposals)(cloneEntries, snapshot);
|
|
1065
|
+
const categoryBySourceId = new Map(categories.map((category) => [category.sourceId, category]));
|
|
1066
|
+
for (const proposal of identity.proposals) {
|
|
1067
|
+
const category = categoryBySourceId.get(proposal.targetSourceId);
|
|
1068
|
+
if (!category) {
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
await this.createOne(FigshareVocabularyCrosswalkMapping.create({
|
|
1072
|
+
crosswalk: String(crosswalk.id),
|
|
1073
|
+
revision: 1,
|
|
1074
|
+
localEntry: proposal.localEntryId,
|
|
1075
|
+
figshareCategory: String(category.id),
|
|
1076
|
+
status: 'proposed',
|
|
1077
|
+
matchType: 'identity'
|
|
1078
|
+
}), connection);
|
|
1079
|
+
}
|
|
1080
|
+
return {
|
|
1081
|
+
localVocabularyId: clone.vocabularyId,
|
|
1082
|
+
crosswalkId: String(crosswalk.id),
|
|
1083
|
+
entries: clone.entryBySourceId.size
|
|
1084
|
+
};
|
|
1085
|
+
}, {
|
|
1086
|
+
logger: sails.log,
|
|
1087
|
+
unsupportedAdapterWarning: 'Transactions are not supported by this datastore adapter. Falling back to compensating cleanup for Figshare clone.'
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
catch (error) {
|
|
1091
|
+
await this.compensate(createdIds);
|
|
1092
|
+
throw error;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
// ── Crosswalks ────────────────────────────────────────────────────
|
|
1096
|
+
async listCrosswalks(query, ctx) {
|
|
1097
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset, 25);
|
|
1098
|
+
const where = { branding: ctx.brandId };
|
|
1099
|
+
if (query?.status) {
|
|
1100
|
+
where.status = String(query.status);
|
|
1101
|
+
}
|
|
1102
|
+
if (query?.localVocabularyId) {
|
|
1103
|
+
where.localVocabulary = String(query.localVocabularyId);
|
|
1104
|
+
}
|
|
1105
|
+
if (query?.sourceId) {
|
|
1106
|
+
where.figshareSource = String(query.sourceId);
|
|
1107
|
+
}
|
|
1108
|
+
const search = String(query?.q ?? '').trim();
|
|
1109
|
+
if (search) {
|
|
1110
|
+
where.name = { contains: search };
|
|
1111
|
+
}
|
|
1112
|
+
const total = await FigshareVocabularyCrosswalk.count(where);
|
|
1113
|
+
const crosswalks = await FigshareVocabularyCrosswalk.find(where)
|
|
1114
|
+
.sort('name ASC')
|
|
1115
|
+
.skip(offset)
|
|
1116
|
+
.limit(limit);
|
|
1117
|
+
const data = await Promise.all(crosswalks.map((crosswalk) => this.describeCrosswalk(crosswalk)));
|
|
1118
|
+
return { data, meta: { total, limit, offset } };
|
|
1119
|
+
}
|
|
1120
|
+
async getCrosswalk(crosswalkId, ctx) {
|
|
1121
|
+
return this.describeCrosswalk(await this.requireCrosswalk(crosswalkId, ctx.brandId));
|
|
1122
|
+
}
|
|
1123
|
+
async describeCrosswalk(crosswalk) {
|
|
1124
|
+
const crosswalkId = String(crosswalk.id);
|
|
1125
|
+
const [localVocabulary, source] = await Promise.all([
|
|
1126
|
+
Vocabulary.findOne({ id: String(crosswalk.localVocabulary) }),
|
|
1127
|
+
FigshareVocabularySource.findOne({ id: String(crosswalk.figshareSource) })
|
|
1128
|
+
]);
|
|
1129
|
+
const [approvedMappingCount, workingMappingCount] = await Promise.all([
|
|
1130
|
+
crosswalk.approvedRevision == null
|
|
1131
|
+
? Promise.resolve(0)
|
|
1132
|
+
: FigshareVocabularyCrosswalkMapping.count({
|
|
1133
|
+
crosswalk: crosswalkId,
|
|
1134
|
+
revision: Number(crosswalk.approvedRevision),
|
|
1135
|
+
status: 'approved'
|
|
1136
|
+
}),
|
|
1137
|
+
FigshareVocabularyCrosswalkMapping.count({ crosswalk: crosswalkId, revision: Number(crosswalk.workingRevision) })
|
|
1138
|
+
]);
|
|
1139
|
+
const historicalTargetCount = await this.countHistoricalTargets(crosswalkId, crosswalk);
|
|
1140
|
+
return {
|
|
1141
|
+
id: crosswalkId,
|
|
1142
|
+
name: crosswalk.name,
|
|
1143
|
+
status: String(crosswalk.status),
|
|
1144
|
+
workingRevision: Number(crosswalk.workingRevision),
|
|
1145
|
+
approvedRevision: crosswalk.approvedRevision ?? null,
|
|
1146
|
+
approvedAt: crosswalk.approvedAt,
|
|
1147
|
+
approvedBy: crosswalk.approvedBy,
|
|
1148
|
+
localVocabularyId: String(crosswalk.localVocabulary),
|
|
1149
|
+
localVocabularyName: localVocabulary?.name ?? '',
|
|
1150
|
+
figshareSourceId: String(crosswalk.figshareSource),
|
|
1151
|
+
figshareSourceName: source?.displayName ?? '',
|
|
1152
|
+
scope: String(source?.scope ?? ''),
|
|
1153
|
+
taxonomyId: String(source?.taxonomyId ?? ''),
|
|
1154
|
+
approvedMappingCount,
|
|
1155
|
+
workingMappingCount,
|
|
1156
|
+
historicalTargetCount
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
async countHistoricalTargets(crosswalkId, crosswalk) {
|
|
1160
|
+
const revision = Number(crosswalk.approvedRevision ?? crosswalk.workingRevision);
|
|
1161
|
+
const mappings = await FigshareVocabularyCrosswalkMapping.find({
|
|
1162
|
+
crosswalk: crosswalkId,
|
|
1163
|
+
revision
|
|
1164
|
+
});
|
|
1165
|
+
if (mappings.length === 0) {
|
|
1166
|
+
return 0;
|
|
1167
|
+
}
|
|
1168
|
+
const categoryIds = Array.from(new Set(mappings.map((mapping) => String(mapping.figshareCategory))));
|
|
1169
|
+
return FigshareVocabularyCategory.count({ id: categoryIds, historical: true });
|
|
1170
|
+
}
|
|
1171
|
+
async createCrosswalk(input, ctx) {
|
|
1172
|
+
const name = String(input?.name ?? '').trim();
|
|
1173
|
+
if (!name) {
|
|
1174
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('name is required');
|
|
1175
|
+
}
|
|
1176
|
+
const localVocabulary = await this.requireLocalVocabulary(String(input?.localVocabularyId ?? ''), ctx.brandId);
|
|
1177
|
+
const source = await this.requireSource(String(input?.sourceId ?? ''), ctx.brandId);
|
|
1178
|
+
const existing = await FigshareVocabularyCrosswalk.findOne({ branding: ctx.brandId, name });
|
|
1179
|
+
if (existing) {
|
|
1180
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError(`A crosswalk named '${name}' already exists for this brand`);
|
|
1181
|
+
}
|
|
1182
|
+
const crosswalk = await FigshareVocabularyCrosswalk.create({
|
|
1183
|
+
branding: ctx.brandId,
|
|
1184
|
+
name,
|
|
1185
|
+
localVocabulary: String(localVocabulary.id),
|
|
1186
|
+
figshareSource: String(source.id),
|
|
1187
|
+
status: 'draft',
|
|
1188
|
+
workingRevision: 1,
|
|
1189
|
+
updatedBy: ctx.userId
|
|
1190
|
+
}).fetch();
|
|
1191
|
+
return this.describeCrosswalk(crosswalk);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Search the local vocabulary behind a crosswalk, annotated with how many targets
|
|
1195
|
+
* each term already has. Terms with no target never appear in the mapping table,
|
|
1196
|
+
* so this is the only way the manual picker can reach them.
|
|
1197
|
+
*/
|
|
1198
|
+
async listCrosswalkLocalEntries(crosswalkId, query, ctx) {
|
|
1199
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1200
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset, 25);
|
|
1201
|
+
const revision = Number(query?.revision ?? crosswalk.workingRevision);
|
|
1202
|
+
const [entries, mappings] = await Promise.all([
|
|
1203
|
+
VocabularyEntry.find({ vocabulary: String(crosswalk.localVocabulary) }),
|
|
1204
|
+
FigshareVocabularyCrosswalkMapping.find({
|
|
1205
|
+
crosswalk: String(crosswalk.id),
|
|
1206
|
+
revision
|
|
1207
|
+
})
|
|
1208
|
+
]);
|
|
1209
|
+
const targetCountByEntryId = new Map();
|
|
1210
|
+
for (const mapping of mappings) {
|
|
1211
|
+
const key = String(mapping.localEntry);
|
|
1212
|
+
targetCountByEntryId.set(key, (targetCountByEntryId.get(key) ?? 0) + 1);
|
|
1213
|
+
}
|
|
1214
|
+
const search = String(query?.q ?? '').trim().toLowerCase();
|
|
1215
|
+
const mappedFilter = String(query?.mapped ?? '').trim().toLowerCase();
|
|
1216
|
+
const rows = entries
|
|
1217
|
+
.map((entry) => ({
|
|
1218
|
+
id: String(entry.id),
|
|
1219
|
+
label: String(entry.label ?? ''),
|
|
1220
|
+
value: String(entry.value ?? ''),
|
|
1221
|
+
identifier: entry.identifier,
|
|
1222
|
+
historical: entry.historical === true,
|
|
1223
|
+
targetCount: targetCountByEntryId.get(String(entry.id)) ?? 0
|
|
1224
|
+
}))
|
|
1225
|
+
.filter((row) => !search || `${row.label} ${row.value}`.toLowerCase().includes(search))
|
|
1226
|
+
.filter((row) => {
|
|
1227
|
+
if (mappedFilter === 'unmapped') {
|
|
1228
|
+
return row.targetCount === 0;
|
|
1229
|
+
}
|
|
1230
|
+
if (mappedFilter === 'mapped') {
|
|
1231
|
+
return row.targetCount > 0;
|
|
1232
|
+
}
|
|
1233
|
+
return true;
|
|
1234
|
+
})
|
|
1235
|
+
.sort((left, right) => left.label.localeCompare(right.label));
|
|
1236
|
+
return {
|
|
1237
|
+
data: rows.slice(offset, offset + limit),
|
|
1238
|
+
meta: { total: rows.length, limit, offset, revision }
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
async listCrosswalkMappings(crosswalkId, query, ctx) {
|
|
1242
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1243
|
+
const { limit, offset } = this.parsePaging(query?.limit, query?.offset);
|
|
1244
|
+
const revision = Number(query?.revision ?? crosswalk.workingRevision);
|
|
1245
|
+
const where = { crosswalk: String(crosswalk.id), revision };
|
|
1246
|
+
if (query?.status) {
|
|
1247
|
+
where.status = String(query.status);
|
|
1248
|
+
}
|
|
1249
|
+
const mappings = await FigshareVocabularyCrosswalkMapping.find(where);
|
|
1250
|
+
const [entries, categories] = await Promise.all([
|
|
1251
|
+
mappings.length === 0
|
|
1252
|
+
? Promise.resolve([])
|
|
1253
|
+
: VocabularyEntry.find({ id: Array.from(new Set(mappings.map((mapping) => String(mapping.localEntry)))) }),
|
|
1254
|
+
mappings.length === 0
|
|
1255
|
+
? Promise.resolve([])
|
|
1256
|
+
: FigshareVocabularyCategory.find({ id: Array.from(new Set(mappings.map((mapping) => String(mapping.figshareCategory)))) })
|
|
1257
|
+
]);
|
|
1258
|
+
const entryById = new Map(entries.map((entry) => [String(entry.id), entry]));
|
|
1259
|
+
const categoryById = new Map(categories.map((category) => [String(category.id), category]));
|
|
1260
|
+
const search = String(query?.q ?? '').trim().toLowerCase();
|
|
1261
|
+
const rows = mappings
|
|
1262
|
+
.map((mapping) => {
|
|
1263
|
+
const entry = entryById.get(String(mapping.localEntry));
|
|
1264
|
+
const category = categoryById.get(String(mapping.figshareCategory));
|
|
1265
|
+
return {
|
|
1266
|
+
id: String(mapping.id),
|
|
1267
|
+
revision: mapping.revision,
|
|
1268
|
+
status: mapping.status,
|
|
1269
|
+
matchType: mapping.matchType,
|
|
1270
|
+
localEntryId: String(mapping.localEntry),
|
|
1271
|
+
localLabel: String(entry?.label ?? ''),
|
|
1272
|
+
localValue: String(entry?.value ?? ''),
|
|
1273
|
+
figshareCategoryId: String(mapping.figshareCategory),
|
|
1274
|
+
figshareSourceId: String(category?.sourceId ?? ''),
|
|
1275
|
+
figshareCategoryNumber: category?.categoryId ?? null,
|
|
1276
|
+
historical: category?.historical === true,
|
|
1277
|
+
approvedAt: mapping.approvedAt ?? null,
|
|
1278
|
+
approvedBy: mapping.approvedBy ?? null
|
|
1279
|
+
};
|
|
1280
|
+
})
|
|
1281
|
+
.filter((row) => !search || `${row.localLabel} ${row.localValue} ${row.figshareSourceId}`.toLowerCase().includes(search))
|
|
1282
|
+
.sort((left, right) => left.localLabel.localeCompare(right.localLabel));
|
|
1283
|
+
return {
|
|
1284
|
+
data: rows.slice(offset, offset + limit),
|
|
1285
|
+
meta: { total: rows.length, limit, offset, revision }
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Batch upsert/delete mapping edges under optimistic revision control. The first
|
|
1290
|
+
* edit of an approved crosswalk copies the approved rows into a new working
|
|
1291
|
+
* revision so publishing continues against the previous approved snapshot.
|
|
1292
|
+
*/
|
|
1293
|
+
async saveMappings(crosswalkId, input, ctx) {
|
|
1294
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1295
|
+
const changes = input?.changes ?? [];
|
|
1296
|
+
if (changes.length > MAX_MAPPING_BATCH) {
|
|
1297
|
+
throw new vocabulary_errors_1.CatalogueInvalidError(`changes exceeds the maximum batch size of ${MAX_MAPPING_BATCH}`);
|
|
1298
|
+
}
|
|
1299
|
+
if (Number(input?.revision) !== Number(crosswalk.workingRevision)) {
|
|
1300
|
+
throw new vocabulary_errors_1.CrosswalkRevisionError();
|
|
1301
|
+
}
|
|
1302
|
+
return (0, TransactionUtils_1.runWithOptionalTransaction)(this.getDatastore(), async (connection) => {
|
|
1303
|
+
let workingRevision = Number(crosswalk.workingRevision);
|
|
1304
|
+
if (crosswalk.approvedRevision != null && Number(crosswalk.approvedRevision) === workingRevision) {
|
|
1305
|
+
workingRevision += 1;
|
|
1306
|
+
const approvedRows = await this.runQuery(FigshareVocabularyCrosswalkMapping.find({
|
|
1307
|
+
crosswalk: String(crosswalk.id),
|
|
1308
|
+
revision: Number(crosswalk.approvedRevision)
|
|
1309
|
+
}), connection);
|
|
1310
|
+
for (const row of approvedRows) {
|
|
1311
|
+
await this.createOne(FigshareVocabularyCrosswalkMapping.create({
|
|
1312
|
+
crosswalk: String(crosswalk.id),
|
|
1313
|
+
revision: workingRevision,
|
|
1314
|
+
localEntry: String(row.localEntry),
|
|
1315
|
+
figshareCategory: String(row.figshareCategory),
|
|
1316
|
+
status: row.status,
|
|
1317
|
+
matchType: row.matchType,
|
|
1318
|
+
evidence: row.evidence,
|
|
1319
|
+
approvedAt: row.approvedAt,
|
|
1320
|
+
approvedBy: row.approvedBy
|
|
1321
|
+
}), connection);
|
|
1322
|
+
}
|
|
1323
|
+
await this.runQuery(FigshareVocabularyCrosswalk.updateOne({ id: String(crosswalk.id) }).set({ workingRevision }), connection);
|
|
1324
|
+
}
|
|
1325
|
+
for (const change of changes) {
|
|
1326
|
+
const localEntryId = String(change?.localEntryId ?? '').trim();
|
|
1327
|
+
const figshareCategoryId = String(change?.figshareCategoryId ?? '').trim();
|
|
1328
|
+
if (!localEntryId || !figshareCategoryId) {
|
|
1329
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('Each change requires localEntryId and figshareCategoryId');
|
|
1330
|
+
}
|
|
1331
|
+
await this.assertMappingOwnership(crosswalk, localEntryId, figshareCategoryId, connection);
|
|
1332
|
+
if (change.op === 'remove') {
|
|
1333
|
+
await this.runQuery(FigshareVocabularyCrosswalkMapping.destroy({
|
|
1334
|
+
crosswalk: String(crosswalk.id),
|
|
1335
|
+
revision: workingRevision,
|
|
1336
|
+
localEntry: localEntryId,
|
|
1337
|
+
figshareCategory: figshareCategoryId
|
|
1338
|
+
}), connection);
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
const existing = await this.runQuery(FigshareVocabularyCrosswalkMapping.findOne({
|
|
1342
|
+
crosswalk: String(crosswalk.id),
|
|
1343
|
+
revision: workingRevision,
|
|
1344
|
+
localEntry: localEntryId,
|
|
1345
|
+
figshareCategory: figshareCategoryId
|
|
1346
|
+
}), connection);
|
|
1347
|
+
const status = change.status ?? 'proposed';
|
|
1348
|
+
const approvalPatch = status === 'approved'
|
|
1349
|
+
? { approvedAt: this.nowIso(), approvedBy: ctx.userId }
|
|
1350
|
+
: { approvedAt: undefined, approvedBy: undefined };
|
|
1351
|
+
if (existing) {
|
|
1352
|
+
await this.runQuery(FigshareVocabularyCrosswalkMapping.updateOne({ id: String(existing.id) }).set({
|
|
1353
|
+
status,
|
|
1354
|
+
matchType: change.matchType ?? existing.matchType,
|
|
1355
|
+
...approvalPatch
|
|
1356
|
+
}), connection);
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
await this.createOne(FigshareVocabularyCrosswalkMapping.create({
|
|
1360
|
+
crosswalk: String(crosswalk.id),
|
|
1361
|
+
revision: workingRevision,
|
|
1362
|
+
localEntry: localEntryId,
|
|
1363
|
+
figshareCategory: figshareCategoryId,
|
|
1364
|
+
status,
|
|
1365
|
+
matchType: change.matchType ?? 'manual',
|
|
1366
|
+
...approvalPatch
|
|
1367
|
+
}), connection);
|
|
1368
|
+
}
|
|
1369
|
+
await this.runQuery(FigshareVocabularyCrosswalk.updateOne({ id: String(crosswalk.id) }).set({ updatedBy: ctx.userId }), connection);
|
|
1370
|
+
const refreshed = await this.runQuery(FigshareVocabularyCrosswalk.findOne({ id: String(crosswalk.id) }), connection);
|
|
1371
|
+
return this.describeCrosswalk(refreshed ?? crosswalk);
|
|
1372
|
+
}, {
|
|
1373
|
+
logger: sails.log,
|
|
1374
|
+
unsupportedAdapterWarning: 'Transactions are not supported by this datastore adapter. Falling back to non-transactional crosswalk mapping save.'
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
async assertMappingOwnership(crosswalk, localEntryId, figshareCategoryId, connection) {
|
|
1378
|
+
const entry = await this.runQuery(VocabularyEntry.findOne({ id: localEntryId, vocabulary: String(crosswalk.localVocabulary) }), connection);
|
|
1379
|
+
if (!entry) {
|
|
1380
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('The local entry does not belong to the crosswalk local vocabulary');
|
|
1381
|
+
}
|
|
1382
|
+
const category = await this.runQuery(FigshareVocabularyCategory.findOne({ id: figshareCategoryId, source: String(crosswalk.figshareSource) }), connection);
|
|
1383
|
+
if (!category) {
|
|
1384
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('The Figshare category does not belong to the crosswalk source');
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Promote the working revision to the approved revision. AppConfig keeps its stable
|
|
1389
|
+
* crosswalkId; publishing immediately follows the newly approved revision.
|
|
1390
|
+
*/
|
|
1391
|
+
async approveCrosswalk(crosswalkId, revision, ctx) {
|
|
1392
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1393
|
+
if (Number(revision) !== Number(crosswalk.workingRevision)) {
|
|
1394
|
+
throw new vocabulary_errors_1.CrosswalkRevisionError();
|
|
1395
|
+
}
|
|
1396
|
+
const mappings = await FigshareVocabularyCrosswalkMapping.find({
|
|
1397
|
+
crosswalk: String(crosswalk.id),
|
|
1398
|
+
revision: Number(crosswalk.workingRevision)
|
|
1399
|
+
});
|
|
1400
|
+
const approvable = mappings.filter((mapping) => mapping.status !== 'rejected');
|
|
1401
|
+
if (approvable.length === 0) {
|
|
1402
|
+
throw new vocabulary_errors_1.CatalogueInvalidError('A crosswalk revision must contain at least one mapping before it can be approved');
|
|
1403
|
+
}
|
|
1404
|
+
const approvedAt = this.nowIso();
|
|
1405
|
+
return (0, TransactionUtils_1.runWithOptionalTransaction)(this.getDatastore(), async (connection) => {
|
|
1406
|
+
for (const mapping of approvable) {
|
|
1407
|
+
await this.assertMappingOwnership(crosswalk, String(mapping.localEntry), String(mapping.figshareCategory), connection);
|
|
1408
|
+
if (mapping.status === 'approved') {
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
await this.runQuery(FigshareVocabularyCrosswalkMapping.updateOne({ id: String(mapping.id) }).set({
|
|
1412
|
+
status: 'approved',
|
|
1413
|
+
approvedAt,
|
|
1414
|
+
approvedBy: ctx.userId
|
|
1415
|
+
}), connection);
|
|
1416
|
+
}
|
|
1417
|
+
await this.runQuery(FigshareVocabularyCrosswalk.updateOne({ id: String(crosswalk.id) }).set({
|
|
1418
|
+
status: 'approved',
|
|
1419
|
+
approvedRevision: Number(crosswalk.workingRevision),
|
|
1420
|
+
approvedAt,
|
|
1421
|
+
approvedBy: ctx.userId,
|
|
1422
|
+
updatedBy: ctx.userId
|
|
1423
|
+
}), connection);
|
|
1424
|
+
const refreshed = await this.runQuery(FigshareVocabularyCrosswalk.findOne({ id: String(crosswalk.id) }), connection);
|
|
1425
|
+
return this.describeCrosswalk(refreshed ?? crosswalk);
|
|
1426
|
+
}, {
|
|
1427
|
+
logger: sails.log,
|
|
1428
|
+
unsupportedAdapterWarning: 'Transactions are not supported by this datastore adapter. Falling back to non-transactional crosswalk approval.'
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Collect the dotted paths of every crosswalk binding in a config that selects
|
|
1433
|
+
* `crosswalkId`. A crosswalk can now be referenced by any binding, not just the
|
|
1434
|
+
* categories one, so the whole config tree has to be walked.
|
|
1435
|
+
*/
|
|
1436
|
+
collectCrosswalkBindings(node, crosswalkId, pathSegments, found) {
|
|
1437
|
+
if (node == null || typeof node !== 'object') {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
if (Array.isArray(node)) {
|
|
1441
|
+
node.forEach((item, index) => this.collectCrosswalkBindings(item, crosswalkId, [...pathSegments, String(index)], found));
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const candidate = node;
|
|
1445
|
+
if (candidate.kind === 'crosswalk' && String(candidate.crosswalkId ?? '') === crosswalkId) {
|
|
1446
|
+
found.push({
|
|
1447
|
+
bindingPath: pathSegments.join('.'),
|
|
1448
|
+
outputs: candidate.outputs == null ? undefined : String(candidate.outputs),
|
|
1449
|
+
sourceVocabularyId: candidate.sourceVocabularyId == null ? undefined : String(candidate.sourceVocabularyId)
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
for (const [key, value] of Object.entries(candidate)) {
|
|
1453
|
+
this.collectCrosswalkBindings(value, crosswalkId, [...pathSegments, key], found);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
/** Report the Figshare publishing bindings that select this crosswalk. */
|
|
1457
|
+
async getCrosswalkUsage(crosswalkId, ctx) {
|
|
1458
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1459
|
+
const appConfigService = sails.services?.appconfigservice;
|
|
1460
|
+
const brandName = this.resolveBrandName(ctx.brandId);
|
|
1461
|
+
const brandConfig = appConfigService?.getAppConfigurationForBrand?.(brandName);
|
|
1462
|
+
const figsharePublishing = brandConfig?.figsharePublishing;
|
|
1463
|
+
const found = [];
|
|
1464
|
+
this.collectCrosswalkBindings(figsharePublishing, String(crosswalk.id), [], found);
|
|
1465
|
+
return found.map((binding) => ({
|
|
1466
|
+
brandName,
|
|
1467
|
+
configKey: 'figsharePublishing',
|
|
1468
|
+
bindingPath: binding.bindingPath,
|
|
1469
|
+
outputs: binding.outputs,
|
|
1470
|
+
sourceVocabularyId: binding.sourceVocabularyId
|
|
1471
|
+
}));
|
|
1472
|
+
}
|
|
1473
|
+
/** Draft crosswalks are deleted; approved ones archive to protect AppConfig references. */
|
|
1474
|
+
async deleteCrosswalk(crosswalkId, ctx) {
|
|
1475
|
+
const crosswalk = await this.requireCrosswalk(crosswalkId, ctx.brandId);
|
|
1476
|
+
const usage = await this.getCrosswalkUsage(crosswalkId, ctx);
|
|
1477
|
+
if (usage.length > 0) {
|
|
1478
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('This crosswalk is selected by a Figshare publishing configuration. Remove or replace the reference first.');
|
|
1479
|
+
}
|
|
1480
|
+
if (crosswalk.status === 'approved') {
|
|
1481
|
+
await FigshareVocabularyCrosswalk.updateOne({ id: String(crosswalk.id) }).set({
|
|
1482
|
+
status: 'archived',
|
|
1483
|
+
updatedBy: ctx.userId
|
|
1484
|
+
});
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
await FigshareVocabularyCrosswalkMapping.destroy({ crosswalk: String(crosswalk.id) });
|
|
1488
|
+
await FigshareVocabularyCrosswalk.destroyOne({ id: String(crosswalk.id) });
|
|
1489
|
+
}
|
|
1490
|
+
// ── Publishing resolution ─────────────────────────────────────────
|
|
1491
|
+
/**
|
|
1492
|
+
* Resolve record codes to the Figshare categories they map to through the
|
|
1493
|
+
* approved revision of a crosswalk. Working revisions are never consulted.
|
|
1494
|
+
*
|
|
1495
|
+
* Shared by every output mode: the caller decides whether to emit the numeric
|
|
1496
|
+
* category ID, the mirrored label, or the Figshare source ID.
|
|
1497
|
+
*/
|
|
1498
|
+
async resolveCrosswalkTargets(input) {
|
|
1499
|
+
const crosswalk = await this.requireCrosswalk(String(input?.crosswalkId ?? ''), String(input?.brandId ?? ''));
|
|
1500
|
+
if (crosswalk.status !== 'approved' || crosswalk.approvedRevision == null) {
|
|
1501
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('The configured Figshare crosswalk has no approved revision');
|
|
1502
|
+
}
|
|
1503
|
+
const sourceVocabularyId = String(input?.sourceVocabularyId ?? '').trim();
|
|
1504
|
+
if (!sourceVocabularyId || String(crosswalk.localVocabulary) !== sourceVocabularyId) {
|
|
1505
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('The configured Figshare crosswalk maps a different local vocabulary');
|
|
1506
|
+
}
|
|
1507
|
+
const source = await FigshareVocabularySource.findOne({
|
|
1508
|
+
id: String(crosswalk.figshareSource),
|
|
1509
|
+
branding: String(input.brandId)
|
|
1510
|
+
});
|
|
1511
|
+
if (!source || source.archived === true) {
|
|
1512
|
+
throw new vocabulary_errors_1.RelationshipBoundaryError('The Figshare source behind the configured crosswalk is unavailable');
|
|
1513
|
+
}
|
|
1514
|
+
const codes = Array.from(new Set((input?.codes ?? []).map((code) => (0, categories_1.normalizeCategoryCode)(code)).filter((code) => code !== '')));
|
|
1515
|
+
if (codes.length === 0) {
|
|
1516
|
+
return { normalizedCodes: [], matches: [], unresolvedCodes: [], historicalTargets: [] };
|
|
1517
|
+
}
|
|
1518
|
+
const entries = await VocabularyEntry.find({ vocabulary: sourceVocabularyId });
|
|
1519
|
+
const entryByCode = new Map();
|
|
1520
|
+
for (const entry of entries) {
|
|
1521
|
+
const valueCode = (0, categories_1.normalizeCategoryCode)(entry.valueLower ?? entry.value);
|
|
1522
|
+
if (valueCode !== '' && !entryByCode.has(valueCode)) {
|
|
1523
|
+
entryByCode.set(valueCode, entry);
|
|
1524
|
+
}
|
|
1525
|
+
const identifierCode = (0, categories_1.normalizeCategoryCode)(entry.identifier);
|
|
1526
|
+
if (identifierCode !== '' && !entryByCode.has(identifierCode)) {
|
|
1527
|
+
entryByCode.set(identifierCode, entry);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
const unresolvedCodes = [];
|
|
1531
|
+
const matchedEntryIdsByCode = new Map();
|
|
1532
|
+
for (const code of codes) {
|
|
1533
|
+
const entry = entryByCode.get(code);
|
|
1534
|
+
if (!entry) {
|
|
1535
|
+
unresolvedCodes.push(code);
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
matchedEntryIdsByCode.set(code, String(entry.id));
|
|
1539
|
+
}
|
|
1540
|
+
if (matchedEntryIdsByCode.size === 0) {
|
|
1541
|
+
return { normalizedCodes: codes, matches: [], unresolvedCodes, historicalTargets: [] };
|
|
1542
|
+
}
|
|
1543
|
+
const mappings = await FigshareVocabularyCrosswalkMapping.find({
|
|
1544
|
+
crosswalk: String(crosswalk.id),
|
|
1545
|
+
revision: Number(crosswalk.approvedRevision),
|
|
1546
|
+
status: 'approved',
|
|
1547
|
+
localEntry: Array.from(new Set(matchedEntryIdsByCode.values()))
|
|
1548
|
+
});
|
|
1549
|
+
if (mappings.length === 0) {
|
|
1550
|
+
return {
|
|
1551
|
+
normalizedCodes: codes,
|
|
1552
|
+
matches: [],
|
|
1553
|
+
unresolvedCodes: [...unresolvedCodes, ...matchedEntryIdsByCode.keys()],
|
|
1554
|
+
historicalTargets: []
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
const categories = await FigshareVocabularyCategory.find({
|
|
1558
|
+
id: Array.from(new Set(mappings.map((mapping) => String(mapping.figshareCategory))))
|
|
1559
|
+
});
|
|
1560
|
+
const categoryById = new Map(categories.map((category) => [String(category.id), category]));
|
|
1561
|
+
const mappingsByEntryId = new Map();
|
|
1562
|
+
for (const mapping of mappings) {
|
|
1563
|
+
const entryId = String(mapping.localEntry);
|
|
1564
|
+
const bucket = mappingsByEntryId.get(entryId);
|
|
1565
|
+
if (bucket) {
|
|
1566
|
+
bucket.push(mapping);
|
|
1567
|
+
}
|
|
1568
|
+
else {
|
|
1569
|
+
mappingsByEntryId.set(entryId, [mapping]);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
// Walk in code order so every output mode returns a deterministic sequence
|
|
1573
|
+
// that follows the record's own ordering.
|
|
1574
|
+
const matches = [];
|
|
1575
|
+
const historicalTargets = [];
|
|
1576
|
+
for (const [code, entryId] of matchedEntryIdsByCode) {
|
|
1577
|
+
let resolved = false;
|
|
1578
|
+
for (const mapping of mappingsByEntryId.get(entryId) ?? []) {
|
|
1579
|
+
const category = categoryById.get(String(mapping.figshareCategory));
|
|
1580
|
+
if (!category) {
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1583
|
+
resolved = true;
|
|
1584
|
+
if (category.historical === true) {
|
|
1585
|
+
historicalTargets.push({ code, categoryId: category.categoryId, sourceId: category.sourceId });
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
matches.push({ code, category });
|
|
1589
|
+
}
|
|
1590
|
+
if (!resolved) {
|
|
1591
|
+
unresolvedCodes.push(code);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return { normalizedCodes: codes, matches, unresolvedCodes, historicalTargets };
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Resolve record category codes to numeric Figshare category IDs. Retained as
|
|
1598
|
+
* the stable narrow surface over {@link resolveCrosswalkValues}.
|
|
1599
|
+
*/
|
|
1600
|
+
async resolveCategories(input) {
|
|
1601
|
+
const resolution = await this.resolveCrosswalkTargets(input);
|
|
1602
|
+
const categoryIds = new Set(resolution.matches.map((match) => match.category.categoryId));
|
|
1603
|
+
return {
|
|
1604
|
+
categoryIds: Array.from(categoryIds).sort((left, right) => left - right),
|
|
1605
|
+
unresolvedCodes: resolution.unresolvedCodes,
|
|
1606
|
+
historicalTargets: resolution.historicalTargets
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
/**
|
|
1610
|
+
* Resolve record codes through a crosswalk into the values a publishing binding
|
|
1611
|
+
* asks for. Historical targets are excluded from `values` in every mode and
|
|
1612
|
+
* reported separately so the caller can decide whether they are fatal.
|
|
1613
|
+
*/
|
|
1614
|
+
async resolveCrosswalkValues(input) {
|
|
1615
|
+
const outputs = input?.outputs || 'categoryId';
|
|
1616
|
+
const resolution = await this.resolveCrosswalkTargets(input);
|
|
1617
|
+
const base = {
|
|
1618
|
+
normalizedCodes: resolution.normalizedCodes,
|
|
1619
|
+
unresolvedCodes: resolution.unresolvedCodes,
|
|
1620
|
+
historicalTargets: resolution.historicalTargets
|
|
1621
|
+
};
|
|
1622
|
+
if (outputs === 'categoryId') {
|
|
1623
|
+
const categoryIds = new Set(resolution.matches.map((match) => match.category.categoryId));
|
|
1624
|
+
return { ...base, values: Array.from(categoryIds).sort((left, right) => left - right) };
|
|
1625
|
+
}
|
|
1626
|
+
if (outputs === 'sourceId') {
|
|
1627
|
+
return { ...base, values: Array.from(new Set(resolution.matches.map((match) => match.category.sourceId))) };
|
|
1628
|
+
}
|
|
1629
|
+
// Labels live on the mirrored VocabularyEntry, not on the category row.
|
|
1630
|
+
const entryIds = Array.from(new Set(resolution.matches.map((match) => String(match.category.entry))));
|
|
1631
|
+
const entries = entryIds.length === 0
|
|
1632
|
+
? []
|
|
1633
|
+
: await VocabularyEntry.find({ id: entryIds });
|
|
1634
|
+
const labelByEntryId = new Map(entries.map((entry) => [String(entry.id), entry.label]));
|
|
1635
|
+
const labels = new Set();
|
|
1636
|
+
for (const match of resolution.matches) {
|
|
1637
|
+
const label = String(labelByEntryId.get(String(match.category.entry)) ?? '').trim();
|
|
1638
|
+
if (label !== '') {
|
|
1639
|
+
labels.add(label);
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
// The mapping resolved; only the display label is missing. Falling back to
|
|
1643
|
+
// the source ID keeps the value usable rather than silently dropping it.
|
|
1644
|
+
sails.log.warn(`Figshare crosswalk ${input.crosswalkId}: category ${match.category.sourceId} has no mirrored label, using its source ID`);
|
|
1645
|
+
labels.add(match.category.sourceId);
|
|
1646
|
+
}
|
|
1647
|
+
return { ...base, values: Array.from(labels) };
|
|
1648
|
+
}
|
|
1649
|
+
// ── Bootstrap data ────────────────────────────────────────────────
|
|
1650
|
+
getBootstrapDataPath() {
|
|
1651
|
+
const configuredPath = lodash_1.default.get(sails.config, 'bootstrap.bootstrapDataPath', DEFAULT_BOOTSTRAP_DATA_PATH);
|
|
1652
|
+
return path.resolve(String(configuredPath), 'vocabularies');
|
|
1653
|
+
}
|
|
1654
|
+
/** Overridable seam so unit tests can drive bootstrapData() without touching disk. */
|
|
1655
|
+
getBootstrapFileOps() {
|
|
1656
|
+
return fs;
|
|
1657
|
+
}
|
|
1658
|
+
resolveDefaultBrandingId() {
|
|
1659
|
+
const brandingService = sails.services?.brandingservice;
|
|
1660
|
+
const defaultBrand = brandingService?.getDefault?.();
|
|
1661
|
+
if (defaultBrand && typeof defaultBrand === 'object') {
|
|
1662
|
+
const brand = defaultBrand;
|
|
1663
|
+
const id = brand.id ?? brand._id;
|
|
1664
|
+
if (id != null && String(id).trim() !== '') {
|
|
1665
|
+
return String(id).trim();
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
return '';
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Declaratively import Figshare taxonomies listed in
|
|
1672
|
+
* `<bootstrapDataPath>/vocabularies/figshare-imports.json` during the Sails lift.
|
|
1673
|
+
*
|
|
1674
|
+
* Each item produces a read-only mirror, an editable local clone, and an approved
|
|
1675
|
+
* identity crosswalk - the state a fresh environment needs for Figshare publishing to
|
|
1676
|
+
* resolve categories without an administrator visiting the admin UI.
|
|
1677
|
+
*
|
|
1678
|
+
* Idempotent: an item whose FigshareVocabularySource already exists is skipped, so a
|
|
1679
|
+
* restart never re-syncs or forks admin-curated crosswalks. Nothing here throws - a
|
|
1680
|
+
* bootstrap importer must not be able to fail the lift.
|
|
1681
|
+
*/
|
|
1682
|
+
async bootstrapData() {
|
|
1683
|
+
if (lodash_1.default.get(sails.config, 'vocab.bootstrapFigshareImports') === false) {
|
|
1684
|
+
sails.log.verbose('Skipping Figshare vocabulary bootstrap imports (disabled)');
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
const filePath = path.join(this.getBootstrapDataPath(), FIGSHARE_IMPORTS_FILE);
|
|
1688
|
+
let parsed = null;
|
|
1689
|
+
try {
|
|
1690
|
+
const content = await this.getBootstrapFileOps().readFile(filePath, 'utf8');
|
|
1691
|
+
parsed = JSON.parse(content);
|
|
1692
|
+
}
|
|
1693
|
+
catch (error) {
|
|
1694
|
+
const ioError = error;
|
|
1695
|
+
if (ioError?.code === 'ENOENT') {
|
|
1696
|
+
sails.log.verbose(`Figshare vocabulary bootstrap file not found: ${filePath}`);
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
sails.log.error(`Failed to read Figshare vocabulary bootstrap file: ${FIGSHARE_IMPORTS_FILE}`, error);
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
if (!Array.isArray(parsed?.imports)) {
|
|
1703
|
+
sails.log.error(`Invalid Figshare imports format in bootstrap file: ${FIGSHARE_IMPORTS_FILE}`);
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
const imports = parsed.imports;
|
|
1707
|
+
if (imports.length === 0) {
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
const brandId = this.resolveDefaultBrandingId();
|
|
1711
|
+
if (!brandId) {
|
|
1712
|
+
sails.log.error('Unable to resolve default branding for Figshare vocabulary bootstrap data');
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
// Most deployments have no Figshare configuration at all; resolveClient() would throw
|
|
1716
|
+
// a transport error on every lift, so check first and skip quietly instead.
|
|
1717
|
+
if ((0, config_1.resolveFigshareVocabularyConfig)(this.resolveBrandName(brandId)) == null) {
|
|
1718
|
+
sails.log.verbose('Skipping Figshare vocabulary bootstrap imports: Figshare is not configured for the default brand');
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
const ctx = { brandId, userId: BOOTSTRAP_ACTOR };
|
|
1722
|
+
for (const item of imports) {
|
|
1723
|
+
await this.processBootstrapImport(item, ctx);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
async processBootstrapImport(item, ctx) {
|
|
1727
|
+
const scope = String(item?.scope ?? '').trim().toLowerCase();
|
|
1728
|
+
const taxonomyId = String(item?.taxonomyId ?? '').trim();
|
|
1729
|
+
const localCloneName = String(item?.localCloneName ?? '').trim();
|
|
1730
|
+
const label = `${scope || '?'}:${taxonomyId || '?'}`;
|
|
1731
|
+
if (scope !== 'public' && scope !== 'account') {
|
|
1732
|
+
sails.log.error(`Skipping Figshare bootstrap import with invalid scope '${item?.scope}' (expected 'public' or 'account')`);
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
if (!taxonomyId) {
|
|
1736
|
+
sails.log.error('Skipping Figshare bootstrap import with missing taxonomyId');
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
if (!localCloneName) {
|
|
1740
|
+
sails.log.error(`Skipping Figshare bootstrap import with missing localCloneName: ${label}`);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
const existing = await FigshareVocabularySource.findOne({
|
|
1744
|
+
branding: ctx.brandId,
|
|
1745
|
+
scope,
|
|
1746
|
+
taxonomyId
|
|
1747
|
+
});
|
|
1748
|
+
if (existing) {
|
|
1749
|
+
sails.log.verbose(`Skipping existing Figshare bootstrap import: ${label}`);
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
try {
|
|
1753
|
+
await (0, PromiseUtils_1.promiseWithTimeout)(this.runBootstrapImport({ scope, taxonomyId, localCloneName, item }, ctx), FIGSHARE_IMPORT_TIMEOUT_MS, `Figshare vocabulary import ${label}`);
|
|
1754
|
+
sails.log.verbose(`Imported Figshare bootstrap vocabulary: ${label}`);
|
|
1755
|
+
}
|
|
1756
|
+
catch (error) {
|
|
1757
|
+
sails.log.error(`Failed Figshare bootstrap import: ${label}`, error);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
async runBootstrapImport(input, ctx) {
|
|
1761
|
+
const localCloneSlug = String(input.item?.localCloneSlug ?? '').trim();
|
|
1762
|
+
const preview = await this.createPreview({
|
|
1763
|
+
scope: input.scope,
|
|
1764
|
+
taxonomyId: input.taxonomyId,
|
|
1765
|
+
createLocalClone: true,
|
|
1766
|
+
localCloneName: input.localCloneName,
|
|
1767
|
+
localCloneSlug: localCloneSlug || undefined
|
|
1768
|
+
}, ctx);
|
|
1769
|
+
// Read the run row directly rather than paging getPreview(), which caps at
|
|
1770
|
+
// MAX_PAGE_SIZE per page - a real taxonomy has thousands of categories. In clone
|
|
1771
|
+
// mode every proposal is an identity match and preselected.
|
|
1772
|
+
const run = await FigshareVocabularySyncRun.findOne({ id: preview.runId });
|
|
1773
|
+
const proposals = (run?.proposals ?? []);
|
|
1774
|
+
const approvedProposalIds = proposals
|
|
1775
|
+
.filter((proposal) => proposal.preselected)
|
|
1776
|
+
.map((proposal) => proposal.proposalId);
|
|
1777
|
+
const result = await this.applyPreview(preview.runId, {
|
|
1778
|
+
remoteHash: preview.remoteHash,
|
|
1779
|
+
approvedProposalIds
|
|
1780
|
+
}, ctx);
|
|
1781
|
+
const crosswalkId = String(result.crosswalkId ?? '');
|
|
1782
|
+
if (!crosswalkId) {
|
|
1783
|
+
throw new Error('Figshare bootstrap import did not produce a crosswalk');
|
|
1784
|
+
}
|
|
1785
|
+
const requestedName = String(input.item?.crosswalkName ?? '').trim();
|
|
1786
|
+
if (requestedName) {
|
|
1787
|
+
// { branding, name } is a unique index, so probe before renaming.
|
|
1788
|
+
const name = await this.uniqueCrosswalkName(requestedName, ctx.brandId);
|
|
1789
|
+
await FigshareVocabularyCrosswalk.updateOne({ id: crosswalkId }).set({
|
|
1790
|
+
name,
|
|
1791
|
+
updatedBy: ctx.userId
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
// Mapping edges are written as 'proposed' and resolveCategories() refuses any
|
|
1795
|
+
// crosswalk without an approved revision - approving here is what makes the
|
|
1796
|
+
// bootstrapped crosswalk usable for publishing.
|
|
1797
|
+
await this.approveCrosswalk(crosswalkId, Number(result.crosswalkRevision ?? 1), ctx);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
Services.FigshareVocabularyService = FigshareVocabularyService;
|
|
1801
|
+
})(Services || (exports.Services = Services = {}));
|
|
1802
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlnc2hhcmVWb2NhYnVsYXJ5U2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9GaWdzaGFyZVZvY2FidWxhcnlTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGdEQUFzRDtBQVV0RCw2RkFBMkY7QUFDM0Ysb0VBQTJFO0FBQzNFLDREQUErRDtBQUMvRCxxREFBdUM7QUFDdkMsZ0RBQWtDO0FBQ2xDLG9EQUF1QjtBQUN2QixpREFBdUU7QUFFdkUsNkNBQTBGO0FBRTFGLHlEQWtCa0M7QUFDbEMsdUVBT3lDO0FBRXpDLElBQWlCLFFBQVEsQ0FrM0V4QjtBQWwzRUQsV0FBaUIsUUFBUTtJQUN2QixNQUFNLGNBQWMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDM0MsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUM7SUFDL0IsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDO0lBQzFCLE1BQU0sMkJBQTJCLEdBQUcsZ0JBQWdCLENBQUM7SUFDckQsTUFBTSxxQkFBcUIsR0FBRyx1QkFBdUIsQ0FBQztJQUN0RCxNQUFNLDBCQUEwQixHQUFHLE9BQU8sQ0FBQztJQUMzQyxNQUFNLGVBQWUsR0FBRyxnQkFBZ0IsQ0FBQztJQStNekMsTUFBYSx5QkFBMEIsU0FBUSxzQkFBUSxDQUFDLElBQUksQ0FBQyxPQUFPO1FBQy9DLGdCQUFnQixHQUFhO1lBQzlDLG9CQUFvQjtZQUNwQixlQUFlO1lBQ2YsWUFBWTtZQUNaLGNBQWM7WUFDZCxhQUFhO1lBQ2IsYUFBYTtZQUNiLFdBQVc7WUFDWCxzQkFBc0I7WUFDdEIsY0FBYztZQUNkLGdCQUFnQjtZQUNoQixjQUFjO1lBQ2QsbUJBQW1CO1lBQ25CLGlCQUFpQjtZQUNqQiwyQkFBMkI7WUFDM0IsdUJBQXVCO1lBQ3ZCLGNBQWM7WUFDZCxrQkFBa0I7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
|