Commit 4bbcf410 authored by Gerrit Hübbers's avatar Gerrit Hübbers 🃏
Browse files

WIP introduce frontend Xml Xslt Source assets

parent 70222d07
......@@ -18,6 +18,8 @@ import org.gesis.dda.publishing.domain.impl.UnapiBssConfigDto;
import org.gesis.dda.publishing.domain.impl.UnapiBundlesStreamSource;
import org.gesis.dda.publishing.domain.impl.XmlBundlesSetSource;
import org.gesis.dda.publishing.domain.impl.XmlFileBssConfigDto;
import org.gesis.dda.publishing.domain.impl.XmlXsltBundlesStreamSource;
import org.gesis.dda.publishing.domain.impl.XmlXsltDto;
import org.gesis.dda.publishing.domain.impl.XsltOaiPmhDto;
import org.gesis.dda.publishing.domain.impl.XsltTransformerOaiPmhBundlesStreamSource;
import org.gesis.dda.wizard.domain.BundlesSource;
......@@ -47,7 +49,7 @@ public class BundlesStreamSourceFactory {
}
public BundlesStreamSource getBundlesStreamSource(BundlesSource bundlesSourceEntity) {
return getBundlesStreamSource(bundlesSourceEntity.getType(), bundlesSourceEntity.getData() );
return getBundlesStreamSource(bundlesSourceEntity.getType(), bundlesSourceEntity.getData(), bundlesSourceEntity.getId() );
}
private String constructLoggingString(KmhopbssDto dtoDeserialized) {
......@@ -62,7 +64,7 @@ public class BundlesStreamSourceFactory {
return msg;
}
public BundlesStreamSource getBundlesStreamSource(BundlesSourceType bundlesSourceType, String data) {
public BundlesStreamSource getBundlesStreamSource(BundlesSourceType bundlesSourceType, String data, long bseId) {
BundlesStreamSource result = null;
if (BundlesSourceType.OAI_PMH == bundlesSourceType) {
KmhopbssDto dtoDeserialized = PersistableHelper.instantiate(data, KmhopbssDto.class);
......@@ -116,6 +118,12 @@ public class BundlesStreamSourceFactory {
Map<String, String> map = dto.getMetadataPrefix2XsltMap();
result = new XsltTransformerOaiPmhBundlesStreamSource(url, map, dto.getFrom(), dto.getUntil());
}
else if (BundlesSourceType.XML_XSLT_FILE == bundlesSourceType) {
XmlXsltDto dto = PersistableHelper.instantiate(data, XmlXsltDto.class);
String xmlContent = dto.getXmlContent();
String xsltContent = dto.getXsltContent();
result = new XmlXsltBundlesStreamSource(xmlContent, xsltContent, bseId);
}
return result;
}
......
......@@ -316,8 +316,8 @@ public class ContentResolver {
private static ContentsUrlsResolvingStrategy getStrategy(String seedUrlString) {
log.debug("seedUrlString is {}", seedUrlString);
ContentsUrlsResolvingStrategy result;
if ( seedUrlString.contains("wbv.de") ) {
result = new WbvResolvingStrategy();
if ( seedUrlString.contains("wbv.de") || seedUrlString.contains("budrich-academic.de") ) {
result = new UseNthPdfOnPageStrategy(0);
}
else if ( seedUrlString.contains("journals.sub.uni-hamburg.de") ) {
// unfortunately, SUB Uni Hamburg's OJS instances report an incorrect HTML citation_pdf_url
......
......@@ -17,12 +17,26 @@ import org.slf4j.LoggerFactory;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentType;
public class WbvResolvingStrategy implements ContentsUrlsResolvingStrategy {
/**
* Strategy to resolve correct PDF from several possible options. If several PDF
* files can be found on an HTML page, then this strategy will collect the nth PDF
* only.
* @author huebbegt
*
*/
public class UseNthPdfOnPageStrategy implements ContentsUrlsResolvingStrategy {
private final static Logger log = LoggerFactory.getLogger(UseNthPdfOnPageStrategy.class);
private int nthPdf;
private int currentPdf = 0;
private int currentAttempt = 0;
private int maximumRetries = 3;
private final static Logger log = LoggerFactory.getLogger(WbvResolvingStrategy.class);
public UseNthPdfOnPageStrategy(int nthPdf) {
this.nthPdf = nthPdf;
}
@Override
public Set<String> getContentsUrls(String seedUrl) {
......@@ -47,9 +61,16 @@ public class WbvResolvingStrategy implements ContentsUrlsResolvingStrategy {
if (null != ci) {
ContentType ct = ci.getContentType();
if ( ContentType.PDF.equals(ct) ) {
contentsUrlStrings.add(resolvedPossiblePdfUrlString);
wasSuccessful = true;
break; // WBV heuristic: first DOM resolvedPossiblePdfUrlString will be correct
if (nthPdf == currentPdf) {
contentsUrlStrings.add(resolvedPossiblePdfUrlString);
wasSuccessful = true;
break;
}
else {
currentPdf++;
continue;
}
}
}
}
......
......@@ -42,9 +42,9 @@ public class XmlXsltBundlesStreamSource implements BundlesStreamSource {
}
public XmlXsltBundlesStreamSource(String xmlPayload, String xslt, long databaseId) {
public XmlXsltBundlesStreamSource(String xmlPayload, String xslt, long bundlesSourceId) {
this(xmlPayload, xslt);
this.reference = "xmlxslt-database-" + databaseId;
this.reference = "xmlxslt-bundlessource-" + bundlesSourceId;
}
@Override
......
package org.gesis.dda.publishing.domain.impl;
public class XmlXsltDto {
private String xmlContent;
private String xsltContent;
public XmlXsltDto(String xmlContent, String xsltContent) {
this.xmlContent = xmlContent;
this.xsltContent = xsltContent;
}
public String getXmlContent() {
return xmlContent;
}
public String getXsltContent() {
return xsltContent;
}
}
\ No newline at end of file
......@@ -4,5 +4,5 @@ package org.gesis.dda.wizard.domain.enumeration;
* The BundlesSourceType enumeration.
*/
public enum BundlesSourceType {
OAI_PMH, EXCEL_SPREADSHEET, XML_FILE, UNAPI, XSLT_OAI_PMH
OAI_PMH, EXCEL_SPREADSHEET, XML_FILE, UNAPI, XSLT_OAI_PMH, XML_XSLT_FILE
}
......@@ -112,6 +112,7 @@
<script src="scripts/components/util/base64.service.js"></script>
<script src="scripts/components/util/capitalize.filter.js"></script>
<script src="scripts/components/util/jsonstring2object.filter.js"></script>
<script src="scripts/components/util/fileread.directive.js"></script>
<script src="scripts/components/alert/alert.service.js"></script>
<script src="scripts/components/alert/alert.directive.js"></script>
<script src="scripts/components/util/parse-links.service.js"></script>
......@@ -184,6 +185,10 @@
<script src="scripts/app/account/userRepositories/publicationsSources-xsltoaipmhaddress-edit-dialog.controller.js"></script>
<script src="scripts/app/account/userRepositories/publicationsSources-xsltoaipmhaddress-delete-dialog.controller.js"></script>
<script src="scripts/app/account/userRepositories/publicationsSources-xmlxsltsource-create-dialog.controller.js"></script>
<script src="scripts/app/account/userRepositories/publicationsSources-xmlxsltsource-edit-dialog.controller.js"></script>
<script src="scripts/app/account/userRepositories/publicationsSources-xmlxsltsource-delete-dialog.controller.js"></script>
<script src="scripts/app/account/userRepositories/userRepositories.js"></script>
<script src="scripts/app/account/userRepositories/userRepositories.controller.js"></script>
<script src="scripts/components/wizardEditor/oaiPmhLinkImporter/oaiPmhLinkImporter.controller.js"></script>
......
'use strict';
angular.module('ddaApp').controller('PublicationsSourcesXmlXsltSourceCreateDialogController',
['$scope', '$stateParams', '$uibModalInstance', '$state', 'BundlesSource',
function($scope, $stateParams, $uibModalInstance, $state, BundlesSource) {
$scope.xmlContent = '';
$scope.xsltContent = '';
$scope.reference = '';
$scope.clear = function() {
$uibModalInstance.dismiss('cancel');
};
var onSaveSuccess = function (result) {
$uibModalInstance.close(result);
};
var onSaveError = function (result) {
};
$scope.save = function () {
var dataObject = {
xmlContent: $scope.xmlContent,
xsltContent: $scope.xsltContent
};
console.log(dataObject);
BundlesSource.createForCurrentUser(
{
'data': angular.toJson(dataObject),
'type': 'XML_XSLT_FILE',
},
onSaveSuccess,
onSaveError
);
};
}]);
<form name="editForm" role="form" novalidate ng-submit="save()" show-validation>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"
ng-click="clear()">&times;</button>
<h4 class="modal-title" id="myFileLabel">Create a new XSLT-based OAI-PMH publications source</h4>
</div>
<div class="modal-body">
<label>XML file
<input type="file" name="xmlContent" fileread="xmlContent">
</label>
<label>XSLT file
<input type="file" name="xsltContent" fileread="xsltContent">
</label>
</div>
<div>{{message}}</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="clear()">
<span class="glyphicon glyphicon-ban-circle"></span>&nbsp;<span>Close</span>
</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="save()">
<span class="glyphicon glyphicon-save"></span>&nbsp;<span>Save</span>
</button>
</div>
</form>
'use strict';
angular.module('ddaApp')
.controller('PublicationsSourcesXsltOaiPmhAddressDeleteDialogController', function($scope, $uibModalInstance, entity, BundlesSource) {
$scope.entity = entity;
$scope.clear = function() {
$uibModalInstance.dismiss('cancel');
};
$scope.confirmDelete = function(id) {
BundlesSource.delete({id: entity.id},
function () {
$uibModalInstance.close(true);
});
};
});
<form name="deleteForm" ng-submit="confirmDelete(xmlFile.id)">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"
ng-click="clear()">&times;</button>
<h4 class="modal-title">Confirm delete operation</h4>
</div>
<div class="modal-body">
<jh-alert-error></jh-alert-error>
<p>Are you sure you want to delete XSLT-based OAI-PMH publication source <i>{{entity.data | jsonstring2object:"oaiPmhEndpoint" }}</i>?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="clear()">
<span class="glyphicon glyphicon-ban-circle"></span>&nbsp;<span>Cancel</span>
</button>
<button type="submit" ng-disabled="deleteForm.$invalid" class="btn btn-danger">
<span class="glyphicon glyphicon-remove-circle"></span>&nbsp;<span>Delete</span>
</button>
</div>
</form>
'use strict';
angular.module('ddaApp').controller('PublicationsSourcesXmlXsltSourceEditDialogController',
['$scope', '$stateParams', '$uibModalInstance', 'entity', '$state', 'BundlesSource', 'MetadataTransformer',
function($scope, $stateParams, $uibModalInstance, entity, $state, BundlesSource, MetadataTransformer) {
$scope.entity = entity;
$scope.newMetadataPrefix = '';
$scope.iso8601From = ( new Date( angular.fromJson(entity.data).from.seconds * 1000) ).toISOString();
$scope.dataDto = {
oaiPmhEndpoint: angular.fromJson(entity.data).oaiPmhEndpoint,
metadataPrefix2XsltMap: angular.fromJson(entity.data).metadataPrefix2XsltMap,
from: angular.fromJson(entity.data).from,
until: angular.fromJson(entity.data).until
};
$scope.clear = function() {
$uibModalInstance.dismiss('cancel');
};
$scope.metadataTransformers = MetadataTransformer.query();
$scope.selectedMetadataTransformer = null;
var onSaveSuccess = function (result) {
$uibModalInstance.close(result);
};
var onSaveError = function (result) {
};
$scope.addMetadataPrefix = function() {
$scope.dataDto.metadataPrefix2XsltMap[$scope.newMetadataPrefix] = '';
};
$scope.removeMetadataPrefix = function(metadataPrefix) {
delete $scope.dataDto.metadataPrefix2XsltMap[metadataPrefix];
};
$scope.convertTimeString = function() {
$scope.dataDto.from.seconds = Date.parse($scope.iso8601From) / 1000;
}
$scope.save = function () {
console.log($scope.dataDto);
BundlesSource.updateData({id: $scope.entity.id}, $scope.dataDto, onSaveSuccess, onSaveError);
if (null != $scope.selectedMetadataTransformer) {
BundlesSource.updateMetadataTransformer({id: $scope.entity.id}, $scope.selectedMetadataTransformer.id, onSaveSuccess, onSaveError);
}
};
}]);
<form name="editForm" role="form" novalidate ng-submit="save()" show-validation>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"
ng-click="clear()">&times;</button>
<h4 class="modal-title" id="myFileLabel">Edit XSLT-based OAI-PMH publications source</h4>
</div>
<div class="modal-body">
<div>
<label>Base URL
<input type="text" name="input" ng-model="dataDto.oaiPmhEndpoint">
</label>
</div>
<div>
<table>
<tr>
<th>&nbsp;</th>
<th>Metadata prefix</th>
<th>XSLT</th>
</tr>
<tr ng-repeat="(metadataPrefix, xsltContent) in dataDto.metadataPrefix2XsltMap">
<td>
<button type="button" class="btn btn-danger" ng-click="removeMetadataPrefix(metadataPrefix)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
<td>{{metadataPrefix}}</td>
<td><textarea name="xslt" cols=80 rows=5 ng-model="dataDto.metadataPrefix2XsltMap[metadataPrefix]"></textarea></td>
</tr>
</table>
<input type="text" name="metadataPrefix" ng-model="newMetadataPrefix">
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="addMetadataPrefix()">
<span class="glyphicon glyphicon-plus"></span>&nbsp;<span>Add additional metadata prefix</span>
</button>
</div>
<div>
<label>Harvest onwards from (ISO8601 format)
<input type="text" name="iso8601From" ng-model="iso8601From" ng-change="convertTimeString()">
</label>
</div>
<div>
<label for="field_metadataTransformer">Metadata transformer</label>
<select class="form-control" id="field_metadataTransformer" name="metadataTransformer" ng-model="selectedMetadataTransformer" ng-options="metadataTransformer as metadataTransformer.name for metadataTransformer in metadataTransformers track by metadataTransformer.id">
<option value=""></option>
</select>
</div>
</div>
<div>{{message}}</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="clear()">
<span class="glyphicon glyphicon-ban-circle"></span>&nbsp;<span>Close</span>
</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="save()">
<span class="glyphicon glyphicon-save"></span>&nbsp;<span>Save</span>
</button>
</div>
</form>
......@@ -30,6 +30,11 @@ angular.module('ddaApp')
$scope.xsltOaiPmhAddresses = result.filter( function(bundlesSource) {
return bundlesSource.type === 'XSLT_OAI_PMH';
});
});
BundlesSource.getForCurrentUser(function(result) {
$scope.xsltOaiPmhAddresses = result.filter( function(bundlesSource) {
return bundlesSource.type === 'XML_XSLT_FILE';
});
})
};
......
......@@ -62,7 +62,66 @@
</tbody>
</table>
</div>
<h3>XSLT-transformed XML files</h3>
<div class="container-fluid">
<div class="row">
<div class="col-xs-4 no-padding-left">
<button class="btn btn-primary" ui-sref="userRepositories.newXmlXsltSource">
<span class="glyphicon glyphicon-plus"></span>
<span>Add XML file source with XSLT transformation</span>
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="jh-table table table-striped">
<thead>
<tr>
<th><span>Name</span></th>
<th><span>Metadata transformer</span></th>
<th><span>State</span></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="xmlXsltFile in xmlXsltFiles track by xmlXsltFile.id">
<td>{{xmlXsltFile.name}}</td>
<td>{{xmlXsltFile.metadataTransformer.name}}</td>
<td>{{xmlXsltFile.bundlesSourceState}}</td>
<td translate="{{'ddaApp.BundlesSourceState.' + bundlesSource.bundlesSourceState}}">{{xmlXsltFile.bundlesSource.bundlesSourceState}}</td>
<td class="text-right">
<div class="btn-group flex-btn-group-container">
<button type="submit"
ng-click="showBundles(xmlXsltFile.id)"
class="btn btn-info btn-sm">
<span class="glyphicon glyphicon-eye-open"></span>
<span class="hidden-xs hidden-sm"></span>
</button>
<button has-authority="ROLE_ADMIN" type="submit"
ui-sref="userRepositories.editXmlXsltFile({id:xmlXsltFile.id})"
class="btn btn-info btn-sm">
<span class="glyphicon glyphicon-pencil"></span>
<span class="hidden-xs hidden-sm"></span>
</button>
<button has-authority="ROLE_ADMIN" type="submit"
ng-click="harvest({id:xmlXsltFile.id})"
class="btn btn-warning btn-sm">
<span class="glyphicon glyphicon-apple"></span>
<span class="hidden-xs hidden-sm"></span>
</button>
<button has-authority="ROLE_ADMIN" type="submit"
ui-sref="userRepositories.deleteXmlXsltFile({id:xmlXsltFile.id})"
class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-remove-circle"></span>
<span class="hidden-xs hidden-sm"></span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<h3>XML files</h3>
<div class="container-fluid">
<div class="row">
......
......@@ -398,5 +398,81 @@ angular.module('ddaApp')
}]
})
.state('userRepositories.newXmlXsltSource', {
parent: 'userRepositories',
url: '/newXmlXsltSource',
data: {
authorities: ['ROLE_USER'],
},
onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: 'scripts/app/account/userRepositories/publicationsSources-xmlxsltsource-create-dialog.html',
controller: 'PublicationsSourcesXmlXsltSourceCreateDialogController',
size: 'lg',
resolve: {
entity: function () {
return {
xmlContent: null,
xsltContent: null,
reference: null
};
}
}
}).result.then(function(result) {
$state.go('userRepositories', null, { reload: true });
}, function() {
$state.go('userRepositories', null, { reload: true });
})
}]
})
.state('userRepositories.editXmlXsltSource', {
parent: 'userRepositories',
url: '/{id}/editXmlXsltSource',
data: {
authorities: ['ROLE_USER'],
},
onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: 'scripts/app/account/userRepositories/publicationsSources-xmlxsltsource-edit-dialog.html',
controller: 'PublicationsSourcesXmlXsltSourceEditDialogController',
size: 'lg',
resolve: {
entity: ['BundlesSource', function(BundlesSource) {
var result = BundlesSource.get({id : $stateParams.id}).$promise;
return result;
}]
}
}).result.then(function(result) {
$state.go('userRepositories', null, { reload: true });
}, function() {
$state.go('userRepositories', null, { reload: true });
})
}]
})
.state('userRepositories.deleteXmlXsltSource', {
parent: 'userRepositories',
url: '/{id}/deleteXmlXsltSource',
data: {
authorities: ['ROLE_USER'],
},
onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: 'scripts/app/account/userRepositories/publicationsSources-xsltoaipmhaddress-delete-dialog.html',
controller: 'PublicationsSourcesXsltOaiPmhAddressDeleteDialogController',
size: 'md',
resolve: {
entity: ['BundlesSource', function(BundlesSource) {
return BundlesSource.get({id : $stateParams.id});
}]
}
}).result.then(function(result) {
$state.go('userRepositories', null, { reload: true });
}, function() {
$state.go('^');
})
}]
})
;
});
'use strict';
// adapted https://stackoverflow.com/a/17063046/923560
angular.module('ddaApp')