diff --git a/src/locales/de.json b/src/locales/de.json index e1349a3e..3ddc60a3 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -234,7 +234,8 @@ "packageNotExist": "Ein Paket mit dieser UUID existiert anscheinend nicht in der gewählten Importquelle", "packageExists": "Ein Paket mit diesem Namen existiert bereits in der GOKB. Prüfen Sie bitte, ob es sich um das selbe Paket handelt.", "platformExists": "Die Plattform ist in dieser Form noch nicht in der GOKB vorhanden. Wählen Sie in dem Suchfeld entweder eine schon existierende Plattform oder übernehmen Sie die Plattform von der Importquelle.", - "providerExists": "Der Anbieter des Pakets ist in dieser Form noch nicht in der GOKB vorhanden. Wählen Sie in dem Suchfeld entweder einen schon existierenden Anbieter oder übernehmen Sie den Anbieter von der Importquelle." + "providerExists": "Der Anbieter des Pakets ist in dieser Form noch nicht in der GOKB vorhanden. Wählen Sie in dem Suchfeld entweder einen schon existierenden Anbieter oder übernehmen Sie den Anbieter von der Importquelle.", + "wrongImportSource": "Ein Import aus der gewählten Quelle ist aktuell nicht möglich." }, "adaptSource": "Quelle übernehmen", "packageName": "Paketname", @@ -307,7 +308,9 @@ "missingStartVolume": "Die Angabe eines letzten Bands erfordert ein Anfangsband.", "refdataLookup": "Unbekannter Wert konnte nicht gespeichert werden.", "yearFormat": "Bitte geben Sie ein vierstelliges Jahr an.", - "missingStart": "Bitte geben Sie einen Startwert an." + "missingStart": "Bitte geben Sie einen Startwert an.", + "ftpUrlRejected": "Konfigurieren Sie eine FTP-Verbindung unter Transfer-Methode.", + "urlEmpty": "Bitte geben Sie eine URL an." }, "job": { "label": "Import | Importe", @@ -1907,6 +1910,31 @@ "enableUpdate": "Aktiviert", "ignoreSizeLimit": "Dateigröße ignorieren", "url": "URL", + "filePath": "Dateipfad", + "completePath": "Vollständiger FTP-Pfad", + "testFtpConnection": { + "label": "Verbindung testen", + "message": { + "success": "Verbindung erfolgreich", + "partlySuccessful": "Die Verbindung zum Server konnte hergestellt werden, die Datei ist (derzeit) aber nicht vorhanden.", + "connectError": "Es konnte keine Verbindung zum FTP-Server hergestellt werden.", + "configurationError": "Die Konfiguration ist fehlerhaft.", + "dateMaskFound": "Eine Datei mit diesem Namen und einem Datumszusatz wurde gefunden.", + "dateMaskNotFound": "Eine Datei mit diesem Namen und einem Datumszusatz ist derzeit nicht vorhanden." + } + }, + "transferMethod": { + "label": "Transfer-Methode", + "HTTP": { + "label": "HTTP" + }, + "FTP": { + "label": "FTP" + } + }, + "endpointConfiguration": { + "label": "Konfiguration" + }, "frequency": { "label": "Update-Zyklus", "Daily": { diff --git a/src/locales/en.json b/src/locales/en.json index 5b3aad34..efdca432 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -233,7 +233,8 @@ "packageNotExist": "A package with this UUID does not seem to exist in the chosen import repository", "packageExists": "A package with this name already exists in the GOKB. Please check if this is a unique package you are trying to import.", "platformExists": "The platform doesn't exist in the GOKB yet. Choose an existing platform in the search field or adopt the platform from the import source.", - "providerExists": "The provider doesn't exist in the GOKB yet. Choose an existing provider in the search field or adopt the provider from the import source." + "providerExists": "The provider doesn't exist in the GOKB yet. Choose an existing provider in the search field or adopt the provider from the import source.", + "wrongImportSource": "An import from the selected source is not possible." }, "adaptSource": "Adopt from source", "packageName": "Package name", @@ -307,7 +308,9 @@ "missingStartVolume": "An end volume requires a set start volume!", "refdataLookup": "Unable to save unrecognized value!", "yearFormat": "Please enter a four digit year.", - "missingStart": "Please first provide a start value." + "missingStart": "Please first provide a start value.", + "ftpUrlRejected": "Configure an FTP connection under Transfer method.", + "urlEmpty": "Please provide a URL." }, "job": { "label": "Import | Imports", @@ -1898,6 +1901,31 @@ "enableUpdate": "Activated", "ignoreSizeLimit": "Ignore Size Limit", "url": "URL", + "filePath": "File Path", + "completePath": "Complete FTP Path", + "testFtpConnection": { + "label": "Test Connection", + "message": { + "success": "Connection successful", + "partlySuccessful": "Could connect to FTP Server but the File does not exist (at the moment).", + "connectError": "Could not connect to FTP Server.", + "configurationError": "The Configuration is incorrect.", + "dateMaskFound": "A File with this name and a date addition was found.", + "dateMaskNotFound": "A File with this name and a date addition was not found." + } + }, + "transferMethod": { + "label": "Transfer Method", + "HTTP": { + "label": "HTTP" + }, + "FTP": { + "label": "FTP" + } + }, + "endpointConfiguration": { + "label": "Configuration" + }, "frequency": { "label": "Update Cycle", "Daily": { diff --git a/src/shared/components/complex/gokb-source-field/gokb-source-field.vue b/src/shared/components/complex/gokb-source-field/gokb-source-field.vue index 0b653d40..530af1d5 100644 --- a/src/shared/components/complex/gokb-source-field/gokb-source-field.vue +++ b/src/shared/components/complex/gokb-source-field/gokb-source-field.vue @@ -5,11 +5,68 @@ :hide-default="!expanded" :sub-title="$tc('component.source.label')" > + + + + + + + + + + + + + + + + {{ $t('component.source.completePath') }}: {{ fullFtpUrl }} + + mdi-check-circle + + + + + + {{ $t('component.source.testFtpConnection.label') }} + + +

{{ ftpTestMessage }}
+ +
+
+ @@ -130,6 +187,7 @@ import providerServices from '@/shared/services/provider-services' import BaseComponent from '@/shared/components/base-component' import account from '@/shared/models/account-model' + import webendpointServices from "@/shared/services/webendpoint-services" export default { name: 'GokbSourceField', @@ -187,7 +245,10 @@ automaticUpdates: undefined, importConfig: undefined, ignoreSizeLimit: false, - update: false + update: false, + webEndpoint: undefined, + transferMethod: undefined, + ftpPath: undefined, }, errors: [], mixedContent: false, @@ -195,12 +256,15 @@ serialVisible: true, monographVisible: true, mixedContentVisible: true, - ignoreLegacyTitleID: true + ignoreLegacyTitleID: true, + isFTPTransfer: false, + ftpTestSuccessful: false, + ftpTestMessage: undefined } }, computed: { importNowDisabled () { - return !this.readonly && !this.item.url + return !this.readonly && (!this.item.url && !(this.isFTPTransfer && !!this.item.ftpPath)) }, activatedDisabled () { return !this.readonly && (!this.item.url || !this.item.frequency) && !this.item.automaticUpdates @@ -208,6 +272,9 @@ activatedErrorMessage () { return !this.readonly && (!this.item.url || !this.item.frequency) && this.item.automaticUpdates ? this.$i18n.t("component.source.error.activatedNoInfo") : undefined }, + fullFtpUrl () { + return this.formatFtpPath(this.item.ftpPath) + }, isAdmin() { return account.loggedIn() && account.hasRole('ROLE_ADMIN') } @@ -266,6 +333,23 @@ }, mixedContent () { this.setVisibleStatusForTitleIdFields() + }, + 'item.transferMethod': { + handler(val) { + if (!!val && (this.item?.transferMethod?.value === 'FTP' || this.item?.transferMethod?.name === 'FTP')) { + this.isFTPTransfer = true + } + else { + this.isFTPTransfer = false + } + this.resetTestConnectionProps() + } + }, + 'item.ftpPath'() { + this.resetTestConnectionProps() + }, + 'item.webEndpoint'() { + this.resetTestConnectionProps() } }, async mounted () { @@ -286,8 +370,49 @@ } else if (!!this.provider){ this.fetchDefaultNamespace() } + + if (this.item?.transferMethod?.value === 'FTP') { + this.isFTPTransfer = true + } + + }, + created () { + }, methods: { + resetTestConnectionProps () { + this.ftpTestSuccessful = false + this.ftpTestMessage = undefined + }, + formatFtpPath (filepath) { + let hostname = this.item.webEndpoint?.url + let filename = "" + let directory = "/" + + if (hostname?.includes("/")) { + let parts = hostname.split("/") + hostname = parts[0] + for(var i = 1; i < parts.length; i++){ + directory = directory.concat(parts[i] + "/") + } + } + + let ftpPath = this.item.ftpPath + if (ftpPath?.startsWith("/")) { + ftpPath = ftpPath.substring(1) + } + + if(ftpPath?.includes("/")){ + let parts = ftpPath.split("/") + filename = parts[parts.length - 1] + directory = directory + ftpPath.substring(0, ftpPath.lastIndexOf("/") + 1) + } + else { + filename = ftpPath + } + + return hostname + directory + filename + }, setVisibleStatusForTitleIdFields () { if (this.mixedContent) { this.serialVisible = true @@ -325,6 +450,26 @@ this.item.titleIdMonograph = result.data.titleIdMonograph this.item.ignoreSizeLimit = result.data.ignoreSizeLimit === true + this.item.ftpPath = result.data.ftpPath + this.item.transferMethod = result.data.transferMethod + this.item.webEndpoint = result.data.webEndpoint + + if (this.item.transferMethod?.value === 'FTP' || this.item.transferMethod?.name === 'FTP') { + this.isFTPTransfer = true + + if(!!result.data.webEndpoint?.id) { + // complete webendpoint object must be loaded + const response = await this.catchError({ + promise: webendpointServices.get(result.data.webEndpoint.id, this.cancelToken.token), + instance: this + }) + + this.item.webEndpoint = response.data.data + + } + + } + if (!!this.item.targetNamespace && !this.item.titleIdSerial && !this.item.titleIdMonograph) { this.ignoreLegacyTitleID = false } @@ -334,6 +479,7 @@ if (!!this.item.url) { this.isExpanded = true } + this.setVisibleStatusForTitleIdFields() } } @@ -365,6 +511,17 @@ this.setVisibleStatusForTitleIdFields() } }, + async testFTPConnection () { + + const checkResult = await this.catchError({ + promise: webendpointServices.check({webhookendpoint: this.item.webEndpoint.id, url: this.item.ftpPath}, this.cancelToken.token), + instance: this + }) + + this.ftpTestSuccessful = (checkResult?.data?.result === 'success') + this.ftpTestMessage = this.$i18n.t('component.source.testFtpConnection.message.' + checkResult?.data?.message) + + } } } diff --git a/src/shared/components/simple/gokb-url-field/gokb-url-field.vue b/src/shared/components/simple/gokb-url-field/gokb-url-field.vue index 52db7809..d0318965 100644 --- a/src/shared/components/simple/gokb-url-field/gokb-url-field.vue +++ b/src/shared/components/simple/gokb-url-field/gokb-url-field.vue @@ -26,6 +26,11 @@ type: Boolean, required: false, default: false + }, + rejectFtpUrl: { + type: Boolean, + required: false, + default: false } }, computed: { @@ -40,13 +45,11 @@ }, methods: { async validate () { - const validResult = await genericServices('rest/entities').checkUrl(this.localValue, this.replaceDate, createCancelToken.token) + const validResult = await genericServices('rest/entities').checkUrl(this.localValue, this.replaceDate, this.rejectFtpUrl, createCancelToken.token) if (validResult.data?.result === 'ERROR') { - if (!this.localErrorMessages || this.localErrorMessages.length === 0) { - this.localErrorMessages = [this.$i18n.t('validation.urlForm')] - this.$emit('valid', false) - } + this.localErrorMessages = [this.$i18n.t(validResult.data?.errors?.value?.messageCode)] + this.$emit('valid', false) } else { if (!!this.localErrorMessages) { diff --git a/src/shared/components/simple/gokb-webendpoint-field/gokb-webendpoint-field.vue b/src/shared/components/simple/gokb-webendpoint-field/gokb-webendpoint-field.vue new file mode 100644 index 00000000..3253b908 --- /dev/null +++ b/src/shared/components/simple/gokb-webendpoint-field/gokb-webendpoint-field.vue @@ -0,0 +1,27 @@ + diff --git a/src/shared/components/simple/gokb-webendpoint-field/index.js b/src/shared/components/simple/gokb-webendpoint-field/index.js new file mode 100644 index 00000000..417d9908 --- /dev/null +++ b/src/shared/components/simple/gokb-webendpoint-field/index.js @@ -0,0 +1 @@ +export {default} from './gokb-webendpoint-field' diff --git a/src/shared/popups/gokb-create-package-with-presets-popup/gokb-create-package-with-presets-popup.vue b/src/shared/popups/gokb-create-package-with-presets-popup/gokb-create-package-with-presets-popup.vue index ea88bf9f..ab9b4744 100644 --- a/src/shared/popups/gokb-create-package-with-presets-popup/gokb-create-package-with-presets-popup.vue +++ b/src/shared/popups/gokb-create-package-with-presets-popup/gokb-create-package-with-presets-popup.vue @@ -591,7 +591,7 @@ export default { if (urlToCheck === oldUrl) { valid = false } else { - const validationResult = await genericServices('rest/entities').checkUrl(urlToCheck, true, this.cancelToken.token) + const validationResult = await genericServices('rest/entities').checkUrl(urlToCheck, true, false, this.cancelToken.token) if (validationResult.data?.result === 'ERROR') { valid = false diff --git a/src/shared/popups/gokb-import-external-source-package-popup/gokb-import-external-source-package-popup.vue b/src/shared/popups/gokb-import-external-source-package-popup/gokb-import-external-source-package-popup.vue index 31dc0a95..211c4b34 100644 --- a/src/shared/popups/gokb-import-external-source-package-popup/gokb-import-external-source-package-popup.vue +++ b/src/shared/popups/gokb-import-external-source-package-popup/gokb-import-external-source-package-popup.vue @@ -27,10 +27,12 @@ +
{{ $t('popups.externalSourceImport.error.wrongImportSource') }}
@@ -375,6 +377,10 @@ }, platformDisplay() { return this.platformName + ' (' + this.platformURL + ')' + }, + validSource() { + // at the moment only wekb is valid source + return ["WEKB"].includes(this.externalSourceType?.value) } }, watch: { diff --git a/src/shared/services/generic-entity-services/generic-entity-services.js b/src/shared/services/generic-entity-services/generic-entity-services.js index 5269dcc1..595052f6 100644 --- a/src/shared/services/generic-entity-services/generic-entity-services.js +++ b/src/shared/services/generic-entity-services/generic-entity-services.js @@ -33,8 +33,8 @@ const api = (baseServices) => return result }, - checkUrl (value, replaceDate, cancelToken) { - const url = import.meta.env.VITE_API_BASE_URL + `/validation/url?replaceDate=${replaceDate}` + checkUrl (value, replaceDate, rejectFtpUrl, cancelToken) { + const url = import.meta.env.VITE_API_BASE_URL + `/validation/url?replaceDate=${replaceDate}&rejectFtpUrl=${rejectFtpUrl}` const data = { value: value } const result = baseServices.request({ method: 'POST', diff --git a/src/shared/services/webendpoint-services/index.js b/src/shared/services/webendpoint-services/index.js new file mode 100644 index 00000000..ef8f57a1 --- /dev/null +++ b/src/shared/services/webendpoint-services/index.js @@ -0,0 +1,4 @@ +import baseServices from '@/shared/services/base-services' +import api from './webendpoint-services' + +export default api(baseServices) diff --git a/src/shared/services/webendpoint-services/webendpoint-services.js b/src/shared/services/webendpoint-services/webendpoint-services.js new file mode 100644 index 00000000..10408b21 --- /dev/null +++ b/src/shared/services/webendpoint-services/webendpoint-services.js @@ -0,0 +1,19 @@ +const WEBENDPOINT_URL = '/rest/web-endpoint' + +const api = (baseServices) => ({ + get (id, cancelToken) { + return baseServices.request({ + method: 'GET', + url: import.meta.env.VITE_API_BASE_URL + `${WEBENDPOINT_URL}/${id}`, + }, cancelToken) + }, + check (data, cancelToken) { + return baseServices.request({ + method: 'POST', + url: import.meta.env.VITE_API_BASE_URL + WEBENDPOINT_URL + '/check', + data: data + }, cancelToken) + } +}) + +export default api diff --git a/src/views/search/search-provider-view.vue b/src/views/search/search-provider-view.vue index 1d90e41b..d2a95744 100644 --- a/src/views/search/search-provider-view.vue +++ b/src/views/search/search-provider-view.vue @@ -12,7 +12,7 @@ searchFilters: { qsName: undefined, identifierValue: undefined, - titleNamespace: undefined, + // titleNamespace: undefined, curatoryGroupIds: undefined, status: 'Current', roles: undefined @@ -120,8 +120,8 @@ url: 'refdata/categories/Org.Role', label: this.$i18n.tc('component.provider.role.label') } - }, - { + } + /* { type: 'GokbNamespaceField', name: 'titleNamespace', value: 'titleNamespaceId', @@ -130,7 +130,7 @@ label: this.$i18n.t('component.provider.titleNamespace.label'), returnObject: false } - }, + }, */ ], ] },