mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge remote-tracking branch 'refs/remotes/origin/main'
Conflicts: dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java dspace-api/src/main/java/org/dspace/submit/lookup/PubmedService.java
This commit is contained in:
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug, needs triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is. Include the version(s) of DSpace where you've seen this problem. Link to examples if they are public.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Do this
|
||||
2. Then this...
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Related work**
|
||||
Link to any related tickets or PRs here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a new feature for this project
|
||||
title: ''
|
||||
labels: new feature, needs triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives or workarounds you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
26
.github/disabled-workflows/pull_request_opened.yml
vendored
Normal file
26
.github/disabled-workflows/pull_request_opened.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# This workflow runs whenever a new pull request is created
|
||||
# TEMPORARILY DISABLED. Unfortunately this doesn't work for PRs created from forked repositories (which is how we tend to create PRs).
|
||||
# There is no known workaround yet. See https://github.community/t/how-to-use-github-token-for-prs-from-forks/16818
|
||||
name: Pull Request opened
|
||||
|
||||
# Only run for newly opened PRs against the "main" branch
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
automation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Assign the PR to whomever created it. This is useful for visualizing assignments on project boards
|
||||
# See https://github.com/marketplace/actions/pull-request-assigner
|
||||
- name: Assign PR to creator
|
||||
uses: thomaseizinger/assign-pr-creator-action@v1.0.0
|
||||
# Note, this authentication token is created automatically
|
||||
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Ignore errors. It is possible the PR was created by someone who cannot be assigned
|
||||
continue-on-error: true
|
9
.github/pull_request_template.md
vendored
9
.github/pull_request_template.md
vendored
@@ -1,8 +1,7 @@
|
||||
## References
|
||||
_Add references/links to any related tickets or PRs. These may include:_
|
||||
* Link to [JIRA](https://jira.lyrasis.org/projects/DS/summary) ticket(s), if any
|
||||
* Link to [REST Contract](https://github.com/DSpace/Rest7Contract) or an open REST Contract PR, if any
|
||||
* Link to [Angular issue or PR](https://github.com/DSpace/dspace-angular/issues) related to this PR, if any
|
||||
_Add references/links to any related issues or PRs. These may include:_
|
||||
* Related to [REST Contract](https://github.com/DSpace/Rest7Contract) or an open REST Contract PR, if any
|
||||
* Fixes [GitHub issue](https://github.com/DSpace/DSpace/issues), if any
|
||||
|
||||
## Description
|
||||
Short summary of changes (1-2 sentences).
|
||||
@@ -23,5 +22,5 @@ _This checklist provides a reminder of what we are going to look for when review
|
||||
- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide).
|
||||
- [ ] My PR includes Javadoc for _all new (or modified) public methods and classes_. It also includes Javadoc for large or complex private methods.
|
||||
- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
|
||||
- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/master/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
|
||||
- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
|
||||
- [ ] If my PR modifies the REST API, I've linked to the REST Contract page (or open PR) related to this change.
|
||||
|
29
.github/workflows/issue_opened.yml
vendored
Normal file
29
.github/workflows/issue_opened.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# This workflow runs whenever a new issue is created
|
||||
name: Issue opened
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
automation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Add the new issue to a project board, if it needs triage
|
||||
# See https://github.com/marketplace/actions/create-project-card-action
|
||||
- name: Add issue to project board
|
||||
# Only add to project board if issue is flagged as "needs triage" or has no labels
|
||||
# NOTE: By default we flag new issues as "needs triage" in our issue template
|
||||
if: (contains(github.event.issue.labels.*.name, 'needs triage') || join(github.event.issue.labels.*.name) == '')
|
||||
uses: technote-space/create-project-card-action@v1
|
||||
# Note, the authentication token below is an ORG level Secret.
|
||||
# It must be created/recreated manually via a personal access token with "public_repo" and "admin:org" permissions
|
||||
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token
|
||||
# This is necessary because the "DSpace Backlog" project is an org level project (i.e. not repo specific)
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.ORG_PROJECT_TOKEN }}
|
||||
PROJECT: DSpace Backlog
|
||||
COLUMN: Triage
|
||||
CHECK_ORG_PROJECT: true
|
||||
# Ignore errors.
|
||||
continue-on-error: true
|
9
.lgtm.yml
Normal file
9
.lgtm.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
# LGTM Settings (https://lgtm.com/)
|
||||
# For reference, see https://lgtm.com/help/lgtm/lgtm.yml-configuration-file
|
||||
# or template at https://lgtm.com/static/downloads/lgtm.template.yml
|
||||
|
||||
extraction:
|
||||
java:
|
||||
index:
|
||||
# Specify the Java version required to build the project
|
||||
java_version: 11
|
@@ -1,5 +1,5 @@
|
||||
# This image will be published as dspace/dspace
|
||||
# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details
|
||||
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
|
||||
#
|
||||
# This version is JDK11 compatible
|
||||
# - tomcat:8-jdk11
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# This image will be published as dspace/dspace-cli
|
||||
# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details
|
||||
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
|
||||
#
|
||||
# This version is JDK11 compatible
|
||||
# - openjdk:11
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# This image will be published as dspace/dspace
|
||||
# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details
|
||||
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
|
||||
#
|
||||
# This version is JDK11 compatible
|
||||
# - tomcat:8-jdk11
|
||||
|
42
README.md
42
README.md
@@ -1,24 +1,24 @@
|
||||
|
||||
# DSpace
|
||||
|
||||
[](https://travis-ci.org/DSpace/DSpace)
|
||||
[](https://travis-ci.com/DSpace/DSpace)
|
||||
|
||||
[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) |
|
||||
[DSpace Documentation](https://wiki.lyrasis.org/display/DSDOC/) |
|
||||
[DSpace Releases](https://github.com/DSpace/DSpace/releases) |
|
||||
[DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) |
|
||||
[Support](https://wiki.duraspace.org/display/DSPACE/Support)
|
||||
[DSpace Wiki](https://wiki.lyrasis.org/display/DSPACE/Home) |
|
||||
[Support](https://wiki.lyrasis.org/display/DSPACE/Support)
|
||||
|
||||
DSpace open source software is a turnkey repository application used by more than
|
||||
2,000 organizations and institutions worldwide to provide durable access to digital resources.
|
||||
For more information, visit http://www.dspace.org/
|
||||
|
||||
***
|
||||
:warning: **Work on DSpace 7 has begun on our `master` branch.** This means that there is temporarily NO user interface on this `master` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) page. Additionally, the codebases can be found in the following places:
|
||||
* DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-server-webapp) of this repository.
|
||||
* The REST Contract is being documented at https://github.com/DSpace/Rest7Contract
|
||||
:warning: **Work on DSpace 7 has begun on our `main` branch.** This means that there is NO user interface on this `main` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 Working Group](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+Working+Group) page. Additionally, the codebases can be found in the following places:
|
||||
* DSpace 7 REST API work is occurring on the [`main` branch](https://github.com/DSpace/DSpace/tree/main/dspace-server-webapp) of this repository.
|
||||
* The REST Contract is at https://github.com/DSpace/Rest7Contract
|
||||
* DSpace 7 Angular UI work is occurring at https://github.com/DSpace/dspace-angular
|
||||
|
||||
**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) wiki page for more info.
|
||||
**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 Working Group](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+Working+Group) wiki page for more info.
|
||||
|
||||
**If you are looking for the ongoing maintenance work for DSpace 6 (or prior releases)**, you can find that work on the corresponding maintenance branch (e.g. [`dspace-6_x`](https://github.com/DSpace/DSpace/tree/dspace-6_x)) in this repository.
|
||||
***
|
||||
@@ -31,10 +31,10 @@ Past releases are all available via GitHub at https://github.com/DSpace/DSpace/r
|
||||
|
||||
## Documentation / Installation
|
||||
|
||||
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/).
|
||||
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.lyrasis.org/display/DSDOC/).
|
||||
|
||||
The latest DSpace Installation instructions are available at:
|
||||
https://wiki.duraspace.org/display/DSDOC6x/Installing+DSpace
|
||||
https://wiki.lyrasis.org/display/DSDOC6x/Installing+DSpace
|
||||
|
||||
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle)
|
||||
and a servlet container (usually Tomcat) in order to function.
|
||||
@@ -49,14 +49,14 @@ DSpace is a community built and supported project. We do not have a centralized
|
||||
but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc.
|
||||
|
||||
We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace:
|
||||
* [How to Contribute to DSpace](https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc)
|
||||
* [Code Contribution Guidelines](https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc.
|
||||
* [DSpace Community Advisory Team (DCAT)](https://wiki.duraspace.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam).
|
||||
* [How to Contribute to DSpace](https://wiki.lyrasis.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc)
|
||||
* [Code Contribution Guidelines](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc.
|
||||
* [DSpace Community Advisory Team (DCAT)](https://wiki.lyrasis.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam).
|
||||
|
||||
We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.duraspace.org/display/DSPACE/Development+with+Git) guide for more info.
|
||||
We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.lyrasis.org/display/DSPACE/Development+with+Git) guide for more info.
|
||||
|
||||
In addition, a listing of all known contributors to DSpace software can be
|
||||
found online at: https://wiki.duraspace.org/display/DSPACE/DSpaceContributors
|
||||
found online at: https://wiki.lyrasis.org/display/DSPACE/DSpaceContributors
|
||||
|
||||
## Getting Help
|
||||
|
||||
@@ -64,12 +64,12 @@ DSpace provides public mailing lists where you can post questions or raise topic
|
||||
We welcome everyone to participate in these lists:
|
||||
|
||||
* [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices
|
||||
* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.duraspace.org/display/DSPACE/Troubleshoot+an+error).
|
||||
* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.lyrasis.org/display/DSPACE/Troubleshoot+an+error).
|
||||
* [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list
|
||||
|
||||
Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace)
|
||||
|
||||
Additional support options are listed at https://wiki.duraspace.org/display/DSPACE/Support
|
||||
Additional support options are at https://wiki.lyrasis.org/display/DSPACE/Support
|
||||
|
||||
DSpace also has an active service provider network. If you'd rather hire a service provider to
|
||||
install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our
|
||||
@@ -77,14 +77,16 @@ install, upgrade, customize or host DSpace, then we recommend getting in touch w
|
||||
|
||||
## Issue Tracker
|
||||
|
||||
The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS/summary
|
||||
DSpace uses GitHub to track issues:
|
||||
* Backend (REST API) issues: https://github.com/DSpace/DSpace/issues
|
||||
* Frontend (User Interface) issues: https://github.com/DSpace/dspace-angular/issues
|
||||
|
||||
## Testing
|
||||
|
||||
### Running Tests
|
||||
|
||||
By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are
|
||||
run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all Pull Requests and code commits.
|
||||
run automatically by [Travis CI](https://travis-ci.com/DSpace/DSpace/) for all Pull Requests and code commits.
|
||||
|
||||
* How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`):
|
||||
```
|
||||
@@ -130,4 +132,4 @@ run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all P
|
||||
## License
|
||||
|
||||
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
|
||||
The full license is available at http://www.dspace.org/license/
|
||||
The full license is available in the [LICENSE](LICENSE) file or online at http://www.dspace.org/license/
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -291,9 +291,20 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<groupId>net.handle</groupId>
|
||||
<artifactId>handle</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.cnri</groupId>
|
||||
<artifactId>cnri-servlet-container</artifactId>
|
||||
<exclusions>
|
||||
<!-- Newer versions provided in our parent POM -->
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- Jetty is needed to run Handle Server -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
@@ -471,11 +482,59 @@
|
||||
<artifactId>solr-cell</artifactId>
|
||||
<version>${solr.client.version}</version>
|
||||
<exclusions>
|
||||
<!-- Newer version provided in our parent POM -->
|
||||
<!-- Newer versions provided in our parent POM -->
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
@@ -115,7 +115,7 @@ public final class CreateAdministrator {
|
||||
String lastName = null;
|
||||
char[] password1 = null;
|
||||
char[] password2 = null;
|
||||
String language = I18nUtil.DEFAULTLOCALE.getLanguage();
|
||||
String language = I18nUtil.getDefaultLocale().getLanguage();
|
||||
|
||||
while (!dataOK) {
|
||||
System.out.print("E-mail address: ");
|
||||
|
@@ -1519,6 +1519,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
log.error("Unable to create directory: " + dir.getAbsolutePath());
|
||||
}
|
||||
// Verify that the directory the entry is using is a subpath of zipDir (and not somewhere else!)
|
||||
if (!dir.toPath().normalize().startsWith(zipDir)) {
|
||||
throw new IOException("Bad zip entry: '" + entry.getName()
|
||||
+ "' in file '" + zipfile.getAbsolutePath() + "'!"
|
||||
+ " Cannot process this file.");
|
||||
}
|
||||
|
||||
//Entries could have too many directories, and we need to adjust the sourcedir
|
||||
// file1.zip (SimpleArchiveFormat / item1 / contents|dublin_core|...
|
||||
@@ -1539,9 +1545,16 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
}
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
File outFile = new File(zipDir + entry.getName());
|
||||
// Verify that this file will be created in our zipDir (and not somewhere else!)
|
||||
if (!outFile.toPath().normalize().startsWith(zipDir)) {
|
||||
throw new IOException("Bad zip entry: '" + entry.getName()
|
||||
+ "' in file '" + zipfile.getAbsolutePath() + "'!"
|
||||
+ " Cannot process this file.");
|
||||
}
|
||||
InputStream in = zf.getInputStream(entry);
|
||||
BufferedOutputStream out = new BufferedOutputStream(
|
||||
new FileOutputStream(zipDir + entry.getName()));
|
||||
new FileOutputStream(outFile));
|
||||
while ((len = in.read(buffer)) >= 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
|
@@ -48,6 +48,9 @@ public class SHERPAResponse {
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document inDoc = db.parse(xmlData);
|
||||
|
@@ -9,7 +9,10 @@ package org.dspace.app.util;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authenticate.factory.AuthenticateServiceFactory;
|
||||
import org.dspace.authorize.AuthorizeConfiguration;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
@@ -26,9 +29,12 @@ import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
|
||||
import org.dspace.xmlworkflow.storedcomponents.CollectionRole;
|
||||
import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService;
|
||||
@@ -41,6 +47,7 @@ import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService;
|
||||
*/
|
||||
public class AuthorizeUtil {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(AuthorizeUtil.class);
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
@@ -605,9 +612,53 @@ public class AuthorizeUtil {
|
||||
throw new AuthorizeException("not authorized to manage this group");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a boolean indicating whether the current user is allowed to register a new
|
||||
* account or not
|
||||
* @param context The relevant DSpace context
|
||||
* @param request The current request
|
||||
* @return A boolean indicating whether the current user can register a new account or not
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
public static boolean authorizeNewAccountRegistration(Context context, HttpServletRequest request)
|
||||
throws SQLException {
|
||||
if (DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||
.getBooleanProperty("user.registration", true)) {
|
||||
// This allowSetPassword is currently the only mthod that would return true only when it's
|
||||
// actually expected to be returning true.
|
||||
// For example the LDAP canSelfRegister will return true due to auto-register, while that
|
||||
// does not imply a new user can register explicitly
|
||||
return AuthenticateServiceFactory.getInstance().getAuthenticationService()
|
||||
.allowSetPassword(context, request, null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a boolean indicating whether it's allowed to update the password for the EPerson
|
||||
* with the given email and canLogin property
|
||||
* @param context The relevant DSpace context
|
||||
* @param email The email to be checked
|
||||
* @return A boolean indicating if the password can be updated or not
|
||||
*/
|
||||
public static boolean authorizeUpdatePassword(Context context, String email) {
|
||||
try {
|
||||
EPerson eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, email);
|
||||
if (eperson != null && eperson.canLogIn()) {
|
||||
HttpServletRequest request = new DSpace().getRequestService().getCurrentRequest()
|
||||
.getHttpServletRequest();
|
||||
return AuthenticateServiceFactory.getInstance().getAuthenticationService()
|
||||
.allowSetPassword(context, request, null);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Something went wrong trying to retrieve EPerson for email: " + email, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the community Admin can manage accounts
|
||||
*
|
||||
*
|
||||
* @return true if is able
|
||||
*/
|
||||
public static boolean canCommunityAdminManageAccounts() {
|
||||
@@ -625,7 +676,7 @@ public class AuthorizeUtil {
|
||||
|
||||
/**
|
||||
* This method checks if the Collection Admin can manage accounts
|
||||
*
|
||||
*
|
||||
* @return true if is able
|
||||
*/
|
||||
public static boolean canCollectionAdminManageAccounts() {
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.util;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.core.Utils;
|
||||
/**
|
||||
* Class representing all DC inputs required for a submission, organized into pages
|
||||
*
|
||||
@@ -107,9 +108,21 @@ public class DCInputSet {
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
for (int j = 0; j < inputs[i].length; j++) {
|
||||
DCInput field = inputs[i][j];
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
return true;
|
||||
// If this is a "qualdrop_value" field, then the full field name is the field + dropdown qualifier
|
||||
if (field.getInputType().equals("qualdrop_value")) {
|
||||
List<String> pairs = field.getPairs();
|
||||
for (int k = 0; k < pairs.size(); k += 2) {
|
||||
String qualifier = pairs.get(k + 1);
|
||||
String fullName = Utils.standardize(field.getSchema(), field.getElement(), qualifier, ".");
|
||||
if (fullName.equals(fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -250,12 +250,8 @@ public class IndexVersion {
|
||||
} else if (firstMinor > secondMinor) {
|
||||
// If we get here, major versions must be EQUAL. Now, time to check our minor versions
|
||||
return GREATER_THAN;
|
||||
} else if (firstMinor < secondMinor) {
|
||||
return LESS_THAN;
|
||||
} else {
|
||||
// This is an impossible scenario.
|
||||
// This 'else' should never be triggered since we've checked for equality above already
|
||||
return EQUAL;
|
||||
return LESS_THAN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -87,13 +87,16 @@ public class IPMatcher {
|
||||
+ ipSpec);
|
||||
}
|
||||
|
||||
int maskBytes = maskBits / 8;
|
||||
for (int i = 0; i < maskBytes; i++) {
|
||||
netmask[i] = (byte) 0Xff;
|
||||
}
|
||||
netmask[maskBytes] = (byte) ((byte) 0Xff << 8 - (maskBits % 8)); // FIXME test!
|
||||
for (int i = maskBytes + 1; i < (128 / 8); i++) {
|
||||
netmask[i] = 0;
|
||||
for (int i = 0; i < netmask.length; i++) {
|
||||
if (maskBits <= 0) {
|
||||
netmask[i] = 0;
|
||||
} else if (maskBits > 8) {
|
||||
netmask[i] = (byte) 0Xff;
|
||||
} else {
|
||||
netmask[i] = (byte) ((byte) 0Xff << 8 - maskBits);
|
||||
}
|
||||
|
||||
maskBits = maskBits - 8;
|
||||
}
|
||||
break;
|
||||
case 1: // No explicit mask: fill the mask with 1s
|
||||
|
@@ -153,7 +153,7 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService {
|
||||
// If the exception was thrown, unknown will == null so goahead and
|
||||
// load s. If not, check that the unknown's registry's name is not
|
||||
// being reset.
|
||||
if (unknown == null || unknown.getID() != bitstreamFormat.getID()) {
|
||||
if (unknown == null || !unknown.getID().equals(bitstreamFormat.getID())) {
|
||||
bitstreamFormat.setShortDescriptionInternal(shortDescription);
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService {
|
||||
// Find "unknown" type
|
||||
BitstreamFormat unknown = findUnknown(context);
|
||||
|
||||
if (unknown.getID() == bitstreamFormat.getID()) {
|
||||
if (unknown.getID().equals(bitstreamFormat.getID())) {
|
||||
throw new IllegalArgumentException("The Unknown bitstream format may not be deleted.");
|
||||
}
|
||||
|
||||
@@ -270,4 +270,4 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -168,11 +168,11 @@ public class MetadataField implements ReloadableEntity<Integer> {
|
||||
return false;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
final MetadataField other = (MetadataField) obj;
|
||||
if (this.getID() != other.getID()) {
|
||||
if (!this.getID().equals(other.getID())) {
|
||||
return false;
|
||||
}
|
||||
if (!getMetadataSchema().equals(other.getMetadataSchema())) {
|
||||
|
@@ -67,11 +67,11 @@ public class MetadataSchema implements ReloadableEntity<Integer> {
|
||||
return false;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
final MetadataSchema other = (MetadataSchema) obj;
|
||||
if (this.id != other.id) {
|
||||
if (!this.id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if ((this.namespace == null) ? (other.namespace != null) : !this.namespace.equals(other.namespace)) {
|
||||
|
@@ -239,17 +239,17 @@ public class MetadataValue implements ReloadableEntity<Integer> {
|
||||
return false;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
final MetadataValue other = (MetadataValue) obj;
|
||||
if (this.id != other.id) {
|
||||
if (!this.id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (this.getID() != other.getID()) {
|
||||
if (!this.getID().equals(other.getID())) {
|
||||
return false;
|
||||
}
|
||||
if (this.getDSpaceObject().getID() != other.getDSpaceObject().getID()) {
|
||||
if (!this.getDSpaceObject().getID().equals(other.getDSpaceObject().getID())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@@ -156,11 +156,11 @@ public class WorkspaceItem
|
||||
return true;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
final WorkspaceItem that = (WorkspaceItem) o;
|
||||
if (this.getID() != that.getID()) {
|
||||
if (!this.getID().equals(that.getID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -272,12 +272,16 @@ public class METSManifest {
|
||||
// Set validation feature
|
||||
if (validate) {
|
||||
builder.setFeature("http://apache.org/xml/features/validation/schema", true);
|
||||
}
|
||||
|
||||
// Tell the parser where local copies of schemas are, to speed up
|
||||
// validation. Local XSDs are identified in the configuration file.
|
||||
if (localSchemas.length() > 0) {
|
||||
builder.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", localSchemas);
|
||||
// Tell the parser where local copies of schemas are, to speed up
|
||||
// validation & avoid XXE attacks from remote schemas. Local XSDs are identified in the configuration file.
|
||||
if (localSchemas.length() > 0) {
|
||||
builder.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", localSchemas);
|
||||
}
|
||||
} else {
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
}
|
||||
|
||||
// Parse the METS file
|
||||
|
@@ -179,7 +179,7 @@ public class Context implements AutoCloseable {
|
||||
}
|
||||
|
||||
currentUser = null;
|
||||
currentLocale = I18nUtil.DEFAULTLOCALE;
|
||||
currentLocale = I18nUtil.getDefaultLocale();
|
||||
extraLogInfo = "";
|
||||
ignoreAuth = false;
|
||||
|
||||
@@ -876,4 +876,5 @@ public class Context implements AutoCloseable {
|
||||
private void reloadContextBoundEntities() throws SQLException {
|
||||
currentUser = reloadEntity(currentUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -37,9 +37,6 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
public class I18nUtil {
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(I18nUtil.class);
|
||||
|
||||
// the default Locale of this DSpace Instance
|
||||
public static final Locale DEFAULTLOCALE = getDefaultLocale();
|
||||
|
||||
// delimiters between elements of UNIX/POSIX locale spec, e.g. en_US.UTF-8
|
||||
private static final String LOCALE_DELIMITERS = " _.";
|
||||
|
||||
@@ -127,7 +124,7 @@ public class I18nUtil {
|
||||
return parseLocales(locales);
|
||||
} else {
|
||||
Locale[] availableLocales = new Locale[1];
|
||||
availableLocales[0] = DEFAULTLOCALE;
|
||||
availableLocales[0] = getDefaultLocale();
|
||||
return availableLocales;
|
||||
}
|
||||
}
|
||||
@@ -148,7 +145,7 @@ public class I18nUtil {
|
||||
Locale supportedLocale = null;
|
||||
String testLocale = "";
|
||||
if (availableLocales == null) {
|
||||
supportedLocale = DEFAULTLOCALE;
|
||||
supportedLocale = getDefaultLocale();
|
||||
} else {
|
||||
if (!locale.getVariant().equals("")) {
|
||||
testLocale = locale.toString();
|
||||
@@ -188,7 +185,7 @@ public class I18nUtil {
|
||||
}
|
||||
}
|
||||
if (!isSupported) {
|
||||
supportedLocale = DEFAULTLOCALE;
|
||||
supportedLocale = getDefaultLocale();
|
||||
}
|
||||
}
|
||||
return supportedLocale;
|
||||
@@ -220,7 +217,7 @@ public class I18nUtil {
|
||||
* String of the message
|
||||
*/
|
||||
public static String getMessage(String key) {
|
||||
return getMessage(key.trim(), DEFAULTLOCALE);
|
||||
return getMessage(key.trim(), getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +230,7 @@ public class I18nUtil {
|
||||
*/
|
||||
public static String getMessage(String key, Locale locale) {
|
||||
if (locale == null) {
|
||||
locale = DEFAULTLOCALE;
|
||||
locale = getDefaultLocale();
|
||||
}
|
||||
ResourceBundle.Control control =
|
||||
ResourceBundle.Control.getNoFallbackControl(
|
||||
@@ -384,4 +381,23 @@ public class I18nUtil {
|
||||
}
|
||||
return resultList.toArray(new Locale[resultList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the input locale is in the list of supported locales
|
||||
* @param locale
|
||||
* @return true if locale is supported, false otherwise
|
||||
*/
|
||||
public static boolean isSupportedLocale(Locale locale) {
|
||||
boolean isSupported = false;
|
||||
Locale[] supportedLocales = getSupportedLocales();
|
||||
if (supportedLocales != null) {
|
||||
for (Locale sLocale: supportedLocales) {
|
||||
if (locale.getLanguage().equals(sLocale.getLanguage()) ) {
|
||||
isSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isSupported;
|
||||
}
|
||||
}
|
||||
|
@@ -199,6 +199,9 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
docBuilder = factory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException pcE) {
|
||||
log.error("caught exception: " + pcE);
|
||||
|
@@ -38,7 +38,7 @@ public interface CitationDocumentService {
|
||||
* Citation enabled globally (all citable bitstreams will get "watermarked") modules/disseminate-citation:
|
||||
* enable_globally
|
||||
* OR
|
||||
* The container is this object is whitelist enabled.
|
||||
* The container is this object is "allow list" enabled.
|
||||
* - community: modules/disseminate-citation: enabled_communities
|
||||
* - collection: modules/disseminate-citation: enabled_collections
|
||||
* AND
|
||||
|
@@ -12,6 +12,7 @@ import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
@@ -22,6 +23,7 @@ import org.dspace.core.Utils;
|
||||
import org.dspace.eperson.service.AccountService;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.eperson.service.RegistrationDataService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
@@ -47,6 +49,8 @@ public class AccountServiceImpl implements AccountService {
|
||||
protected EPersonService ePersonService;
|
||||
@Autowired(required = true)
|
||||
protected RegistrationDataService registrationDataService;
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
protected AccountServiceImpl() {
|
||||
|
||||
@@ -67,6 +71,9 @@ public class AccountServiceImpl implements AccountService {
|
||||
public void sendRegistrationInfo(Context context, String email)
|
||||
throws SQLException, IOException, MessagingException,
|
||||
AuthorizeException {
|
||||
if (!configurationService.getBooleanProperty("user.registration", true)) {
|
||||
throw new IllegalStateException("The user.registration parameter was set to false");
|
||||
}
|
||||
sendInfo(context, email, true, true);
|
||||
}
|
||||
|
||||
@@ -155,6 +162,14 @@ public class AccountServiceImpl implements AccountService {
|
||||
registrationDataService.deleteByToken(context, token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyPasswordStructure(String password) {
|
||||
if (StringUtils.length(password) < 6) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* THIS IS AN INTERNAL METHOD. THE SEND PARAMETER ALLOWS IT TO BE USED FOR
|
||||
* TESTING PURPOSES.
|
||||
@@ -233,8 +248,8 @@ public class AccountServiceImpl implements AccountService {
|
||||
// Note change from "key=" to "token="
|
||||
String specialLink = new StringBuffer().append(base).append(
|
||||
base.endsWith("/") ? "" : "/").append(
|
||||
isRegister ? "register" : "forgot").append("?")
|
||||
.append("token=").append(rd.getToken())
|
||||
isRegister ? "register" : "forgot").append("/")
|
||||
.append(rd.getToken())
|
||||
.toString();
|
||||
Locale locale = context.getCurrentLocale();
|
||||
Email bean = Email.getEmail(I18nUtil.getEmailFilename(locale, isRegister ? "register"
|
||||
|
@@ -189,7 +189,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl<Group> implements
|
||||
return false;
|
||||
|
||||
// special, everyone is member of group 0 (anonymous)
|
||||
} else if (StringUtils.equals(group.getName(), Group.ANONYMOUS)) {
|
||||
} else if (StringUtils.equals(group.getName(), Group.ANONYMOUS) ||
|
||||
isParentOf(context, group, findByName(context, Group.ANONYMOUS))) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
@@ -46,4 +46,11 @@ public interface AccountService {
|
||||
|
||||
public void deleteToken(Context context, String token)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* This method verifies that a certain String adheres to the password rules for DSpace
|
||||
* @param password The String to be checked
|
||||
* @return A boolean indicating whether or not the given String adheres to the password rules
|
||||
*/
|
||||
public boolean verifyPasswordStructure(String password);
|
||||
}
|
||||
|
@@ -134,11 +134,13 @@ public class HarvestScheduler implements Runnable {
|
||||
if (maxActiveThreads == 0) {
|
||||
maxActiveThreads = 3;
|
||||
}
|
||||
minHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.minHeartbeat") * 1000;
|
||||
minHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.minHeartbeat");
|
||||
minHeartbeat = minHeartbeat * 1000; // multiple by 1000 to turn seconds to ms
|
||||
if (minHeartbeat == 0) {
|
||||
minHeartbeat = 30000;
|
||||
}
|
||||
maxHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.maxHeartbeat") * 1000;
|
||||
maxHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.maxHeartbeat");
|
||||
maxHeartbeat = maxHeartbeat * 1000; // multiple by 1000 to turn seconds to ms
|
||||
if (maxHeartbeat == 0) {
|
||||
maxHeartbeat = 3600000;
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ public class SimpleXpathMetadatumContributor implements MetadataContributor<OMEl
|
||||
* @param query query string
|
||||
* @param prefixToNamespaceMapping metadata prefix to namespace mapping
|
||||
* @param field
|
||||
* <a href="https://github.com/DSpace/DSpace/tree/master/dspace-api/src/main/java/org/dspace/importer/external#metadata-mapping-">MetadataFieldConfig</a>
|
||||
* <a href="https://github.com/DSpace/DSpace/tree/main/dspace-api/src/main/java/org/dspace/importer/external#metadata-mapping-">MetadataFieldConfig</a>
|
||||
*/
|
||||
public SimpleXpathMetadatumContributor(String query, Map<String, String> prefixToNamespaceMapping,
|
||||
MetadataFieldConfig field) {
|
||||
|
@@ -8,6 +8,8 @@
|
||||
package org.dspace.license;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wbossons
|
||||
*/
|
||||
@@ -15,17 +17,17 @@ public class CCLicense {
|
||||
|
||||
private String licenseName;
|
||||
private String licenseId;
|
||||
private int order = 0;
|
||||
private List<CCLicenseField> ccLicenseFieldList;
|
||||
|
||||
public CCLicense() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CCLicense(String licenseId, String licenseName, int order) {
|
||||
public CCLicense(String licenseId, String licenseName, List<CCLicenseField> ccLicenseFieldList) {
|
||||
super();
|
||||
this.licenseId = licenseId;
|
||||
this.licenseName = licenseName;
|
||||
this.order = order;
|
||||
this.ccLicenseFieldList = ccLicenseFieldList;
|
||||
}
|
||||
|
||||
public String getLicenseName() {
|
||||
@@ -44,13 +46,19 @@ public class CCLicense {
|
||||
this.licenseId = licenseId;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
/**
|
||||
* Gets the list of CC License Fields
|
||||
* @return the list of CC License Fields
|
||||
*/
|
||||
public List<CCLicenseField> getCcLicenseFieldList() {
|
||||
return ccLicenseFieldList;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
/**
|
||||
* Sets the list of CC License Fields
|
||||
* @param ccLicenseFieldList
|
||||
*/
|
||||
public void setCcLicenseFieldList(final List<CCLicenseField> ccLicenseFieldList) {
|
||||
this.ccLicenseFieldList = ccLicenseFieldList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jdom.Document;
|
||||
|
||||
/**
|
||||
* Service interface class for the Creative commons license connector service.
|
||||
* The implementation of this class is responsible for all the calls to the CC license API and parsing the response
|
||||
* The service is autowired by spring
|
||||
*/
|
||||
public interface CCLicenseConnectorService {
|
||||
|
||||
/**
|
||||
* Retrieves the CC Licenses for the provided language from the CC License API
|
||||
*
|
||||
* @param language - the language to retrieve the licenses for
|
||||
* @return a map of licenses with the id and the license for the provided language
|
||||
*/
|
||||
public Map<String, CCLicense> retrieveLicenses(String language);
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
|
||||
* the CC License API
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the CC License URI
|
||||
*/
|
||||
public String retrieveRightsByQuestion(String licenseId,
|
||||
String language,
|
||||
Map<String, String> answerMap);
|
||||
|
||||
/**
|
||||
* Retrieve the license RDF document based on the license URI
|
||||
*
|
||||
* @param licenseURI - The license URI for which to retrieve the license RDF document
|
||||
* @return the license RDF document
|
||||
* @throws IOException
|
||||
*/
|
||||
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve the license Name from the license document
|
||||
*
|
||||
* @param doc - The license document from which to retrieve the license name
|
||||
* @return the license name
|
||||
*/
|
||||
public String retrieveLicenseName(final Document doc);
|
||||
|
||||
}
|
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.jaxen.JaxenException;
|
||||
import org.jaxen.jdom.JDOMXPath;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.input.SAXBuilder;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* Implementation for the Creative commons license connector service.
|
||||
* This class is responsible for all the calls to the CC license API and parsing the response
|
||||
*/
|
||||
public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService, InitializingBean {
|
||||
|
||||
private Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLicenseConnectorServiceImpl.class);
|
||||
|
||||
private CloseableHttpClient client;
|
||||
protected SAXBuilder parser = new SAXBuilder();
|
||||
|
||||
private String postArgument = "answers";
|
||||
private String postAnswerFormat =
|
||||
"<answers> " +
|
||||
"<locale>{1}</locale>" +
|
||||
"<license-{0}>" +
|
||||
"{2}" +
|
||||
"</license-{0}>" +
|
||||
"</answers>";
|
||||
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
|
||||
client = builder
|
||||
.disableAutomaticRetries()
|
||||
.setMaxConnTotal(5)
|
||||
.build();
|
||||
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CC Licenses for the provided language from the CC License API
|
||||
*
|
||||
* @param language - the language to retrieve the licenses for
|
||||
* @return a map of licenses with the id and the license for the provided language
|
||||
*/
|
||||
public Map<String, CCLicense> retrieveLicenses(String language) {
|
||||
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
|
||||
|
||||
String uri = ccLicenseUrl + "/?locale=" + language;
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
|
||||
List<String> licenses;
|
||||
try (CloseableHttpResponse response = client.execute(httpGet)) {
|
||||
licenses = retrieveLicenses(response);
|
||||
} catch (JDOMException | JaxenException | IOException e) {
|
||||
log.error("Error while retrieving the license details using url: " + uri, e);
|
||||
licenses = Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<String, CCLicense> ccLicenses = new HashMap<>();
|
||||
|
||||
for (String license : licenses) {
|
||||
|
||||
String licenseUri = ccLicenseUrl + "/license/" + license;
|
||||
HttpGet licenseHttpGet = new HttpGet(licenseUri);
|
||||
try (CloseableHttpResponse response = client.execute(licenseHttpGet)) {
|
||||
CCLicense ccLicense = retrieveLicenseObject(license, response);
|
||||
ccLicenses.put(ccLicense.getLicenseId(), ccLicense);
|
||||
} catch (JaxenException | JDOMException | IOException e) {
|
||||
log.error("Error while retrieving the license details using url: " + licenseUri, e);
|
||||
}
|
||||
}
|
||||
|
||||
return ccLicenses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of licenses from the response from the CC License API and remove the licenses configured
|
||||
* to be excluded
|
||||
*
|
||||
* @param response The response from the API
|
||||
* @return a list of license identifiers for which details need to be retrieved
|
||||
* @throws IOException
|
||||
* @throws JaxenException
|
||||
* @throws JDOMException
|
||||
*/
|
||||
private List<String> retrieveLicenses(CloseableHttpResponse response)
|
||||
throws IOException, JaxenException, JDOMException {
|
||||
|
||||
List<String> domains = new LinkedList<>();
|
||||
String[] excludedLicenses = configurationService.getArrayProperty("cc.license.classfilter");
|
||||
|
||||
|
||||
String responseString = EntityUtils.toString(response.getEntity());
|
||||
JDOMXPath licenseClassXpath = new JDOMXPath("//licenses/license");
|
||||
|
||||
|
||||
try (StringReader stringReader = new StringReader(responseString)) {
|
||||
InputSource is = new InputSource(stringReader);
|
||||
org.jdom.Document classDoc = this.parser.build(is);
|
||||
|
||||
List<Element> elements = licenseClassXpath.selectNodes(classDoc);
|
||||
for (Element element : elements) {
|
||||
String licenseId = getSingleNodeValue(element, "@id");
|
||||
if (StringUtils.isNotBlank(licenseId) && !ArrayUtils.contains(excludedLicenses, licenseId)) {
|
||||
domains.add(licenseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return domains;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the response for a single CC License and return the corresponding CC License Object
|
||||
*
|
||||
* @param licenseId the license id of the CC License to retrieve
|
||||
* @param response for a specific CC License response
|
||||
* @return the corresponding CC License Object
|
||||
* @throws IOException
|
||||
* @throws JaxenException
|
||||
* @throws JDOMException
|
||||
*/
|
||||
private CCLicense retrieveLicenseObject(final String licenseId, CloseableHttpResponse response)
|
||||
throws IOException, JaxenException, JDOMException {
|
||||
|
||||
String responseString = EntityUtils.toString(response.getEntity());
|
||||
|
||||
|
||||
JDOMXPath licenseClassXpath = new JDOMXPath("//licenseclass");
|
||||
JDOMXPath licenseFieldXpath = new JDOMXPath("field");
|
||||
|
||||
|
||||
try (StringReader stringReader = new StringReader(responseString)) {
|
||||
InputSource is = new InputSource(stringReader);
|
||||
|
||||
org.jdom.Document classDoc = this.parser.build(is);
|
||||
|
||||
Object element = licenseClassXpath.selectSingleNode(classDoc);
|
||||
String licenseLabel = getSingleNodeValue(element, "label");
|
||||
|
||||
List<CCLicenseField> ccLicenseFields = new LinkedList<>();
|
||||
|
||||
List<Element> licenseFields = licenseFieldXpath.selectNodes(element);
|
||||
for (Element licenseField : licenseFields) {
|
||||
CCLicenseField ccLicenseField = parseLicenseField(licenseField);
|
||||
ccLicenseFields.add(ccLicenseField);
|
||||
}
|
||||
|
||||
return new CCLicense(licenseId, licenseLabel, ccLicenseFields);
|
||||
}
|
||||
}
|
||||
|
||||
private CCLicenseField parseLicenseField(final Element licenseField) throws JaxenException {
|
||||
String id = getSingleNodeValue(licenseField, "@id");
|
||||
String label = getSingleNodeValue(licenseField, "label");
|
||||
String description = getSingleNodeValue(licenseField, "description");
|
||||
|
||||
JDOMXPath enumXpath = new JDOMXPath("enum");
|
||||
List<Element> enums = enumXpath.selectNodes(licenseField);
|
||||
|
||||
List<CCLicenseFieldEnum> ccLicenseFieldEnumList = new LinkedList<>();
|
||||
|
||||
for (Element enumElement : enums) {
|
||||
CCLicenseFieldEnum ccLicenseFieldEnum = parseEnum(enumElement);
|
||||
ccLicenseFieldEnumList.add(ccLicenseFieldEnum);
|
||||
}
|
||||
|
||||
return new CCLicenseField(id, label, description, ccLicenseFieldEnumList);
|
||||
|
||||
}
|
||||
|
||||
private CCLicenseFieldEnum parseEnum(final Element enumElement) throws JaxenException {
|
||||
String id = getSingleNodeValue(enumElement, "@id");
|
||||
String label = getSingleNodeValue(enumElement, "label");
|
||||
String description = getSingleNodeValue(enumElement, "description");
|
||||
|
||||
return new CCLicenseFieldEnum(id, label, description);
|
||||
}
|
||||
|
||||
|
||||
private String getNodeValue(final Object el) {
|
||||
if (el instanceof Element) {
|
||||
return ((Element) el).getValue();
|
||||
} else if (el instanceof Attribute) {
|
||||
return ((Attribute) el).getValue();
|
||||
} else if (el instanceof String) {
|
||||
return (String) el;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSingleNodeValue(final Object t, String query) throws JaxenException {
|
||||
JDOMXPath xpath = new JDOMXPath(query);
|
||||
Object singleNode = xpath.selectSingleNode(t);
|
||||
|
||||
return getNodeValue(singleNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
|
||||
* the CC License API
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the CC License URI
|
||||
*/
|
||||
public String retrieveRightsByQuestion(String licenseId,
|
||||
String language,
|
||||
Map<String, String> answerMap) {
|
||||
|
||||
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
|
||||
|
||||
|
||||
HttpPost httpPost = new HttpPost(ccLicenseUrl + "/license/" + licenseId + "/issue");
|
||||
|
||||
|
||||
String answers = createAnswerString(answerMap);
|
||||
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||
String text = MessageFormat.format(postAnswerFormat, licenseId, language, answers);
|
||||
builder.addTextBody(postArgument, text);
|
||||
|
||||
HttpEntity multipart = builder.build();
|
||||
|
||||
httpPost.setEntity(multipart);
|
||||
|
||||
try (CloseableHttpResponse response = client.execute(httpPost)) {
|
||||
return retrieveLicenseUri(response);
|
||||
} catch (JDOMException | JaxenException | IOException e) {
|
||||
log.error("Error while retrieving the license uri for license : " + licenseId + " with answers "
|
||||
+ answerMap.toString(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the response for the CC License URI request and return the corresponding CC License URI
|
||||
*
|
||||
* @param response for a specific CC License URI response
|
||||
* @return the corresponding CC License URI as a string
|
||||
* @throws IOException
|
||||
* @throws JaxenException
|
||||
* @throws JDOMException
|
||||
*/
|
||||
private String retrieveLicenseUri(final CloseableHttpResponse response)
|
||||
throws IOException, JaxenException, JDOMException {
|
||||
|
||||
String responseString = EntityUtils.toString(response.getEntity());
|
||||
JDOMXPath licenseClassXpath = new JDOMXPath("//result/license-uri");
|
||||
|
||||
|
||||
try (StringReader stringReader = new StringReader(responseString)) {
|
||||
InputSource is = new InputSource(stringReader);
|
||||
org.jdom.Document classDoc = this.parser.build(is);
|
||||
|
||||
Object node = licenseClassXpath.selectSingleNode(classDoc);
|
||||
String nodeValue = getNodeValue(node);
|
||||
|
||||
if (StringUtils.isNotBlank(nodeValue)) {
|
||||
return nodeValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String createAnswerString(final Map<String, String> parameterMap) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String key : parameterMap.keySet()) {
|
||||
sb.append("<");
|
||||
sb.append(key);
|
||||
sb.append(">");
|
||||
sb.append(parameterMap.get(key));
|
||||
sb.append("</");
|
||||
sb.append(key);
|
||||
sb.append(">");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the license RDF document based on the license URI
|
||||
*
|
||||
* @param licenseURI - The license URI for which to retrieve the license RDF document
|
||||
* @return the license RDF document
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
|
||||
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
|
||||
|
||||
String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI;
|
||||
|
||||
URL request_url;
|
||||
try {
|
||||
request_url = new URL(issueUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
URLConnection connection = request_url.openConnection();
|
||||
connection.setDoOutput(true);
|
||||
try {
|
||||
// parsing document from input stream
|
||||
InputStream stream = connection.getInputStream();
|
||||
Document doc = parser.build(stream);
|
||||
return doc;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error while retrieving the license document for URI: " + licenseURI, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the license Name from the license document
|
||||
*
|
||||
* @param doc - The license document from which to retrieve the license name
|
||||
* @return the license name
|
||||
*/
|
||||
public String retrieveLicenseName(final Document doc) {
|
||||
try {
|
||||
return getSingleNodeValue(doc, "//result/license-name");
|
||||
} catch (JaxenException e) {
|
||||
log.error("Error while retrieving the license name from the license document", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -7,8 +7,7 @@
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper class for representation of a license field declaration.
|
||||
@@ -22,7 +21,7 @@ public class CCLicenseField {
|
||||
private String description = "";
|
||||
private String type = "";
|
||||
|
||||
private HashMap fieldEnum = null;
|
||||
private List<CCLicenseFieldEnum> fieldEnum = null;
|
||||
|
||||
/**
|
||||
* Construct a new LicenseField class. Note that after construction,
|
||||
@@ -31,13 +30,11 @@ public class CCLicenseField {
|
||||
* @param id The unique identifier for this field; this value will be used in constructing the answers XML.
|
||||
* @param label The label to use when generating the user interface.
|
||||
*/
|
||||
public CCLicenseField(String id, String label) {
|
||||
super();
|
||||
|
||||
this.fieldEnum = new HashMap();
|
||||
|
||||
public CCLicenseField(String id, String label, String description, List<CCLicenseFieldEnum> fieldEnum) {
|
||||
this.id = id;
|
||||
this.label = label;
|
||||
this.description = description;
|
||||
this.fieldEnum = fieldEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,16 +87,12 @@ public class CCLicenseField {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns an instance implementing the Map interface;
|
||||
* the instance contains a mapping from identifiers to
|
||||
* labels for the enumeration values.
|
||||
* @see Map
|
||||
* Returns the list of enums of this field
|
||||
* @return the list of enums of this field
|
||||
*/
|
||||
public Map<String, String> getEnum() {
|
||||
return this.fieldEnum;
|
||||
public List<CCLicenseFieldEnum> getFieldEnum() {
|
||||
return fieldEnum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Wrapper class for representation of a license field enum declaration.
|
||||
* A field enum is a single "answer" to the field question
|
||||
*/
|
||||
public class CCLicenseFieldEnum {
|
||||
|
||||
private String id = "";
|
||||
private String label = "";
|
||||
private String description = "";
|
||||
|
||||
public CCLicenseFieldEnum(String id, String label, String description) {
|
||||
if (StringUtils.isNotBlank(id)) {
|
||||
this.id = id;
|
||||
}
|
||||
if (StringUtils.isNotBlank(label)) {
|
||||
this.label = label;
|
||||
}
|
||||
if (StringUtils.isNotBlank(description)) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of this enum
|
||||
* @return the id of this enum
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id of this enum
|
||||
* @param id
|
||||
*/
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label of this enum
|
||||
* @return the label of this enum
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label of this enum
|
||||
* @param label
|
||||
*/
|
||||
public void setLabel(final String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the description of this enum
|
||||
* @return the description of this enum
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the description of this enum
|
||||
* @param description
|
||||
*/
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
@@ -1,435 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.license.factory.LicenseServiceFactory;
|
||||
import org.dspace.license.service.CreativeCommonsService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.jaxen.JaxenException;
|
||||
import org.jaxen.jdom.JDOMXPath;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.input.SAXBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper around Creative Commons REST web services.
|
||||
*
|
||||
* @author Wendy Bossons
|
||||
*/
|
||||
public class CCLookup {
|
||||
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLookup.class);
|
||||
|
||||
private String cc_root;
|
||||
private String jurisdiction;
|
||||
private List<String> lcFilter = new ArrayList<String>();
|
||||
|
||||
private Document license_doc = null;
|
||||
private String rdfString = null;
|
||||
private String errorMessage = null;
|
||||
private boolean success = false;
|
||||
|
||||
private SAXBuilder parser = new SAXBuilder();
|
||||
private List<CCLicense> licenses = new ArrayList<CCLicense>();
|
||||
private List<CCLicenseField> licenseFields = new ArrayList<CCLicenseField>();
|
||||
|
||||
protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance()
|
||||
.getCreativeCommonsService();
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the default web services root.
|
||||
*/
|
||||
public CCLookup() {
|
||||
super();
|
||||
|
||||
ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
cc_root = configurationService.getProperty("cc.api.rooturl");
|
||||
|
||||
String jurisProp = configurationService.getProperty("cc.license.jurisdiction");
|
||||
jurisdiction = (jurisProp != null) ? jurisProp : "";
|
||||
|
||||
String[] filters = configurationService.getArrayProperty("cc.license.classfilter");
|
||||
if (filters != null) {
|
||||
for (String name : filters) {
|
||||
lcFilter.add(name.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id for a particular CCLicense label. Returns an
|
||||
* empty string if no match is found.
|
||||
*
|
||||
* @param class_label The CCLicense label to find.
|
||||
* @return Returns a String containing the License class ID if the label
|
||||
* is found; if not found, returns an empty string.
|
||||
* @see CCLicense
|
||||
*/
|
||||
public String getLicenseId(String class_label) {
|
||||
for (int i = 0; i < this.licenses.size(); i++) {
|
||||
if (((CCLicense) this.licenses.get(i)).getLicenseName().equals(class_label)) {
|
||||
return ((CCLicense) this.licenses.get(i)).getLicenseId();
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the web service for the available licenses.
|
||||
*
|
||||
* @param language The language to request labels and description strings in.
|
||||
* @return Returns a Map of CCLicense objects.
|
||||
* @see Map
|
||||
* @see CCLicense
|
||||
*/
|
||||
public Collection<CCLicense> getLicenses(String language) {
|
||||
|
||||
// create XPath expressions
|
||||
try {
|
||||
JDOMXPath xp_Licenses = new JDOMXPath("//licenses/license");
|
||||
JDOMXPath xp_LicenseID = new JDOMXPath("@id");
|
||||
URL classUrl = new URL(this.cc_root + "/?locale=" + language);
|
||||
Document classDoc = this.parser.build(classUrl);
|
||||
// extract the identifiers and labels using XPath
|
||||
List<Element> results = xp_Licenses.selectNodes(classDoc);
|
||||
// populate licenses container
|
||||
this.licenses.clear();
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
Element license = results.get(i);
|
||||
// add if not filtered
|
||||
String liD = ((Attribute) xp_LicenseID.selectSingleNode(license)).getValue();
|
||||
if (!lcFilter.contains(liD)) {
|
||||
this.licenses.add(new CCLicense(liD, license.getText(), i));
|
||||
}
|
||||
}
|
||||
} catch (JaxenException jaxen_e) {
|
||||
return null;
|
||||
} catch (JDOMException jdom_e) {
|
||||
return null;
|
||||
} catch (IOException io_e) {
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
// do nothing... but we should
|
||||
return null;
|
||||
}
|
||||
|
||||
return licenses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queries the web service for a set of licenseFields for a particular license class.
|
||||
*
|
||||
* @param license A String specifying the CCLicense identifier to
|
||||
* retrieve fields for.
|
||||
* @param language the locale string
|
||||
* @return A Collection of LicenseField objects.
|
||||
* @see CCLicense
|
||||
*/
|
||||
public Collection<CCLicenseField> getLicenseFields(String license, String language) {
|
||||
|
||||
JDOMXPath xp_LicenseField;
|
||||
JDOMXPath xp_LicenseID;
|
||||
JDOMXPath xp_FieldType;
|
||||
JDOMXPath xp_Description;
|
||||
JDOMXPath xp_Label;
|
||||
JDOMXPath xp_Enum;
|
||||
|
||||
Document fieldDoc;
|
||||
|
||||
URL classUrl;
|
||||
List results = null;
|
||||
List enumOptions = null;
|
||||
|
||||
// create XPath expressions
|
||||
try {
|
||||
xp_LicenseField = new JDOMXPath("//field");
|
||||
xp_LicenseID = new JDOMXPath("@id");
|
||||
xp_Description = new JDOMXPath("description");
|
||||
xp_Label = new JDOMXPath("label");
|
||||
xp_FieldType = new JDOMXPath("type");
|
||||
xp_Enum = new JDOMXPath("enum");
|
||||
|
||||
} catch (JaxenException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// retrieve and parse the license class document
|
||||
try {
|
||||
classUrl = new URL(this.cc_root + "/license/" + license + "?locale=" + language);
|
||||
} catch (Exception err) {
|
||||
// do nothing... but we should
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse the licenses document
|
||||
try {
|
||||
fieldDoc = this.parser.build(classUrl);
|
||||
} catch (JDOMException e) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// reset the field definition container
|
||||
this.licenseFields.clear();
|
||||
|
||||
// extract the identifiers and labels using XPath
|
||||
try {
|
||||
results = xp_LicenseField.selectNodes(fieldDoc);
|
||||
} catch (JaxenException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
Element field = (Element) results.get(i);
|
||||
|
||||
try {
|
||||
// create the field object
|
||||
CCLicenseField cclicensefield = new CCLicenseField(
|
||||
((Attribute) xp_LicenseID.selectSingleNode(field)).getValue(),
|
||||
((Element) xp_Label.selectSingleNode(field)).getText());
|
||||
|
||||
// extract additional properties
|
||||
cclicensefield.setDescription(((Element) xp_Description.selectSingleNode(field)).getText());
|
||||
cclicensefield.setType(((Element) xp_FieldType.selectSingleNode(field)).getText());
|
||||
|
||||
enumOptions = xp_Enum.selectNodes(field);
|
||||
|
||||
for (int j = 0; j < enumOptions.size(); j++) {
|
||||
String id = ((Attribute) xp_LicenseID.selectSingleNode(enumOptions.get(j))).getValue();
|
||||
String label = ((Element) xp_Label.selectSingleNode(enumOptions.get(j))).getText();
|
||||
|
||||
cclicensefield.getEnum().put(id, label);
|
||||
|
||||
} // for each enum option
|
||||
|
||||
this.licenseFields.add(cclicensefield);
|
||||
} catch (JaxenException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return licenseFields;
|
||||
} // licenseFields
|
||||
|
||||
/**
|
||||
* Passes a set of "answers" to the web service and retrieves a license.
|
||||
*
|
||||
* @param licenseId The identifier of the license class being requested.
|
||||
* @param answers A Map containing the answers to the license fields;
|
||||
* each key is the identifier of a LicenseField, with the value
|
||||
* containing the user-supplied answer.
|
||||
* @param lang The language to request localized elements in.
|
||||
* @throws IOException if IO error
|
||||
* @see CCLicense
|
||||
* @see Map
|
||||
*/
|
||||
public void issue(String licenseId, Map answers, String lang)
|
||||
throws IOException {
|
||||
|
||||
// Determine the issue URL
|
||||
String issueUrl = this.cc_root + "/license/" + licenseId + "/issue";
|
||||
// Assemble the "answers" document
|
||||
String answer_doc = "<answers>\n<locale>" + lang + "</locale>\n" + "<license-" + licenseId + ">\n";
|
||||
Iterator keys = answers.keySet().iterator();
|
||||
|
||||
try {
|
||||
String current = (String) keys.next();
|
||||
|
||||
while (true) {
|
||||
answer_doc += "<" + current + ">" + (String) answers.get(current) + "</" + current + ">\n";
|
||||
current = (String) keys.next();
|
||||
}
|
||||
|
||||
|
||||
} catch (NoSuchElementException e) {
|
||||
// exception indicates we've iterated through the
|
||||
// entire collection; just swallow and continue
|
||||
}
|
||||
// answer_doc += "<jurisdiction></jurisidiction>\n"; FAILS with jurisdiction argument
|
||||
answer_doc += "</license-" + licenseId + ">\n</answers>\n";
|
||||
String post_data;
|
||||
|
||||
try {
|
||||
post_data = URLEncoder.encode("answers", "UTF-8") + "=" + URLEncoder.encode(answer_doc, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
URL post_url;
|
||||
try {
|
||||
post_url = new URL(issueUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return;
|
||||
}
|
||||
URLConnection connection = post_url.openConnection();
|
||||
// this will not be needed after I'm done TODO: remove
|
||||
connection.setDoOutput(true);
|
||||
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
|
||||
writer.write(post_data);
|
||||
writer.flush();
|
||||
// end TODO
|
||||
try {
|
||||
// parsing document from input stream
|
||||
java.io.InputStream stream = connection.getInputStream();
|
||||
this.license_doc = this.parser.build(stream);
|
||||
} catch (JDOMException jde) {
|
||||
log.warn(jde.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getCause());
|
||||
}
|
||||
return;
|
||||
} // issue
|
||||
|
||||
/**
|
||||
* Passes a set of "answers" to the web service and retrieves a license.
|
||||
*
|
||||
* @param licenseURI The uri of the license.
|
||||
*
|
||||
* Note: does not support localization in 1.5 -- not yet
|
||||
* @throws IOException if IO error
|
||||
* @see CCLicense
|
||||
* @see Map
|
||||
*/
|
||||
public void issue(String licenseURI)
|
||||
throws IOException {
|
||||
|
||||
// Determine the issue URL
|
||||
// Example: http://api.creativecommons.org/rest/1.5/details?
|
||||
// license-uri=http://creativecommons.org/licenses/by-nc-sa/3.0/
|
||||
String issueUrl = cc_root + "/details?license-uri=" + licenseURI;
|
||||
|
||||
URL request_url;
|
||||
try {
|
||||
request_url = new URL(issueUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return;
|
||||
}
|
||||
URLConnection connection = request_url.openConnection();
|
||||
// this will not be needed after I'm done TODO: remove
|
||||
connection.setDoOutput(true);
|
||||
try {
|
||||
// parsing document from input stream
|
||||
java.io.InputStream stream = connection.getInputStream();
|
||||
license_doc = this.parser.build(stream);
|
||||
} catch (JDOMException jde) {
|
||||
log.warn(jde.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getCause());
|
||||
}
|
||||
return;
|
||||
} // issue
|
||||
|
||||
/**
|
||||
* Retrieves the URI for the license issued.
|
||||
*
|
||||
* @return A String containing the URI for the license issued.
|
||||
*/
|
||||
public String getLicenseUrl() {
|
||||
String text = null;
|
||||
try {
|
||||
JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-uri");
|
||||
text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
setSuccess(false);
|
||||
text = "An error occurred getting the license - uri.";
|
||||
} finally {
|
||||
return text;
|
||||
}
|
||||
} // getLicenseUrl
|
||||
|
||||
/**
|
||||
* Retrieves the human readable name for the license issued.
|
||||
*
|
||||
* @return A String containing the license name.
|
||||
*/
|
||||
public String getLicenseName() {
|
||||
String text = null;
|
||||
try {
|
||||
JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-name");
|
||||
text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
setSuccess(false);
|
||||
text = "An error occurred on the license name.";
|
||||
} finally {
|
||||
return text;
|
||||
}
|
||||
} // getLicenseName
|
||||
|
||||
|
||||
public org.jdom.Document getLicenseDocument() {
|
||||
return this.license_doc;
|
||||
}
|
||||
|
||||
public String getRdf()
|
||||
throws IOException {
|
||||
String result = "";
|
||||
try {
|
||||
result = creativeCommonsService.fetchLicenseRDF(license_doc);
|
||||
} catch (Exception e) {
|
||||
log.warn("An error occurred getting the rdf . . ." + e.getMessage());
|
||||
setSuccess(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
setSuccess(false);
|
||||
JDOMXPath xp_Success;
|
||||
String text = null;
|
||||
try {
|
||||
xp_Success = new JDOMXPath("//message");
|
||||
text = ((Element) xp_Success.selectSingleNode(this.license_doc)).getText();
|
||||
setErrorMessage(text);
|
||||
} catch (Exception e) {
|
||||
log.warn("There was an issue . . . " + text);
|
||||
setSuccess(true);
|
||||
}
|
||||
return this.success;
|
||||
}
|
||||
|
||||
private void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return this.errorMessage;
|
||||
}
|
||||
|
||||
private void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
}
|
@@ -13,7 +13,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.transform.Templates;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
@@ -82,9 +85,18 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
protected BundleService bundleService;
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
@Autowired
|
||||
protected CCLicenseConnectorService ccLicenseConnectorService;
|
||||
|
||||
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private String defaultLanguage;
|
||||
private String jurisdiction;
|
||||
private static final String JURISDICTION_KEY = "jurisdiction";
|
||||
|
||||
|
||||
private Map<String, Map<String, CCLicense>> ccLicenses;
|
||||
|
||||
protected CreativeCommonsServiceImpl() {
|
||||
|
||||
}
|
||||
@@ -101,10 +113,14 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
System.setProperty("http.proxyPort", proxyPort);
|
||||
}
|
||||
|
||||
ccLicenses = new HashMap<>();
|
||||
defaultLanguage = configurationService.getProperty("cc.license.locale", "en");
|
||||
jurisdiction = configurationService.getProperty("cc.license.jurisdiction", "");
|
||||
|
||||
try {
|
||||
templates = TransformerFactory.newInstance().newTemplates(
|
||||
new StreamSource(CreativeCommonsServiceImpl.class
|
||||
.getResourceAsStream("CreativeCommons.xsl")));
|
||||
new StreamSource(CreativeCommonsServiceImpl.class
|
||||
.getResourceAsStream("CreativeCommons.xsl")));
|
||||
} catch (TransformerConfigurationException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
@@ -112,15 +128,10 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// create the CC bundle if it doesn't exist
|
||||
// If it does, remove it and create a new one.
|
||||
protected Bundle getCcBundle(Context context, Item item)
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
throws SQLException, AuthorizeException, IOException {
|
||||
List<Bundle> bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
|
||||
|
||||
if ((bundles.size() > 0) && (bundles.get(0) != null)) {
|
||||
@@ -131,8 +142,8 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
|
||||
@Override
|
||||
public void setLicenseRDF(Context context, Item item, String licenseRdf)
|
||||
throws SQLException, IOException,
|
||||
AuthorizeException {
|
||||
throws SQLException, IOException,
|
||||
AuthorizeException {
|
||||
Bundle bundle = getCcBundle(context, item);
|
||||
// set the format
|
||||
BitstreamFormat bs_rdf_format = bitstreamFormatService.findByShortDescription(context, "RDF XML");
|
||||
@@ -144,7 +155,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
@Override
|
||||
public void setLicense(Context context, Item item,
|
||||
InputStream licenseStm, String mimeType)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
Bundle bundle = getCcBundle(context, item);
|
||||
|
||||
// set the format
|
||||
@@ -160,17 +171,26 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
Bitstream bs = bitstreamService.create(context, bundle, licenseStm);
|
||||
bs.setSource(context, CC_BS_SOURCE);
|
||||
bs.setName(context, (mimeType != null &&
|
||||
(mimeType.equalsIgnoreCase("text/xml") ||
|
||||
mimeType.equalsIgnoreCase("text/rdf"))) ?
|
||||
BSN_LICENSE_RDF : BSN_LICENSE_TEXT);
|
||||
(mimeType.equalsIgnoreCase("text/xml") ||
|
||||
mimeType.equalsIgnoreCase("text/rdf"))) ?
|
||||
BSN_LICENSE_RDF : BSN_LICENSE_TEXT);
|
||||
bs.setFormat(context, bs_format);
|
||||
bitstreamService.update(context, bs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the license file from the item
|
||||
*
|
||||
* @param context - The relevant DSpace Context
|
||||
* @param item - The item from which the license file needs to be removed
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@Override
|
||||
public void removeLicense(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
public void removeLicenseFile(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
// remove CC license bundle if one exists
|
||||
List<Bundle> bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
|
||||
|
||||
@@ -179,66 +199,74 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLicense(Context context, Item item)
|
||||
throws SQLException, IOException {
|
||||
// try to find CC license bundle
|
||||
List<Bundle> bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
|
||||
|
||||
if (bundles.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify it has correct contents
|
||||
try {
|
||||
if ((getLicenseURL(context, item) == null)) {
|
||||
return false;
|
||||
}
|
||||
} catch (AuthorizeException ae) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLicenseRDF(Context context, Item item) throws SQLException,
|
||||
IOException, AuthorizeException {
|
||||
return getStringFromBitstream(context, item, BSN_LICENSE_RDF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitstream getLicenseRdfBitstream(Item item) throws SQLException,
|
||||
IOException, AuthorizeException {
|
||||
IOException, AuthorizeException {
|
||||
return getBitstream(item, BSN_LICENSE_RDF);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public Bitstream getLicenseTextBitstream(Item item) throws SQLException,
|
||||
IOException, AuthorizeException {
|
||||
IOException, AuthorizeException {
|
||||
return getBitstream(item, BSN_LICENSE_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLicenseURL(Context context, Item item) throws SQLException, IOException, AuthorizeException {
|
||||
String licenseUri = getCCField("uri").ccItemValue(item);
|
||||
String licenseUri = getCCField("uri");
|
||||
if (StringUtils.isNotBlank(licenseUri)) {
|
||||
return licenseUri;
|
||||
return getLicenseURI(item);
|
||||
}
|
||||
|
||||
// JSPUI backward compatibility see https://jira.duraspace.org/browse/DS-2604
|
||||
return getStringFromBitstream(context, item, BSN_LICENSE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored license uri of the item
|
||||
*
|
||||
* @param item - The item for which to retrieve the stored license uri
|
||||
* @return the stored license uri of the item
|
||||
*/
|
||||
@Override
|
||||
public String getLicenseURI(Item item) {
|
||||
String licenseUriField = getCCField("uri");
|
||||
if (StringUtils.isNotBlank(licenseUriField)) {
|
||||
String metadata = itemService.getMetadata(item, licenseUriField);
|
||||
if (StringUtils.isNotBlank(metadata)) {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored license name of the item
|
||||
*
|
||||
* @param item - The item for which to retrieve the stored license name
|
||||
* @return the stored license name of the item
|
||||
*/
|
||||
@Override
|
||||
public String getLicenseName( Item item) {
|
||||
String licenseNameField = getCCField("name");
|
||||
if (StringUtils.isNotBlank(licenseNameField)) {
|
||||
String metadata = itemService.getMetadata(item, licenseNameField);
|
||||
if (StringUtils.isNotBlank(metadata)) {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fetchLicenseRDF(Document license) {
|
||||
StringWriter result = new StringWriter();
|
||||
|
||||
try {
|
||||
templates.newTransformer().transform(
|
||||
new JDOMSource(license),
|
||||
new StreamResult(result)
|
||||
new JDOMSource(license),
|
||||
new StreamResult(result)
|
||||
);
|
||||
} catch (TransformerException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
@@ -267,7 +295,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
*/
|
||||
protected void setBitstreamFromBytes(Context context, Item item, Bundle bundle,
|
||||
String bitstream_name, BitstreamFormat format, byte[] bytes)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
Bitstream bs = bitstreamService.create(context, bundle, bais);
|
||||
|
||||
@@ -297,7 +325,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
*/
|
||||
protected String getStringFromBitstream(Context context, Item item,
|
||||
String bitstream_name) throws SQLException, IOException,
|
||||
AuthorizeException {
|
||||
AuthorizeException {
|
||||
byte[] bytes = getBytesFromBitstream(context, item, bitstream_name);
|
||||
|
||||
if (bytes == null) {
|
||||
@@ -320,7 +348,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
* to perform a particular action.
|
||||
*/
|
||||
protected Bitstream getBitstream(Item item, String bitstream_name)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
Bundle cc_bundle = null;
|
||||
|
||||
// look for the CC bundle
|
||||
@@ -342,7 +370,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
}
|
||||
|
||||
protected byte[] getBytesFromBitstream(Context context, Item item, String bitstream_name)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
Bitstream bs = getBitstream(item, bitstream_name);
|
||||
|
||||
// no such bitstream
|
||||
@@ -361,26 +389,322 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
|
||||
* Returns a metadata field handle for given field Id
|
||||
*/
|
||||
@Override
|
||||
public LicenseMetadataValue getCCField(String fieldId) {
|
||||
return new LicenseMetadataValue(configurationService.getProperty("cc.license." + fieldId));
|
||||
public String getCCField(String fieldId) {
|
||||
return configurationService.getProperty("cc.license." + fieldId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove license information, delete also the bitstream
|
||||
*
|
||||
* @param context - DSpace Context
|
||||
* @param item - the item
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
@Override
|
||||
public void removeLicense(Context context, LicenseMetadataValue uriField,
|
||||
LicenseMetadataValue nameField, Item item)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
public void removeLicense(Context context, Item item)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
|
||||
String uriField = getCCField("uri");
|
||||
String nameField = getCCField("name");
|
||||
|
||||
String licenseUri = itemService.getMetadata(item, uriField);
|
||||
|
||||
// only remove any previous licenses
|
||||
String licenseUri = uriField.ccItemValue(item);
|
||||
if (licenseUri != null) {
|
||||
uriField.removeItemValue(context, item, licenseUri);
|
||||
removeLicenseField(context, item, uriField);
|
||||
if (configurationService.getBooleanProperty("cc.submit.setname")) {
|
||||
String licenseName = nameField.keyedItemValue(item, licenseUri);
|
||||
nameField.removeItemValue(context, item, licenseName);
|
||||
removeLicenseField(context, item, nameField);
|
||||
}
|
||||
if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
|
||||
removeLicense(context, item);
|
||||
removeLicenseFile(context, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLicenseField(Context context, Item item, String field) throws SQLException {
|
||||
String[] params = splitField(field);
|
||||
itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
|
||||
|
||||
}
|
||||
|
||||
private void addLicenseField(Context context, Item item, String field, String value) throws SQLException {
|
||||
String[] params = splitField(field);
|
||||
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all CC Licenses using the default language found in the configuration
|
||||
*
|
||||
* @return A list of available CC Licenses
|
||||
*/
|
||||
@Override
|
||||
public List<CCLicense> findAllCCLicenses() {
|
||||
return findAllCCLicenses(defaultLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all CC Licenses for the provided language
|
||||
*
|
||||
* @param language - the language for which to find the CC Licenses
|
||||
* @return A list of available CC Licenses for the provided language
|
||||
*/
|
||||
@Override
|
||||
public List<CCLicense> findAllCCLicenses(String language) {
|
||||
|
||||
if (!ccLicenses.containsKey(language)) {
|
||||
initLicenses(language);
|
||||
}
|
||||
return new LinkedList<>(ccLicenses.get(language).values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the CC License corresponding to the provided ID using the default language found in the configuration
|
||||
*
|
||||
* @param id - the ID of the license to be found
|
||||
* @return the corresponding license if found or null when not found
|
||||
*/
|
||||
@Override
|
||||
public CCLicense findOne(String id) {
|
||||
return findOne(id, defaultLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the CC License corresponding to the provided ID and provided language
|
||||
*
|
||||
* @param id - the ID of the license to be found
|
||||
* @param language - the language for which to find the CC License
|
||||
* @return the corresponding license if found or null when not found
|
||||
*/
|
||||
@Override
|
||||
public CCLicense findOne(String id, String language) {
|
||||
if (!ccLicenses.containsKey(language)) {
|
||||
initLicenses(language);
|
||||
}
|
||||
Map<String, CCLicense> licenseMap = ccLicenses.get(language);
|
||||
if (licenseMap.containsKey(id)) {
|
||||
return licenseMap.get(id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the licenses for a specific language and cache them in this service
|
||||
*
|
||||
* @param language - the language for which to find the CC Licenses
|
||||
*/
|
||||
private void initLicenses(final String language) {
|
||||
Map<String, CCLicense> licenseMap = ccLicenseConnectorService.retrieveLicenses(language);
|
||||
ccLicenses.put(language, licenseMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
|
||||
* language found in the configuration
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the corresponding license URI
|
||||
*/
|
||||
@Override
|
||||
public String retrieveLicenseUri(String licenseId, Map<String, String> answerMap) {
|
||||
return retrieveLicenseUri(licenseId, defaultLanguage, answerMap);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI for the provided license ID and language based on the provided answers
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to find the CC License URI
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the corresponding license URI
|
||||
*/
|
||||
@Override
|
||||
public String retrieveLicenseUri(String licenseId, String language, Map<String, String> answerMap) {
|
||||
return ccLicenseConnectorService.retrieveRightsByQuestion(licenseId, language, answerMap);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
|
||||
* corresponding question in the license, using the default language found in the config to check the license
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param fullAnswerMap - the answers to the different field questions
|
||||
* @return whether the information is valid
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyLicenseInformation(String licenseId, Map<String, String> fullAnswerMap) {
|
||||
return verifyLicenseInformation(licenseId, defaultLanguage, fullAnswerMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
|
||||
* corresponding question in the license, using the provided language to check the license
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param fullAnswerMap - the answers to the different field questions
|
||||
* @return whether the information is valid
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyLicenseInformation(String licenseId, String language, Map<String, String> fullAnswerMap) {
|
||||
CCLicense ccLicense = findOne(licenseId, language);
|
||||
|
||||
List<CCLicenseField> ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
|
||||
|
||||
for (String field : fullAnswerMap.keySet()) {
|
||||
CCLicenseField ccLicenseField = findCCLicenseField(field, ccLicenseFieldList);
|
||||
if (ccLicenseField == null) {
|
||||
return false;
|
||||
}
|
||||
if (!containsAnswerEnum(fullAnswerMap.get(field), ccLicenseField)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full answer map containing empty values when an answer for a field was not provided in the
|
||||
* answerMap, using the default language found in the configuration
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the answerMap supplemented with all other license fields with a blank answer
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> retrieveFullAnswerMap(String licenseId, Map<String, String> answerMap) {
|
||||
return retrieveFullAnswerMap(licenseId, defaultLanguage, answerMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
|
||||
* provided in the answerMap.
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the answerMap supplemented with all other license fields with a blank answer for the provided language
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> retrieveFullAnswerMap(String licenseId, String language, Map<String, String> answerMap) {
|
||||
CCLicense ccLicense = findOne(licenseId, language);
|
||||
if (ccLicense == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> fullParamMap = new HashMap<>(answerMap);
|
||||
List<CCLicenseField> ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
|
||||
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
|
||||
if (!fullParamMap.containsKey(ccLicenseField.getId())) {
|
||||
fullParamMap.put(ccLicenseField.getId(), "");
|
||||
}
|
||||
}
|
||||
|
||||
updateJurisdiction(fullParamMap);
|
||||
|
||||
return fullParamMap;
|
||||
}
|
||||
|
||||
private void updateJurisdiction(final Map<String, String> fullParamMap) {
|
||||
if (fullParamMap.containsKey(JURISDICTION_KEY)) {
|
||||
fullParamMap.put(JURISDICTION_KEY, jurisdiction);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsAnswerEnum(final String enumAnswer, final CCLicenseField ccLicenseField) {
|
||||
List<CCLicenseFieldEnum> fieldEnums = ccLicenseField.getFieldEnum();
|
||||
for (CCLicenseFieldEnum fieldEnum : fieldEnums) {
|
||||
if (StringUtils.equals(fieldEnum.getId(), enumAnswer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private CCLicenseField findCCLicenseField(final String field, final List<CCLicenseField> ccLicenseFieldList) {
|
||||
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
|
||||
if (StringUtils.equals(ccLicenseField.getId(), field)) {
|
||||
return ccLicenseField;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the license of the item with a new one based on the provided license URI
|
||||
*
|
||||
* @param context - The relevant DSpace context
|
||||
* @param licenseUri - The license URI to be used in the update
|
||||
* @param item - The item for which to update the license
|
||||
* @return true when the update was successful, false when not
|
||||
* @throws AuthorizeException
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public boolean updateLicense(final Context context, final String licenseUri, final Item item)
|
||||
throws AuthorizeException, SQLException {
|
||||
try {
|
||||
Document doc = ccLicenseConnectorService.retrieveLicenseRDFDoc(licenseUri);
|
||||
if (doc == null) {
|
||||
return false;
|
||||
}
|
||||
String licenseName = ccLicenseConnectorService.retrieveLicenseName(doc);
|
||||
if (StringUtils.isBlank(licenseName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeLicense(context, item);
|
||||
addLicense(context, item, licenseUri, licenseName, doc);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Error while updating the license of item: " + item.getID(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new license to the item
|
||||
*
|
||||
* @param context - The relevant Dspace context
|
||||
* @param item - The item to which the license will be added
|
||||
* @param licenseUri - The license URI to add
|
||||
* @param licenseName - The license name to add
|
||||
* @param doc - The license to document to add
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@Override
|
||||
public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
String uriField = getCCField("uri");
|
||||
String nameField = getCCField("name");
|
||||
|
||||
addLicenseField(context, item, uriField, licenseUri);
|
||||
if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
|
||||
setLicenseRDF(context, item, fetchLicenseRDF(doc));
|
||||
}
|
||||
if (configurationService.getBooleanProperty("cc.submit.setname")) {
|
||||
addLicenseField(context, item, nameField, licenseName);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] splitField(String fieldName) {
|
||||
String[] params = new String[4];
|
||||
String[] fParams = fieldName.split("\\.");
|
||||
for (int i = 0; i < fParams.length; i++) {
|
||||
params[i] = fParams[i];
|
||||
}
|
||||
params[3] = Item.ANY;
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,129 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* Helper class for using CC-related Metadata fields
|
||||
*
|
||||
* @author kevinvandevelde at atmire.com
|
||||
*/
|
||||
public class LicenseMetadataValue {
|
||||
|
||||
protected final ItemService itemService;
|
||||
// Shibboleth for Creative Commons license data - i.e. characters that reliably indicate CC in a URI
|
||||
protected static final String ccShib = "creativecommons";
|
||||
|
||||
private String[] params = new String[4];
|
||||
|
||||
public LicenseMetadataValue(String fieldName) {
|
||||
if (fieldName != null && fieldName.length() > 0) {
|
||||
String[] fParams = fieldName.split("\\.");
|
||||
for (int i = 0; i < fParams.length; i++) {
|
||||
params[i] = fParams[i];
|
||||
}
|
||||
params[3] = Item.ANY;
|
||||
}
|
||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first value that matches Creative Commons 'shibboleth',
|
||||
* or null if no matching values.
|
||||
* NB: this method will succeed only for metadata fields holding CC URIs
|
||||
*
|
||||
* @param item - the item to read
|
||||
* @return value - the first CC-matched value, or null if no such value
|
||||
*/
|
||||
public String ccItemValue(Item item) {
|
||||
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
|
||||
for (MetadataValue dcvalue : dcvalues) {
|
||||
if ((dcvalue.getValue()).indexOf(ccShib) != -1) {
|
||||
// return first value that matches the shib
|
||||
return dcvalue.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that matches the value mapped to the passed key if any.
|
||||
* NB: this only delivers a license name (if present in field) given a license URI
|
||||
*
|
||||
* @param item - the item to read
|
||||
* @param key - the key for desired value
|
||||
* @return value - the value associated with key or null if no such value
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public String keyedItemValue(Item item, String key)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
CCLookup ccLookup = new CCLookup();
|
||||
ccLookup.issue(key);
|
||||
String matchValue = ccLookup.getLicenseName();
|
||||
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
|
||||
for (MetadataValue dcvalue : dcvalues) {
|
||||
if (dcvalue.getValue().equals(matchValue)) {
|
||||
return dcvalue.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the passed value from the set of values for the field in passed item.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param item - the item to update
|
||||
* @param value - the value to remove
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public void removeItemValue(Context context, Item item, String value)
|
||||
throws AuthorizeException, IOException, SQLException {
|
||||
if (value != null) {
|
||||
List<MetadataValue> dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
|
||||
ArrayList<String> arrayList = new ArrayList<String>();
|
||||
for (MetadataValue dcvalue : dcvalues) {
|
||||
if (!dcvalue.getValue().equals(value)) {
|
||||
arrayList.add(dcvalue.getValue());
|
||||
}
|
||||
}
|
||||
itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
|
||||
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], arrayList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds passed value to the set of values for the field in passed item.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param item - the item to update
|
||||
* @param value - the value to add in this field
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public void addItemValue(Context context, Item item, String value) throws SQLException {
|
||||
itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
|
||||
}
|
||||
|
||||
}
|
@@ -10,12 +10,14 @@ package org.dspace.license.service;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.license.LicenseMetadataValue;
|
||||
import org.dspace.license.CCLicense;
|
||||
import org.jdom.Document;
|
||||
|
||||
/**
|
||||
@@ -29,13 +31,6 @@ public interface CreativeCommonsService {
|
||||
|
||||
public static final String CC_BUNDLE_NAME = "CC-LICENSE";
|
||||
|
||||
/**
|
||||
* Simple accessor for enabling of CC
|
||||
*
|
||||
* @return is CC enabled?
|
||||
*/
|
||||
public boolean isEnabled();
|
||||
|
||||
/**
|
||||
* setLicenseRDF
|
||||
*
|
||||
@@ -50,7 +45,7 @@ public interface CreativeCommonsService {
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public void setLicenseRDF(Context context, Item item, String licenseRdf)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -72,19 +67,40 @@ public interface CreativeCommonsService {
|
||||
*/
|
||||
public void setLicense(Context context, Item item,
|
||||
InputStream licenseStm, String mimeType)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
public void removeLicense(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
/**
|
||||
* Removes the license file from the item
|
||||
*
|
||||
* @param context - The relevant DSpace Context
|
||||
* @param item - The item from which the license file needs to be removed
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
public void removeLicenseFile(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
public boolean hasLicense(Context context, Item item)
|
||||
throws SQLException, IOException;
|
||||
|
||||
public String getLicenseURL(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
public String getLicenseRDF(Context context, Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Returns the stored license uri of the item
|
||||
*
|
||||
* @param item - The item for which to retrieve the stored license uri
|
||||
* @return the stored license uri of the item
|
||||
*/
|
||||
public String getLicenseURI(Item item);
|
||||
|
||||
/**
|
||||
* Returns the stored license name of the item
|
||||
*
|
||||
* @param item - The item for which to retrieve the stored license name
|
||||
* @return the stored license name of the item
|
||||
*/
|
||||
public String getLicenseName(Item item);
|
||||
|
||||
/**
|
||||
* Get Creative Commons license RDF, returning Bitstream object.
|
||||
@@ -97,7 +113,7 @@ public interface CreativeCommonsService {
|
||||
* to perform a particular action.
|
||||
*/
|
||||
public Bitstream getLicenseRdfBitstream(Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Get Creative Commons license Text, returning Bitstream object.
|
||||
@@ -112,7 +128,7 @@ public interface CreativeCommonsService {
|
||||
* is no longer stored (see https://jira.duraspace.org/browse/DS-2604)
|
||||
*/
|
||||
public Bitstream getLicenseTextBitstream(Item item)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Get a few license-specific properties. We expect these to be cached at
|
||||
@@ -121,7 +137,7 @@ public interface CreativeCommonsService {
|
||||
* @param fieldId name of the property.
|
||||
* @return its value.
|
||||
*/
|
||||
public LicenseMetadataValue getCCField(String fieldId);
|
||||
public String getCCField(String fieldId);
|
||||
|
||||
/**
|
||||
* Apply same transformation on the document to retrieve only the most
|
||||
@@ -138,15 +154,134 @@ public interface CreativeCommonsService {
|
||||
* Remove license information, delete also the bitstream
|
||||
*
|
||||
* @param context - DSpace Context
|
||||
* @param uriField - the metadata field for license uri
|
||||
* @param nameField - the metadata field for license name
|
||||
* @param item - the item
|
||||
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
|
||||
* to perform a particular action.
|
||||
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public void removeLicense(Context context, LicenseMetadataValue uriField,
|
||||
LicenseMetadataValue nameField, Item item)
|
||||
throws AuthorizeException, IOException, SQLException;
|
||||
public void removeLicense(Context context, Item item)
|
||||
throws AuthorizeException, IOException, SQLException;
|
||||
|
||||
/**
|
||||
* Find all CC Licenses using the default language found in the configuration
|
||||
*
|
||||
* @return A list of available CC Licenses
|
||||
*/
|
||||
public List<CCLicense> findAllCCLicenses();
|
||||
|
||||
/**
|
||||
* Find all CC Licenses for the provided language
|
||||
*
|
||||
* @param language - the language for which to find the CC Licenses
|
||||
* @return A list of available CC Licenses for the provided language
|
||||
*/
|
||||
public List<CCLicense> findAllCCLicenses(String language);
|
||||
|
||||
/**
|
||||
* Find the CC License corresponding to the provided ID using the default language found in the configuration
|
||||
*
|
||||
* @param id - the ID of the license to be found
|
||||
* @return the corresponding license if found or null when not found
|
||||
*/
|
||||
public CCLicense findOne(String id);
|
||||
|
||||
/**
|
||||
* Find the CC License corresponding to the provided ID and provided language
|
||||
*
|
||||
* @param id - the ID of the license to be found
|
||||
* @param language - the language for which to find the CC License
|
||||
* @return the corresponding license if found or null when not found
|
||||
*/
|
||||
public CCLicense findOne(String id, String language);
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
|
||||
* language found in the configuration
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the corresponding license URI
|
||||
*/
|
||||
public String retrieveLicenseUri(String licenseId, Map<String, String> answerMap);
|
||||
|
||||
/**
|
||||
* Retrieve the CC License URI for the provided license ID and language based on the provided answers
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to find the CC License URI
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the corresponding license URI
|
||||
*/
|
||||
public String retrieveLicenseUri(String licenseId, String language, Map<String, String> answerMap);
|
||||
|
||||
/**
|
||||
* Retrieve the full answer map containing empty values when an answer for a field was not provided in the
|
||||
* answerMap, using the default language found in the configuration
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the answerMap supplemented with all other license fields with a blank answer
|
||||
*/
|
||||
public Map<String, String> retrieveFullAnswerMap(String licenseId, Map<String, String> answerMap);
|
||||
|
||||
/**
|
||||
* Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
|
||||
* provided in the answerMap.
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the answerMap supplemented with all other license fields with a blank answer for the provided language
|
||||
*/
|
||||
public Map<String, String> retrieveFullAnswerMap(String licenseId, String language, Map<String, String> answerMap);
|
||||
|
||||
/**
|
||||
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
|
||||
* corresponding question in the license, using the default language found in the config to check the license
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param fullAnswerMap - the answers to the different field questions
|
||||
* @return whether the information is valid
|
||||
*/
|
||||
public boolean verifyLicenseInformation(String licenseId, Map<String, String> fullAnswerMap);
|
||||
|
||||
/**
|
||||
* Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
|
||||
* corresponding question in the license, using the provided language to check the license
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param fullAnswerMap - the answers to the different field questions
|
||||
* @return whether the information is valid
|
||||
*/
|
||||
public boolean verifyLicenseInformation(String licenseId, String language, Map<String, String> fullAnswerMap);
|
||||
|
||||
/**
|
||||
* Update the license of the item with a new one based on the provided license URI
|
||||
*
|
||||
* @param context - The relevant DSpace context
|
||||
* @param licenseUri - The license URI to be used in the update
|
||||
* @param item - The item for which to update the license
|
||||
* @return true when the update was successful, false when not
|
||||
* @throws AuthorizeException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public boolean updateLicense(final Context context, String licenseUri, final Item item)
|
||||
throws AuthorizeException, SQLException;
|
||||
|
||||
/**
|
||||
* Add a new license to the item
|
||||
*
|
||||
* @param context - The relevant Dspace context
|
||||
* @param item - The item to which the license will be added
|
||||
* @param licenseUri - The license URI to add
|
||||
* @param licenseName - The license name to add
|
||||
* @param doc - The license to document to add
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
|
||||
throws SQLException, IOException, AuthorizeException;
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import java.util.Iterator;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.validator.routines.UrlValidator;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.rdf.RDFUtil;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
@@ -197,6 +198,7 @@ public class Negotiator {
|
||||
if (extraPathInfo == null) {
|
||||
extraPathInfo = "";
|
||||
}
|
||||
UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS);
|
||||
|
||||
StringBuilder urlBuilder = new StringBuilder();
|
||||
String lang = null;
|
||||
@@ -256,12 +258,15 @@ public class Negotiator {
|
||||
urlBuilder.append(handle).append("/").append(extraPathInfo);
|
||||
}
|
||||
String url = urlBuilder.toString();
|
||||
|
||||
log.debug("Will forward to '" + url + "'.");
|
||||
response.setStatus(HttpServletResponse.SC_SEE_OTHER);
|
||||
response.setHeader("Location", url);
|
||||
response.flushBuffer();
|
||||
return true;
|
||||
if (urlValidator.isValid(url)) {
|
||||
log.debug("Will forward to '" + url + "'.");
|
||||
response.setStatus(HttpServletResponse.SC_SEE_OTHER);
|
||||
response.setHeader("Location", url);
|
||||
response.flushBuffer();
|
||||
return true;
|
||||
} else {
|
||||
throw new IOException("Invalid URL '" + url + "', cannot redirect.");
|
||||
}
|
||||
}
|
||||
|
||||
// currently we cannot serve statistics as rdf
|
||||
@@ -287,10 +292,14 @@ public class Negotiator {
|
||||
urlBuilder.append("/handle/").append(handle);
|
||||
urlBuilder.append("/").append(lang);
|
||||
String url = urlBuilder.toString();
|
||||
log.debug("Will forward to '" + url + "'.");
|
||||
response.setStatus(HttpServletResponse.SC_SEE_OTHER);
|
||||
response.setHeader("Location", url);
|
||||
response.flushBuffer();
|
||||
return true;
|
||||
if (urlValidator.isValid(url)) {
|
||||
log.debug("Will forward to '" + url + "'.");
|
||||
response.setStatus(HttpServletResponse.SC_SEE_OTHER);
|
||||
response.setHeader("Location", url);
|
||||
response.flushBuffer();
|
||||
return true;
|
||||
} else {
|
||||
throw new IOException("Invalid URL '" + url + "', cannot redirect.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.submit.lookup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import gr.ekt.bte.core.Record;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Andrea Bollini
|
||||
* @author Kostas Stamatis
|
||||
* @author Luigi Andrea Pascarelli
|
||||
* @author Panagiotis Koutsourakis
|
||||
*/
|
||||
public class ArXivService {
|
||||
private int timeout = 1000;
|
||||
|
||||
/**
|
||||
* How long to wait for a connection to be established.
|
||||
*
|
||||
* @param timeout milliseconds
|
||||
*/
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public List<Record> getByDOIs(Set<String> dois) throws HttpException,
|
||||
IOException {
|
||||
if (dois != null && dois.size() > 0) {
|
||||
String doisQuery = StringUtils.join(dois.iterator(), " OR ");
|
||||
return search(doisQuery, null, 100);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Record> searchByTerm(String title, String author, int year)
|
||||
throws HttpException, IOException {
|
||||
StringBuffer query = new StringBuffer();
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
query.append("ti:\"").append(title).append("\"");
|
||||
}
|
||||
if (StringUtils.isNotBlank(author)) {
|
||||
// [FAU]
|
||||
if (query.length() > 0) {
|
||||
query.append(" AND ");
|
||||
}
|
||||
query.append("au:\"").append(author).append("\"");
|
||||
}
|
||||
return search(query.toString(), "", 10);
|
||||
}
|
||||
|
||||
protected List<Record> search(String query, String arxivid, int max_result)
|
||||
throws IOException, HttpException {
|
||||
List<Record> results = new ArrayList<Record>();
|
||||
HttpGet method = null;
|
||||
try {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpParams params = client.getParams();
|
||||
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
|
||||
|
||||
try {
|
||||
URIBuilder uriBuilder = new URIBuilder("http://export.arxiv.org/api/query");
|
||||
uriBuilder.addParameter("id_list", arxivid);
|
||||
uriBuilder.addParameter("search_query", query);
|
||||
uriBuilder.addParameter("max_results", String.valueOf(max_result));
|
||||
method = new HttpGet(uriBuilder.build());
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new HttpException(ex.getMessage());
|
||||
}
|
||||
|
||||
// Execute the method.
|
||||
HttpResponse response = client.execute(method);
|
||||
StatusLine responseStatus = response.getStatusLine();
|
||||
int statusCode = responseStatus.getStatusCode();
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
if (statusCode == HttpStatus.SC_BAD_REQUEST) {
|
||||
throw new RuntimeException("arXiv query is not valid");
|
||||
} else {
|
||||
throw new RuntimeException("Http call failed: "
|
||||
+ responseStatus);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document inDoc = db.parse(response.getEntity().getContent());
|
||||
|
||||
Element xmlRoot = inDoc.getDocumentElement();
|
||||
List<Element> dataRoots = XMLUtils.getElementList(xmlRoot,
|
||||
"entry");
|
||||
|
||||
for (Element dataRoot : dataRoots) {
|
||||
Record crossitem = ArxivUtils
|
||||
.convertArxixDomToRecord(dataRoot);
|
||||
if (crossitem != null) {
|
||||
results.add(crossitem);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"ArXiv identifier is not valid or not exist");
|
||||
}
|
||||
} finally {
|
||||
if (method != null) {
|
||||
method.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public Record getByArXivIDs(String raw) throws HttpException, IOException {
|
||||
if (StringUtils.isNotBlank(raw)) {
|
||||
raw = raw.trim();
|
||||
if (raw.startsWith("http://arxiv.org/abs/")) {
|
||||
raw = raw.substring("http://arxiv.org/abs/".length());
|
||||
} else if (raw.toLowerCase().startsWith("arxiv:")) {
|
||||
raw = raw.substring("arxiv:".length());
|
||||
}
|
||||
List<Record> result = search("", raw, 1);
|
||||
if (result != null && result.size() > 0) {
|
||||
return result.get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -102,6 +102,9 @@ public class CiNiiService {
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document inDoc = db.parse(response.getEntity().getContent());
|
||||
@@ -178,6 +181,9 @@ public class CiNiiService {
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document inDoc = db.parse(response.getEntity().getContent());
|
||||
|
@@ -99,6 +99,9 @@ public class CrossRefService {
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder db = factory
|
||||
.newDocumentBuilder();
|
||||
|
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.submit.lookup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import gr.ekt.bte.core.Record;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* @author Andrea Bollini
|
||||
* @author Kostas Stamatis
|
||||
* @author Luigi Andrea Pascarelli
|
||||
* @author Panagiotis Koutsourakis
|
||||
*/
|
||||
public class PubmedService {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(PubmedService.class);
|
||||
|
||||
protected int timeout = 1000;
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public Record getByPubmedID(String pubmedid) throws HttpException,
|
||||
IOException, ParserConfigurationException, SAXException {
|
||||
List<String> ids = new ArrayList<String>();
|
||||
ids.add(pubmedid.trim());
|
||||
List<Record> items = getByPubmedIDs(ids);
|
||||
if (items != null && items.size() > 0) {
|
||||
return items.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Record> search(String title, String author, int year)
|
||||
throws HttpException, IOException {
|
||||
StringBuffer query = new StringBuffer();
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
query.append("((").append(title).append("[TI]) OR (");
|
||||
// [TI] does not always work, book chapter title
|
||||
query.append("(").append(title).append("[book]))");
|
||||
}
|
||||
if (StringUtils.isNotBlank(author)) {
|
||||
// [FAU]
|
||||
if (query.length() > 0) {
|
||||
query.append(" AND ");
|
||||
}
|
||||
query.append("(").append(author).append("[AU])");
|
||||
}
|
||||
if (year != -1) {
|
||||
// [DP]
|
||||
if (query.length() > 0) {
|
||||
query.append(" AND ");
|
||||
}
|
||||
query.append(year).append("[DP]");
|
||||
}
|
||||
return search(query.toString());
|
||||
}
|
||||
|
||||
public List<Record> search(String query) throws IOException, HttpException {
|
||||
List<Record> results = new ArrayList<>();
|
||||
if (!ConfigurationManager.getBooleanProperty(SubmissionLookupService.CFG_MODULE, "remoteservice.demo")) {
|
||||
HttpGet method = null;
|
||||
try {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
|
||||
|
||||
URIBuilder uriBuilder = new URIBuilder(
|
||||
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi");
|
||||
uriBuilder.addParameter("db", "pubmed");
|
||||
uriBuilder.addParameter("datetype", "edat");
|
||||
uriBuilder.addParameter("retmax", "10");
|
||||
uriBuilder.addParameter("term", query);
|
||||
method = new HttpGet(uriBuilder.build());
|
||||
|
||||
// Execute the method.
|
||||
HttpResponse response = client.execute(method);
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
int statusCode = statusLine.getStatusCode();
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
throw new RuntimeException("WS call failed: "
|
||||
+ statusLine);
|
||||
}
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder builder;
|
||||
try {
|
||||
builder = factory.newDocumentBuilder();
|
||||
|
||||
Document inDoc = builder.parse(response.getEntity().getContent());
|
||||
|
||||
Element xmlRoot = inDoc.getDocumentElement();
|
||||
Element idList = XMLUtils.getSingleElement(xmlRoot,
|
||||
"IdList");
|
||||
List<String> pubmedIDs = XMLUtils.getElementValueList(
|
||||
idList, "Id");
|
||||
results = getByPubmedIDs(pubmedIDs);
|
||||
} catch (ParserConfigurationException e1) {
|
||||
log.error(e1.getMessage(), e1);
|
||||
} catch (SAXException e1) {
|
||||
log.error(e1.getMessage(), e1);
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
log.error(e1.getMessage(), e1);
|
||||
} finally {
|
||||
if (method != null) {
|
||||
method.releaseConnection();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
File file = new File(
|
||||
ConfigurationManager.getProperty("dspace.dir")
|
||||
+ "/config/crosswalks/demo/pubmed-search.xml");
|
||||
stream = new FileInputStream(file);
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document inDoc = builder.parse(stream);
|
||||
|
||||
Element xmlRoot = inDoc.getDocumentElement();
|
||||
Element idList = XMLUtils.getSingleElement(xmlRoot, "IdList");
|
||||
List<String> pubmedIDs = XMLUtils.getElementValueList(idList,
|
||||
"Id");
|
||||
results = getByPubmedIDs(pubmedIDs);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Record> getByPubmedIDs(List<String> pubmedIDs)
|
||||
throws HttpException, IOException, ParserConfigurationException,
|
||||
SAXException {
|
||||
List<Record> results = new ArrayList<Record>();
|
||||
HttpGet method = null;
|
||||
try {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5 * timeout);
|
||||
|
||||
try {
|
||||
URIBuilder uriBuilder = new URIBuilder(
|
||||
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi");
|
||||
uriBuilder.addParameter("db", "pubmed");
|
||||
uriBuilder.addParameter("retmode", "xml");
|
||||
uriBuilder.addParameter("rettype", "full");
|
||||
uriBuilder.addParameter("id", StringUtils.join(
|
||||
pubmedIDs.iterator(), ","));
|
||||
method = new HttpGet(uriBuilder.build());
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new RuntimeException("Request not sent", ex);
|
||||
}
|
||||
|
||||
// Execute the method.
|
||||
HttpResponse response = client.execute(method);
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
int statusCode = statusLine.getStatusCode();
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
throw new RuntimeException("WS call failed: " + statusLine);
|
||||
}
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
// disallow DTD parsing to ensure no XXE attacks can occur.
|
||||
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document inDoc = builder
|
||||
.parse(response.getEntity().getContent());
|
||||
|
||||
Element xmlRoot = inDoc.getDocumentElement();
|
||||
List<Element> pubArticles = XMLUtils.getElementList(xmlRoot,
|
||||
"PubmedArticle");
|
||||
|
||||
for (Element xmlArticle : pubArticles) {
|
||||
Record pubmedItem = null;
|
||||
try {
|
||||
pubmedItem = PubmedUtils
|
||||
.convertPubmedDomToRecord(xmlArticle);
|
||||
results.add(pubmedItem);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"PubmedID is not valid or not exist: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
} finally {
|
||||
if (method != null) {
|
||||
method.releaseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Record> search(String doi, String pmid) throws HttpException,
|
||||
IOException {
|
||||
StringBuffer query = new StringBuffer();
|
||||
if (StringUtils.isNotBlank(doi)) {
|
||||
query.append(doi);
|
||||
query.append("[AID]");
|
||||
}
|
||||
if (StringUtils.isNotBlank(pmid)) {
|
||||
// [FAU]
|
||||
if (query.length() > 0) {
|
||||
query.append(" OR ");
|
||||
}
|
||||
query.append(pmid).append("[PMID]");
|
||||
}
|
||||
return search(query.toString());
|
||||
}
|
||||
}
|
@@ -135,12 +135,12 @@ public class Version implements ReloadableEntity<Integer> {
|
||||
return true;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Version that = (Version) o;
|
||||
if (this.getID() != that.getID()) {
|
||||
if (!this.getID().equals(that.getID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -93,12 +93,12 @@ public class VersionHistory implements ReloadableEntity<Integer> {
|
||||
return true;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o);
|
||||
if (getClass() != objClass) {
|
||||
if (!getClass().equals(objClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final VersionHistory that = (VersionHistory) o;
|
||||
if (this.getID() != that.getID()) {
|
||||
if (!this.getID().equals(that.getID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
<!-- for handle "default". -->
|
||||
<submission-map>
|
||||
<name-map collection-handle="default" submission-name="traditional"/>
|
||||
<name-map collection-handle="123456789/language-test-1" submission-name="languagetestprocess"/>
|
||||
</submission-map>
|
||||
|
||||
|
||||
@@ -82,9 +83,9 @@
|
||||
<!--Step will be to select a Creative Commons License -->
|
||||
<!-- Uncomment this step to allow the user to select a Creative Commons
|
||||
license -->
|
||||
<!-- <step id="creative-commons"> <heading>submit.progressbar.CClicense</heading>
|
||||
<processing-class>org.dspace.submit.step.CCLicenseStep</processing-class>
|
||||
<type>cclicense</type> </step> -->
|
||||
<step id="cclicense"> <heading>submit.progressbar.CClicense</heading>
|
||||
<processing-class>org.dspace.app.rest.submit.step.CCLicenseStep</processing-class>
|
||||
<type>cclicense</type> </step>
|
||||
|
||||
<!--Step will be to Check for potential duplicate -->
|
||||
<!-- <step id="detect-duplicate"> <heading>submit.progressbar.detect.duplicate</heading>
|
||||
@@ -108,6 +109,12 @@
|
||||
<processing-class>org.dspace.submit.step.SampleStep</processing-class>
|
||||
<type>sample</type>
|
||||
</step>
|
||||
|
||||
<step id="languagetest" mandatory="true">
|
||||
<heading>submit.progressbar.describe.stepone</heading>
|
||||
<processing-class>org.dspace.app.rest.submit.step.DescribeStep</processing-class>
|
||||
<type>submission-form</type>
|
||||
</step>
|
||||
</step-definitions>
|
||||
|
||||
<!-- The submission-definitions map lays out the detailed definition of -->
|
||||
@@ -145,10 +152,14 @@
|
||||
|
||||
<!--Step will be to Sign off on the License -->
|
||||
<step id="license"/>
|
||||
<!-- <step id="creative-commons"/> -->
|
||||
<step id="cclicense"/>
|
||||
<!-- <step id="verify"/> -->
|
||||
</submission-process>
|
||||
|
||||
<submission-process name="languagetestprocess">
|
||||
<step id="collection"/>
|
||||
<step id="languagetest"/>
|
||||
</submission-process>
|
||||
</submission-definitions>
|
||||
|
||||
</item-submission>
|
||||
|
@@ -120,3 +120,7 @@ rest.properties.exposed = configuration.not.existing
|
||||
configuration.not.exposed = secret_value
|
||||
configuration.exposed.single.value = public_value
|
||||
configuration.exposed.array.value = public_value_1, public_value_2
|
||||
|
||||
# Test config for the authentication ip functionality
|
||||
authentication-ip.Staff = 5.5.5.5
|
||||
authentication-ip.Student = 6.6.6.6
|
||||
|
@@ -0,0 +1,169 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE input-forms SYSTEM "submission-forms.dtd">
|
||||
|
||||
|
||||
<input-forms>
|
||||
|
||||
<!-- The form-definitions map lays out the detailed definition of all the -->
|
||||
<!-- submission forms. Each separate form set has a unique name as an -->
|
||||
<!-- attribute. This name matches one of the names in the form-map. One -->
|
||||
<!-- named form set has the name "traditional"; as this name suggests, -->
|
||||
<!-- it is the old style and is also the default, which gets used when -->
|
||||
<!-- the specified collection has no correspondingly-named form set. -->
|
||||
<!-- -->
|
||||
<!-- Each form set contains an ordered set of pages; each page defines -->
|
||||
<!-- one submission metadata entry screen. Each page has an ordered list -->
|
||||
<!-- of field definitions, Each field definition corresponds to one -->
|
||||
<!-- metadata entry (a so-called row), which has a DC element name, a -->
|
||||
<!-- displayed label, a text string prompt which is called a hint, and -->
|
||||
<!-- an input-type. Each field also may hold optional elements: DC -->
|
||||
<!-- qualifier name, a repeatable flag, and a text string whose presence -->
|
||||
<!-- serves as a 'this field is required' flag. -->
|
||||
|
||||
<form-definitions>
|
||||
<form name="bitstream-metadata">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Titolo</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Inserisci nome del file</hint>
|
||||
<required>È necessario inserire un titolo principale per questo item</required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Descrizione</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Inserisci descrizione per questo file</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="languagetest">
|
||||
<row>
|
||||
<relation-field>
|
||||
<relationship-type>isAuthorOfPublication</relationship-type>
|
||||
<search-configuration>person</search-configuration>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Autore</label>
|
||||
<hint>Aggiungi un autore</hint>
|
||||
<linked-metadata-field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<input-type>name</input-type>
|
||||
</linked-metadata-field>
|
||||
<required>È richiesto almeno un autore</required>
|
||||
</relation-field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Titolo</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Inserisci titolo principale di questo item</hint>
|
||||
<required>È necessario inserire un titolo principale per questo item</required>
|
||||
<!-- <language value-pairs-name="common_iso_languages">true</language> -->
|
||||
</field>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>language</dc-element>
|
||||
<dc-qualifier>iso</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Lingua</label>
|
||||
<input-type value-pairs-name="common_iso_languages">dropdown</input-type>
|
||||
<hint>Selezionare la lingua del contenuto principale dell'item. Se la lingua non compare nell'elenco, selezionare (Altro). Se il contenuto non ha davvero una lingua (ad esempio, se è un set di dati o un'immagine) selezionare (N/A).
|
||||
</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
</form-definitions>
|
||||
|
||||
|
||||
<!-- form-value-pairs populate dropdown and qualdrop-value lists. -->
|
||||
<!-- The form-value-pairs element holds child elements named 'value-pairs' -->
|
||||
<!-- A 'value-pairs' element has a value-pairs-name and a dc-term -->
|
||||
<!-- attribute. The dc-term attribute specifies which to which Dublin Core -->
|
||||
<!-- Term this set of value-pairs applies. -->
|
||||
<!-- Current dc-terms are: identifier-pairs, type-pairs, and -->
|
||||
<!-- language_iso-pairs. The name attribute matches a name -->
|
||||
<!-- in the form-map, above. -->
|
||||
<!-- A value-pair contains one 'pair' for each value displayed in the list -->
|
||||
<!-- Each pair contains a 'displayed-value' element and a 'stored-value' -->
|
||||
<!-- element. A UI list displays the displayed-values, but the program -->
|
||||
<!-- stores the associated stored-values in the database. -->
|
||||
|
||||
<form-value-pairs>
|
||||
|
||||
<!-- default language order: (from dspace 1.2.1)
|
||||
"en_US", "en", "es", "de", "fr", "it", "ja", "zh", "other", ""
|
||||
-->
|
||||
<value-pairs value-pairs-name="common_iso_languages" dc-term="language_iso">
|
||||
<pair>
|
||||
<displayed-value>N/A</displayed-value>
|
||||
<stored-value></stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Inglese (USA)</displayed-value>
|
||||
<stored-value>en_US</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Inglese</displayed-value>
|
||||
<stored-value>en</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Spagnolo</displayed-value>
|
||||
<stored-value>es</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Tedesco</displayed-value>
|
||||
<stored-value>de</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Francese</displayed-value>
|
||||
<stored-value>fr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Italiano</displayed-value>
|
||||
<stored-value>it</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Giapponese</displayed-value>
|
||||
<stored-value>ja</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Cinese</displayed-value>
|
||||
<stored-value>zh</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Portogallo</displayed-value>
|
||||
<stored-value>pt</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Ucraino</displayed-value>
|
||||
<stored-value>uk</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>(Altro)</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
</form-value-pairs>
|
||||
|
||||
</input-forms>
|
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE input-forms SYSTEM "submission-forms.dtd">
|
||||
|
||||
|
||||
<input-forms>
|
||||
|
||||
<!-- The form-definitions map lays out the detailed definition of all the -->
|
||||
<!-- submission forms. Each separate form set has a unique name as an -->
|
||||
<!-- attribute. This name matches one of the names in the form-map. One -->
|
||||
<!-- named form set has the name "traditional"; as this name suggests, -->
|
||||
<!-- it is the old style and is also the default, which gets used when -->
|
||||
<!-- the specified collection has no correspondingly-named form set. -->
|
||||
<!-- -->
|
||||
<!-- Each form set contains an ordered set of pages; each page defines -->
|
||||
<!-- one submission metadata entry screen. Each page has an ordered list -->
|
||||
<!-- of field definitions, Each field definition corresponds to one -->
|
||||
<!-- metadata entry (a so-called row), which has a DC element name, a -->
|
||||
<!-- displayed label, a text string prompt which is called a hint, and -->
|
||||
<!-- an input-type. Each field also may hold optional elements: DC -->
|
||||
<!-- qualifier name, a repeatable flag, and a text string whose presence -->
|
||||
<!-- serves as a 'this field is required' flag. -->
|
||||
|
||||
<form-definitions>
|
||||
<form name="bitstream-metadata">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Заголовок</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Ввести основний заголовок файла.</hint>
|
||||
<required>Заговолок файла обов'язковий !</required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Опис</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Ввести опис для цього файла</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="languagetest">
|
||||
<row>
|
||||
<relation-field>
|
||||
<relationship-type>isAuthorOfPublication</relationship-type>
|
||||
<search-configuration>person</search-configuration>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Автор</label>
|
||||
<hint>Додати автора</hint>
|
||||
<linked-metadata-field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<input-type>name</input-type>
|
||||
</linked-metadata-field>
|
||||
<required>Потрібно ввести хочаб одного автора!</required>
|
||||
</relation-field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Заголовок</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Ввести основний заголовок файла</hint>
|
||||
<required>Заговолок файла обов'язковий !</required>
|
||||
<!-- <language value-pairs-name="common_iso_languages">true</language> -->
|
||||
</field>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>language</dc-element>
|
||||
<dc-qualifier>iso</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Мова</label>
|
||||
<input-type value-pairs-name="common_iso_languages">dropdown</input-type>
|
||||
<hint>Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша). Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A) </hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
</form-definitions>
|
||||
|
||||
|
||||
<!-- form-value-pairs populate dropdown and qualdrop-value lists. -->
|
||||
<!-- The form-value-pairs element holds child elements named 'value-pairs' -->
|
||||
<!-- A 'value-pairs' element has a value-pairs-name and a dc-term -->
|
||||
<!-- attribute. The dc-term attribute specifies which to which Dublin Core -->
|
||||
<!-- Term this set of value-pairs applies. -->
|
||||
<!-- Current dc-terms are: identifier-pairs, type-pairs, and -->
|
||||
<!-- language_iso-pairs. The name attribute matches a name -->
|
||||
<!-- in the form-map, above. -->
|
||||
<!-- A value-pair contains one 'pair' for each value displayed in the list -->
|
||||
<!-- Each pair contains a 'displayed-value' element and a 'stored-value' -->
|
||||
<!-- element. A UI list displays the displayed-values, but the program -->
|
||||
<!-- stores the associated stored-values in the database. -->
|
||||
|
||||
<form-value-pairs>
|
||||
<!-- default language order: (from dspace 1.2.1)
|
||||
"en_US", "en", "es", "de", "fr", "it", "ja", "zh", "other", ""
|
||||
-->
|
||||
<value-pairs value-pairs-name="common_iso_languages" dc-term="language_iso">
|
||||
<pair>
|
||||
<displayed-value>N/A</displayed-value>
|
||||
<stored-value></stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Американська (USA)</displayed-value>
|
||||
<stored-value>en_US</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Англiйська</displayed-value>
|
||||
<stored-value>en</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Iспанська</displayed-value>
|
||||
<stored-value>es</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Нiмецька</displayed-value>
|
||||
<stored-value>de</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Французька</displayed-value>
|
||||
<stored-value>fr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Iталiйська</displayed-value>
|
||||
<stored-value>it</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Японська</displayed-value>
|
||||
<stored-value>ja</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Китайська</displayed-value>
|
||||
<stored-value>zh</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Португальська</displayed-value>
|
||||
<stored-value>pt</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Турецька</displayed-value>
|
||||
<stored-value>tr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>(Iнша)</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
</form-value-pairs>
|
||||
|
||||
</input-forms>
|
@@ -153,6 +153,14 @@ public class IPMatcherTest {
|
||||
assertFalse(ipMatcher.match("0:0:0:0:0:0:0:1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6FullMaskMatching() throws Exception {
|
||||
final IPMatcher ipMatcher = new IPMatcher("::2/128");
|
||||
|
||||
assertTrue(ipMatcher.match("0:0:0:0:0:0:0:2"));
|
||||
assertFalse(ipMatcher.match("0:0:0:0:0:0:0:1"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAsteriskMatchingSuccess() throws Exception {
|
||||
|
@@ -130,7 +130,7 @@ public class ContextTest extends AbstractUnitTest {
|
||||
public void testGetCurrentLocale() {
|
||||
//NOTE: CurrentLocale is not initialized in AbstractUnitTest. So it should be DEFAULTLOCALE
|
||||
assertThat("testGetCurrentLocale 0", context.getCurrentLocale(), notNullValue());
|
||||
assertThat("testGetCurrentLocale 1", context.getCurrentLocale(), equalTo(I18nUtil.DEFAULTLOCALE));
|
||||
assertThat("testGetCurrentLocale 1", context.getCurrentLocale(), equalTo(I18nUtil.getDefaultLocale()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.license;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
/**
|
||||
* Mock implementation for the Creative commons license connector service.
|
||||
* This class will return a structure of CC Licenses similar to the CC License API but without having to contact it
|
||||
*/
|
||||
public class MockCCLicenseConnectorServiceImpl extends CCLicenseConnectorServiceImpl {
|
||||
|
||||
/**
|
||||
* Retrieves mock CC Licenses for the provided language
|
||||
* @param language - the language
|
||||
* @return a map of mocked licenses with the id and the license
|
||||
*/
|
||||
public Map<String, CCLicense> retrieveLicenses(String language) {
|
||||
Map<String, CCLicense> ccLicenses = new HashMap<>();
|
||||
CCLicense mockLicense1 = createMockLicense(1, new int[]{3, 2, 3});
|
||||
CCLicense mockLicense2 = createMockLicense(2, new int[]{2});
|
||||
CCLicense mockLicense3 = createMockLicense(3, new int[]{});
|
||||
|
||||
ccLicenses.put(mockLicense1.getLicenseId(), mockLicense1);
|
||||
ccLicenses.put(mockLicense2.getLicenseId(), mockLicense2);
|
||||
ccLicenses.put(mockLicense3.getLicenseId(), mockLicense3);
|
||||
|
||||
return ccLicenses;
|
||||
}
|
||||
|
||||
private CCLicense createMockLicense(int count, int[] amountOfFieldsAndEnums) {
|
||||
String licenseId = "license" + count;
|
||||
String licenseName = "License " + count + " - Name";
|
||||
List<CCLicenseField> mockLicenseFields = createMockLicenseFields(count, amountOfFieldsAndEnums);
|
||||
return new CCLicense(licenseId, licenseName, mockLicenseFields);
|
||||
}
|
||||
|
||||
private List<CCLicenseField> createMockLicenseFields(int count, int[] amountOfFieldsAndEnums) {
|
||||
List<CCLicenseField> ccLicenseFields = new LinkedList<>();
|
||||
for (int index = 0; index < amountOfFieldsAndEnums.length; index++) {
|
||||
String licenseFieldId = "license" + count + "-field" + index;
|
||||
String licenseFieldLabel = "License " + count + " - Field " + index + " - Label";
|
||||
String licenseFieldDescription = "License " + count + " - Field " + index + " - Description";
|
||||
List<CCLicenseFieldEnum> mockLicenseFields = createMockLicenseFields(count,
|
||||
index,
|
||||
amountOfFieldsAndEnums[index]);
|
||||
ccLicenseFields.add(new CCLicenseField(licenseFieldId,
|
||||
licenseFieldLabel,
|
||||
licenseFieldDescription,
|
||||
mockLicenseFields));
|
||||
|
||||
}
|
||||
|
||||
return ccLicenseFields;
|
||||
}
|
||||
|
||||
private List<CCLicenseFieldEnum> createMockLicenseFields(int count, int index, int amountOfEnums) {
|
||||
List<CCLicenseFieldEnum> ccLicenseFieldEnumList = new LinkedList<>();
|
||||
for (int i = 0; i < amountOfEnums; i++) {
|
||||
String enumId = "license" + count + "-field" + index + "-enum" + i;
|
||||
String enumLabel = "License " + count + " - Field " + index + " - Enum " + i + " - Label";
|
||||
String enumDescription = "License " + count + " - Field " + index + " - Enum " + i + " - " +
|
||||
"Description";
|
||||
ccLicenseFieldEnumList.add(new CCLicenseFieldEnum(enumId, enumLabel, enumDescription));
|
||||
}
|
||||
return ccLicenseFieldEnumList;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a mock CC License URI
|
||||
*
|
||||
* @param licenseId - the ID of the license
|
||||
* @param language - the language for which to retrieve the full answerMap
|
||||
* @param answerMap - the answers to the different field questions
|
||||
* @return the CC License URI
|
||||
*/
|
||||
public String retrieveRightsByQuestion(final String licenseId,
|
||||
final String language,
|
||||
final Map<String, String> answerMap) {
|
||||
|
||||
return "mock-license-uri";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a mock license RDF document.
|
||||
* When the uri contains "invalid", null will be returned to simulate that no document was found for the provided
|
||||
* URI
|
||||
*
|
||||
* @param licenseURI - The license URI for which to retrieve the license RDF document
|
||||
* @return a mock license RDF document or null when the URI contains invalid
|
||||
* @throws IOException
|
||||
*/
|
||||
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
|
||||
if (!StringUtils.contains(licenseURI, "invalid")) {
|
||||
InputStream cclicense = null;
|
||||
try {
|
||||
cclicense = getClass().getResourceAsStream("cc-license-rdf.xml");
|
||||
|
||||
Document doc = parser.build(cclicense);
|
||||
return doc;
|
||||
} catch (JDOMException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (cclicense != null) {
|
||||
cclicense.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<groupId>org.dspace</groupId>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@@ -86,7 +86,8 @@ public class LocalURIRedirectionServlet extends HttpServlet {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
// use object's reported handle for redirect (just in case user provided handle had odd characters)
|
||||
handle = dso.getHandle();
|
||||
// close the context and send forward.
|
||||
context.abort();
|
||||
Negotiator.sendRedirect(response, handle, "", requestedMimeType, true);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-rest</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<name>DSpace (Deprecated) REST Webapp</name>
|
||||
<description>DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED.
|
||||
Please consider using the REST API in the dspace-server-webapp instead!</description>
|
||||
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@@ -274,16 +274,16 @@ public class CollectionsResource extends Resource {
|
||||
headers, request, context);
|
||||
|
||||
items = new ArrayList<Item>();
|
||||
Iterator<org.dspace.content.Item> dspaceItems = itemService.findByCollection(context, dspaceCollection);
|
||||
for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++) {
|
||||
Iterator<org.dspace.content.Item> dspaceItems = itemService.findByCollection(context, dspaceCollection,
|
||||
limit, offset);
|
||||
|
||||
while (dspaceItems.hasNext()) {
|
||||
org.dspace.content.Item dspaceItem = dspaceItems.next();
|
||||
|
||||
if (i >= offset) {
|
||||
if (itemService.isItemListedForUser(context, dspaceItem)) {
|
||||
items.add(new Item(dspaceItem, servletContext, expand, context));
|
||||
writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
|
||||
headers, request, context);
|
||||
}
|
||||
if (itemService.isItemListedForUser(context, dspaceItem)) {
|
||||
items.add(new Item(dspaceItem, servletContext, expand, context));
|
||||
writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
|
||||
headers, request, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
<!-- Inject the SolrLoggerUsageEventListener into the EventService -->
|
||||
<!--
|
||||
Temporarily commented out SolrLoggerUsageEventListener to get REST API working on master.
|
||||
Temporarily commented out SolrLoggerUsageEventListener to get REST API working.
|
||||
This should be uncommented again once DS-3815 is resolved.
|
||||
|
||||
<bean class="org.dspace.statistics.SolrLoggerUsageEventListener">
|
||||
|
@@ -15,7 +15,7 @@ var Report = function() {
|
||||
this.ROOTPATH = "/xmlui/handle/"
|
||||
//this.ROOTPATH = "/jspui/handle/"
|
||||
//this.ROOTPATH = "/handle/"
|
||||
|
||||
|
||||
//Indicate if Password Authentication is supported
|
||||
this.makeAuthLink = function(){return false;};
|
||||
|
||||
@@ -27,34 +27,34 @@ var Report = function() {
|
||||
this.getId = function(obj) {
|
||||
return obj.uuid;
|
||||
}
|
||||
|
||||
|
||||
//Override this method is sortable.js has been included
|
||||
this.hasSorttable = function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
this.getDefaultParameters = function(){
|
||||
return {};
|
||||
}
|
||||
this.getCurrentParameters = function(){
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
this.saveUrl = function() {
|
||||
this.myReportParameters.saveAsUrl(this.getCurrentParameters());
|
||||
}
|
||||
|
||||
|
||||
this.getLoginPayload = function() {
|
||||
//Placeholder to allow a customized report to prompt for email/password
|
||||
//If not enabled, the authenticaton callback will be called immediately
|
||||
var email = $("#restemail").val();
|
||||
var pass = $("#restpass").val();
|
||||
if (email == "" || pass == "") {
|
||||
return undefined;
|
||||
return undefined;
|
||||
} else if (email == null || pass == null) {
|
||||
return undefined;
|
||||
return undefined;
|
||||
} else {
|
||||
return {email: email, password: pass};
|
||||
return {email: email, password: pass};
|
||||
}
|
||||
}
|
||||
this.getLangSuffix = function(){
|
||||
@@ -82,15 +82,15 @@ var Report = function() {
|
||||
className: 'spinner', // The CSS class to assign to the spinner
|
||||
zIndex: 2e9, // The z-index (defaults to 2000000000)
|
||||
top: '400px', // Top position relative to parent
|
||||
left: '600px' // Left position relative to parent
|
||||
left: '600px' // Left position relative to parent
|
||||
});
|
||||
|
||||
|
||||
this.displayItems = function(itemsTitle, offset, limit, total, funcdec, funcinc) {
|
||||
var count = $("#itemtable tr.data").length;
|
||||
|
||||
|
||||
var last = offset + limit;
|
||||
var suff = "";
|
||||
|
||||
|
||||
if (total == null) {
|
||||
last = offset + count;
|
||||
suff = (count == limit) ? " of " + last + "+ " : " of " + last;
|
||||
@@ -102,7 +102,7 @@ var Report = function() {
|
||||
suff = " of " + total;
|
||||
}
|
||||
suff += " unfiltered; displaying " + count + " filtered" ;
|
||||
|
||||
|
||||
itemsTitle += " (" + (offset+1) + " - " + last + suff + ")";
|
||||
$("#prev,#next").attr("disabled",true);
|
||||
$("#itemdiv h3").text(itemsTitle);
|
||||
@@ -110,34 +110,34 @@ var Report = function() {
|
||||
if (offset > 0) $("#prev").attr("disabled", false);
|
||||
$("#prev").off("click").on("click", funcdec);
|
||||
//in case of filters, always allow next
|
||||
|
||||
|
||||
if (total == null) {
|
||||
$("#next").attr("disabled", false);
|
||||
$("#next").attr("disabled", false);
|
||||
} else if (offset + limit < total) {
|
||||
$("#next").attr("disabled", false);
|
||||
$("#next").attr("disabled", false);
|
||||
$("#exlimit").addClass("red");
|
||||
} else if (limit == total) {
|
||||
//total may only be accurate to one page
|
||||
$("#next").attr("disabled", false);
|
||||
$("#next").attr("disabled", false);
|
||||
$("#exlimit").addClass("red");
|
||||
}
|
||||
$("#next").off("click").on("click", funcinc);
|
||||
}
|
||||
|
||||
|
||||
this.myReportParameters = undefined;
|
||||
this.myFilters = undefined;
|
||||
this.myMetadataFields = undefined;
|
||||
|
||||
|
||||
this.initMetadataFields = function() {
|
||||
this.myMetadataFields = new MetadataFields(self);
|
||||
this.myMetadataFields.load();
|
||||
this.myMetadataFields.load();
|
||||
}
|
||||
|
||||
|
||||
this.initBitstreamFields = function() {
|
||||
this.myBitstreamFields = new BitstreamFields(self);
|
||||
this.myBitstreamFields.load();
|
||||
this.myBitstreamFields.load();
|
||||
}
|
||||
|
||||
|
||||
this.baseInit = function() {
|
||||
this.myReportParameters = new ReportParameters(
|
||||
this.getDefaultParameters(),
|
||||
@@ -173,13 +173,13 @@ var Report = function() {
|
||||
});
|
||||
return itemdata;
|
||||
}
|
||||
|
||||
|
||||
this.export = function(rows) {
|
||||
var itemdata = "data:text/csv;charset=utf-8," + this.makeCsv(rows);
|
||||
var encodedUri = encodeURI(itemdata);
|
||||
window.open(encodedUri);
|
||||
window.open(encodedUri);
|
||||
}
|
||||
|
||||
|
||||
//this is meant to be overridden for each report
|
||||
this.exportCol = function(colnum, col) {
|
||||
var data = "";
|
||||
@@ -187,7 +187,7 @@ var Report = function() {
|
||||
data += self.exportCell(col);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
this.exportCell = function(col) {
|
||||
data = "\"";
|
||||
$(col).contents().each(function(i, node){
|
||||
@@ -198,16 +198,16 @@ var Report = function() {
|
||||
if ($(node).is("div:not(:last-child)")) {
|
||||
data += "||";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
data += "\"";
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
this.init = function() {
|
||||
this.baseInit();
|
||||
this.baseInit();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
var Auth = function(report) {
|
||||
@@ -242,17 +242,17 @@ var Auth = function(report) {
|
||||
self.authStat();
|
||||
self.callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.verifyShibLogin = function() {
|
||||
var self = this;
|
||||
$.ajax({
|
||||
url: "/rest/shibboleth-login",
|
||||
url: "/rest/shibboleth-login",
|
||||
success: self.authStat
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.authStat = function() {
|
||||
var self = this;
|
||||
$.ajax({
|
||||
@@ -264,7 +264,7 @@ var Auth = function(report) {
|
||||
success: function(data) {
|
||||
var user = "";
|
||||
if (data.email != undefined) {
|
||||
user = data.email;
|
||||
user = data.email;
|
||||
} else {
|
||||
user = "You are not logged in. Some items may be excluded from reports.";
|
||||
}
|
||||
@@ -279,10 +279,10 @@ var Auth = function(report) {
|
||||
if (data.email == undefined && self.report.makeShibLink()) {
|
||||
self.verifyShibLogin();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.logout = function() {
|
||||
var self = this;
|
||||
$.ajax({
|
||||
@@ -293,7 +293,7 @@ var Auth = function(report) {
|
||||
complete: function(xhr, status) {
|
||||
self.authStat();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
this.getHeaders = function() {
|
||||
var HEADERS = {};
|
||||
@@ -314,14 +314,14 @@ var ReportParameters = function(defaultParams, prmstr) {
|
||||
var field = tmparr[0];
|
||||
var val = decodeURIComponent(tmparr[1]);
|
||||
var pval = this.params[field];
|
||||
|
||||
|
||||
if ($.isArray(pval)) {
|
||||
pval[pval.length] = val;
|
||||
pval[pval.length] = val;
|
||||
} else {
|
||||
this.params[field] = val;
|
||||
}
|
||||
}
|
||||
$("#limit").val(this.params.limit);
|
||||
$("#limit").val(this.params.limit);
|
||||
$("#offset").val(this.params.offset);
|
||||
this.limit = this.params.limit;
|
||||
this.offset = this.params.offset;
|
||||
@@ -350,11 +350,11 @@ var ReportParameters = function(defaultParams, prmstr) {
|
||||
var lim = $("#limit").val();
|
||||
if ($.isNumeric(val) && $.isNumeric(lim)) {
|
||||
if (increment) {
|
||||
$("#offset").val(this.getNextOffset());
|
||||
$("#offset").val(this.getNextOffset());
|
||||
} else {
|
||||
$("#offset").val(this.getPrevOffset());
|
||||
$("#offset").val(this.getPrevOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.saveAsUrl = function(params) {
|
||||
@@ -381,7 +381,7 @@ var Filters = function() {
|
||||
$("#filter-reload").attr("disabled", false);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$.getJSON(
|
||||
"/rest/filters",
|
||||
function(data){
|
||||
@@ -444,13 +444,13 @@ var Filters = function() {
|
||||
list = "none";
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var MetadataFields = function(report) {
|
||||
this.metadataSchemas = undefined;
|
||||
var self = this;
|
||||
|
||||
|
||||
this.load = function(){
|
||||
$.ajax({
|
||||
url: "/rest/registries/schema",
|
||||
@@ -463,15 +463,15 @@ var MetadataFields = function(report) {
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.initFields = function(data, report) {
|
||||
var params = report.myReportParameters.params;
|
||||
self.metadataSchemas = data;
|
||||
self.drawShowFields(params["show_fields[]"]);
|
||||
}
|
||||
|
||||
|
||||
this.getShowFields = function(){
|
||||
var val = $("#show-fields select").val();
|
||||
return val == null ? Array() : val;
|
||||
@@ -497,7 +497,7 @@ var MetadataFields = function(report) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.initQueries = function(){};
|
||||
}
|
||||
|
||||
@@ -508,15 +508,15 @@ var BitstreamFields = function(report) {
|
||||
}
|
||||
this.map = [
|
||||
{
|
||||
key: "original-file-names",
|
||||
name: "Original File Names",
|
||||
key: "original-file-names",
|
||||
name: "Original File Names",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
return bit.name;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "mime-type",
|
||||
key: "mime-type",
|
||||
name: "Mime Type",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
@@ -524,7 +524,7 @@ var BitstreamFields = function(report) {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "bitstream-format",
|
||||
key: "bitstream-format",
|
||||
name: "Bitstream Format",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
@@ -532,7 +532,7 @@ var BitstreamFields = function(report) {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "bitstream-description",
|
||||
key: "bitstream-description",
|
||||
name: "Bitstream Description",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
@@ -540,7 +540,7 @@ var BitstreamFields = function(report) {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "bitstream-size",
|
||||
key: "bitstream-size",
|
||||
name: "Bitstream Size",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
@@ -548,18 +548,18 @@ var BitstreamFields = function(report) {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "bitstream-checksum",
|
||||
key: "bitstream-checksum",
|
||||
name: "MD5 Checksum",
|
||||
ftest: self.isOriginal,
|
||||
fval: function(bit) {
|
||||
if (bit.checkSum.checkSumAlgorithm === "MD5") {
|
||||
return bit.checkSum.value;
|
||||
return bit.checkSum.value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
this.load = function(){
|
||||
self.initFields(report);
|
||||
}
|
||||
@@ -568,7 +568,7 @@ var BitstreamFields = function(report) {
|
||||
var params = report.myReportParameters.params;
|
||||
self.drawShowFieldsBits(params["show_fields_bits[]"]);
|
||||
};
|
||||
|
||||
|
||||
this.hasBitstreamFields = function() {
|
||||
return self.getShowFieldsBits() != null;
|
||||
}
|
||||
@@ -576,20 +576,20 @@ var BitstreamFields = function(report) {
|
||||
var val = $("#show-fields-bits select").val();
|
||||
return val == null ? Array() : val;
|
||||
}
|
||||
|
||||
|
||||
this.drawShowFieldsBits = function(pfieldsBits) {
|
||||
var sel = $("<select name='show_fields_bits'/>");
|
||||
sel.attr("multiple","true").attr("size","8").appendTo("#show-fields-bits");
|
||||
for(var i=0; i<this.map.length; i++) {
|
||||
var opt = report.myHtmlUtil.addOpt(sel, this.map[i].name, this.map[i].key);
|
||||
if (pfieldsBits != null) {
|
||||
opt.attr("selected", pfieldsBits[this.map[i].key] != undefined ? "Y" : null);
|
||||
opt.attr("selected", pfieldsBits[this.map[i].key] != undefined ? "Y" : null);
|
||||
}
|
||||
sel.append(opt);
|
||||
sel.append(opt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
this.getKeyText = function(key, item, bitfields) {
|
||||
var ret = [];
|
||||
if (bitfields == null || item.bitstreams == null) {
|
||||
@@ -608,20 +608,20 @@ var BitstreamFields = function(report) {
|
||||
if (mapval == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
$.each(item.bitstreams, function(colindex, bitstream) {
|
||||
if (mapval.ftest(bitstream)) {
|
||||
var val = mapval.fval(bitstream);
|
||||
if (val != null) {
|
||||
if (isNaN(val) || ret.length == 0) {
|
||||
ret.push(val);
|
||||
ret.push(val);
|
||||
} else {
|
||||
ret[0] += val;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -661,6 +661,7 @@ var HtmlUtil = function() {
|
||||
a.append(val);
|
||||
a.attr("href", href);
|
||||
a.attr("target", "_blank");
|
||||
a.attr("rel", "noopener noreferrer");
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -704,7 +705,7 @@ var CommunitySelector = function(report, parent, paramCollSel) {
|
||||
var collSel = $("<select/>").attr("id","collSel").attr("name","collSel").attr("multiple", true).attr("size",15);
|
||||
parent.append(collSel);
|
||||
report.myHtmlUtil.addOpt(collSel, "Whole Repository", "");
|
||||
|
||||
|
||||
$.ajax({
|
||||
url: "/rest/hierarchy",
|
||||
dataType: "json",
|
||||
@@ -722,7 +723,7 @@ var CommunitySelector = function(report, parent, paramCollSel) {
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.addCommLabel = function(collSel, comm, indent, paramCollSel) {
|
||||
var prefix = "";
|
||||
@@ -738,12 +739,12 @@ var CommunitySelector = function(report, parent, paramCollSel) {
|
||||
opt.attr("selected", true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
if (comm.community != null) {
|
||||
$.each(comm.community, function(index, scomm) {
|
||||
self.addCommLabel(collSel, scomm, indent + 1, paramCollSel);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>7.0-beta3-SNAPSHOT</version>
|
||||
<version>7.0-beta4-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -460,6 +460,14 @@
|
||||
<artifactId>solr-cell</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
@@ -140,11 +140,11 @@ public class Application extends SpringBootServletInitializer {
|
||||
// Set Access-Control-Allow-Credentials to "true" and specify which origins are valid
|
||||
// for our Access-Control-Allow-Origin header
|
||||
.allowCredentials(corsAllowCredentials).allowedOrigins(corsAllowedOrigins)
|
||||
// Whitelist of request preflight headers allowed to be sent to us from the client
|
||||
// Allow list of request preflight headers allowed to be sent to us from the client
|
||||
.allowedHeaders("Authorization", "Content-Type", "X-Requested-With", "accept", "Origin",
|
||||
"Access-Control-Request-Method", "Access-Control-Request-Headers",
|
||||
"X-On-Behalf-Of")
|
||||
// Whitelist of response headers allowed to be sent by us (the server)
|
||||
// Allow list of response headers allowed to be sent by us (the server)
|
||||
.exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials",
|
||||
"Authorization");
|
||||
}
|
||||
|
@@ -16,10 +16,13 @@ import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.converter.EPersonConverter;
|
||||
import org.dspace.app.rest.link.HalLinkService;
|
||||
import org.dspace.app.rest.model.AuthenticationStatusRest;
|
||||
import org.dspace.app.rest.model.AuthenticationTokenRest;
|
||||
import org.dspace.app.rest.model.AuthnRest;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.hateoas.AuthenticationStatusResource;
|
||||
import org.dspace.app.rest.model.hateoas.AuthenticationTokenResource;
|
||||
import org.dspace.app.rest.model.hateoas.AuthnResource;
|
||||
import org.dspace.app.rest.model.wrapper.AuthenticationToken;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.security.RestAuthenticationService;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
@@ -32,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -118,6 +122,30 @@ public class AuthenticationRestController implements InitializingBean {
|
||||
"valid.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will generate a short lived token to be used for bitstream downloads among other things.
|
||||
*
|
||||
* curl -v -X POST https://{dspace-server.url}/api/authn/shortlivedtokens -H "Authorization: Bearer eyJhbG...COdbo"
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* curl -v -X POST https://{dspace-server.url}/api/authn/shortlivedtokens -H "Authorization: Bearer eyJhbG...COdbo"
|
||||
* }
|
||||
* </pre>
|
||||
* @param request The StandardMultipartHttpServletRequest
|
||||
* @return The created short lived token
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@RequestMapping(value = "/shortlivedtokens", method = RequestMethod.POST)
|
||||
public AuthenticationTokenResource shortLivedToken(HttpServletRequest request) {
|
||||
Projection projection = utils.obtainProjection();
|
||||
AuthenticationToken shortLivedToken =
|
||||
restAuthenticationService.getShortLivedAuthenticationToken(ContextUtil.obtainContext(request), request);
|
||||
AuthenticationTokenRest authenticationTokenRest = converter.toRest(shortLivedToken, projection);
|
||||
return converter.toResource(authenticationTokenRest);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/login", method = { RequestMethod.GET, RequestMethod.PUT, RequestMethod.PATCH,
|
||||
RequestMethod.DELETE })
|
||||
public ResponseEntity login() {
|
||||
|
@@ -34,6 +34,7 @@ import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogManager;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverResult;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
@@ -103,7 +104,8 @@ public class OpenSearchController {
|
||||
|
||||
// do some sanity checking
|
||||
if (!openSearchService.getFormats().contains(format)) {
|
||||
String err = "Format " + format + " is not supported.";
|
||||
// Since we are returning error response as HTML, escape any HTML in "format" param
|
||||
String err = "Format " + Utils.addEntities(format) + " is not supported.";
|
||||
response.setContentType("text/html");
|
||||
response.setContentLength(err.length());
|
||||
response.getWriter().write(err);
|
||||
|
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
|
||||
import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
|
||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.license.service.CreativeCommonsService;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This Repository is responsible for handling the CC License URIs.
|
||||
* It only supports a search method
|
||||
*/
|
||||
|
||||
@Component(SubmissionCCLicenseUrlRest.CATEGORY + "." + SubmissionCCLicenseUrlRest.NAME)
|
||||
public class SubmissionCCLicenseUrlRepository extends DSpaceRestRepository<SubmissionCCLicenseUrlRest, String>
|
||||
implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
protected Utils utils;
|
||||
|
||||
@Autowired
|
||||
protected CreativeCommonsService creativeCommonsService;
|
||||
|
||||
@Autowired
|
||||
protected ConverterService converter;
|
||||
|
||||
protected RequestService requestService = new DSpace().getRequestService();
|
||||
|
||||
@Autowired
|
||||
DiscoverableEndpointsService discoverableEndpointsService;
|
||||
|
||||
/**
|
||||
* Retrieves the CC License URI based on the license ID and answers in the field questions, provided as parameters
|
||||
* to this request
|
||||
*
|
||||
* @return the CC License URI as a SubmissionCCLicenseUrlRest
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@SearchRestMethod(name = "rightsByQuestions")
|
||||
public SubmissionCCLicenseUrlRest findByRightsByQuestions() {
|
||||
ServletRequest servletRequest = requestService.getCurrentRequest()
|
||||
.getServletRequest();
|
||||
Map<String, String[]> requestParameterMap = servletRequest
|
||||
.getParameterMap();
|
||||
Map<String, String> parameterMap = new HashMap<>();
|
||||
String licenseId = servletRequest.getParameter("license");
|
||||
if (StringUtils.isBlank(licenseId)) {
|
||||
throw new DSpaceBadRequestException(
|
||||
"A \"license\" parameter needs to be provided.");
|
||||
}
|
||||
|
||||
// Loop through parameters to find answer parameters, adding them to the parameterMap. Zero or more answers
|
||||
// may exist, as some CC licenses do not require answers
|
||||
for (String parameter : requestParameterMap.keySet()) {
|
||||
if (StringUtils.startsWith(parameter, "answer_")) {
|
||||
String field = StringUtils.substringAfter(parameter, "answer_");
|
||||
String answer = "";
|
||||
if (requestParameterMap.get(parameter).length > 0) {
|
||||
answer = requestParameterMap.get(parameter)[0];
|
||||
}
|
||||
parameterMap.put(field, answer);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> fullParamMap = creativeCommonsService.retrieveFullAnswerMap(licenseId, parameterMap);
|
||||
if (fullParamMap == null) {
|
||||
throw new ResourceNotFoundException("No CC License could be matched on the provided ID: " + licenseId);
|
||||
}
|
||||
boolean licenseContainsCorrectInfo = creativeCommonsService.verifyLicenseInformation(licenseId, fullParamMap);
|
||||
if (!licenseContainsCorrectInfo) {
|
||||
throw new DSpaceBadRequestException(
|
||||
"The provided answers do not match the required fields for the provided license.");
|
||||
}
|
||||
|
||||
String licenseUri = creativeCommonsService.retrieveLicenseUri(licenseId, fullParamMap);
|
||||
|
||||
SubmissionCCLicenseUrl submissionCCLicenseUrl = new SubmissionCCLicenseUrl(licenseUri, licenseUri);
|
||||
if (StringUtils.isBlank(licenseUri)) {
|
||||
throw new ResourceNotFoundException("No CC License URI could be found for ID: " + licenseId);
|
||||
}
|
||||
|
||||
return converter.toRest(submissionCCLicenseUrl, utils.obtainProjection());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The findOne method is not supported in this repository
|
||||
*/
|
||||
@PreAuthorize("permitAll()")
|
||||
public SubmissionCCLicenseUrlRest findOne(final Context context, final String s) {
|
||||
throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findOne");
|
||||
}
|
||||
|
||||
/**
|
||||
* The findAll method is not supported in this repository
|
||||
*/
|
||||
public Page<SubmissionCCLicenseUrlRest> findAll(final Context context, final Pageable pageable) {
|
||||
throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findAll");
|
||||
}
|
||||
|
||||
public Class<SubmissionCCLicenseUrlRest> getDomainClass() {
|
||||
return SubmissionCCLicenseUrlRest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + SubmissionCCLicenseUrlRest.CATEGORY + "/" +
|
||||
SubmissionCCLicenseUrlRest.NAME + "/search",
|
||||
SubmissionCCLicenseUrlRest.NAME + "-search")));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.util.AuthorizeUtil;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The EPerson Registration feature. It's able to be used on site objects if the user.registration property is set to
|
||||
* true. If it's set to true, it'll check if the current context is allowed to set the password.
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = EPersonRegistrationFeature.NAME,
|
||||
description = "It can be used to register an eperson")
|
||||
public class EPersonRegistrationFeature implements AuthorizationFeature {
|
||||
|
||||
public static final String NAME = "epersonRegistration";
|
||||
|
||||
@Autowired
|
||||
private RequestService requestService;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (!(object instanceof SiteRest)) {
|
||||
return false;
|
||||
}
|
||||
if (!AuthorizeUtil.authorizeNewAccountRegistration(context,
|
||||
requestService.getCurrentRequest().getHttpServletRequest())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[] {SiteRest.CATEGORY + "." + SiteRest.NAME};
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.AuthenticationTokenRest;
|
||||
import org.dspace.app.rest.model.wrapper.AuthenticationToken;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the converter from the AuthenticationToken to the REST data model
|
||||
*/
|
||||
@Component
|
||||
public class AuthenticationTokenConverter implements DSpaceConverter<AuthenticationToken, AuthenticationTokenRest> {
|
||||
@Override
|
||||
public AuthenticationTokenRest convert(AuthenticationToken modelObject, Projection projection) {
|
||||
AuthenticationTokenRest token = new AuthenticationTokenRest();
|
||||
token.setToken(modelObject.getToken());
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AuthenticationToken> getModelClass() {
|
||||
return AuthenticationToken.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.license.CCLicense;
|
||||
import org.dspace.license.CCLicenseField;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This converter is responsible for transforming the model representation of an CCLicense to the REST
|
||||
* representation of an CCLicense and vice versa
|
||||
**/
|
||||
@Component
|
||||
public class SubmissionCCLicenseConverter implements DSpaceConverter<CCLicense, SubmissionCCLicenseRest> {
|
||||
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
/**
|
||||
* Convert a CCLicense to its REST representation
|
||||
* @param modelObject - the CCLicense to convert
|
||||
* @param projection - the projection
|
||||
* @return the corresponding SubmissionCCLicenseRest object
|
||||
*/
|
||||
@Override
|
||||
public SubmissionCCLicenseRest convert(final CCLicense modelObject, final Projection projection) {
|
||||
SubmissionCCLicenseRest submissionCCLicenseRest = new SubmissionCCLicenseRest();
|
||||
submissionCCLicenseRest.setProjection(projection);
|
||||
submissionCCLicenseRest.setId(modelObject.getLicenseId());
|
||||
submissionCCLicenseRest.setName(modelObject.getLicenseName());
|
||||
|
||||
List<CCLicenseField> ccLicenseFieldList = modelObject.getCcLicenseFieldList();
|
||||
List<SubmissionCCLicenseFieldRest> submissionCCLicenseFieldRests = new LinkedList<>();
|
||||
if (ccLicenseFieldList != null) {
|
||||
for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
|
||||
submissionCCLicenseFieldRests.add(converter.toRest(ccLicenseField, projection));
|
||||
}
|
||||
}
|
||||
submissionCCLicenseRest.setFields(submissionCCLicenseFieldRests);
|
||||
return submissionCCLicenseRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<CCLicense> getModelClass() {
|
||||
return CCLicense.class;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.license.CCLicenseField;
|
||||
import org.dspace.license.CCLicenseFieldEnum;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This converter is responsible for transforming the model representation of an CCLicenseField to the REST
|
||||
* representation of an CCLicenseField and vice versa
|
||||
* The CCLicenseField is a sub component of the CCLicense object
|
||||
**/
|
||||
@Component
|
||||
public class SubmissionCCLicenseFieldConverter
|
||||
implements DSpaceConverter<CCLicenseField, SubmissionCCLicenseFieldRest> {
|
||||
|
||||
@Autowired
|
||||
private ConverterService converter;
|
||||
|
||||
/**
|
||||
* Convert a CCLicenseField to its REST representation
|
||||
* @param modelObject - the CCLicenseField to convert
|
||||
* @param projection - the projection
|
||||
* @return the corresponding SubmissionCCLicenseFieldRest object
|
||||
*/
|
||||
@Override
|
||||
public SubmissionCCLicenseFieldRest convert(final CCLicenseField modelObject, final Projection projection) {
|
||||
SubmissionCCLicenseFieldRest submissionCCLicenseFieldRest = new SubmissionCCLicenseFieldRest();
|
||||
submissionCCLicenseFieldRest.setId(modelObject.getId());
|
||||
submissionCCLicenseFieldRest.setLabel(modelObject.getLabel());
|
||||
submissionCCLicenseFieldRest.setDescription(modelObject.getDescription());
|
||||
|
||||
List<CCLicenseFieldEnum> fieldEnum = modelObject.getFieldEnum();
|
||||
List<SubmissionCCLicenseFieldEnumRest> submissionCCLicenseFieldEnumRests = new LinkedList<>();
|
||||
if (fieldEnum != null) {
|
||||
for (CCLicenseFieldEnum ccLicenseFieldEnum : fieldEnum) {
|
||||
submissionCCLicenseFieldEnumRests.add(converter.toRest(ccLicenseFieldEnum, projection));
|
||||
}
|
||||
}
|
||||
submissionCCLicenseFieldRest.setEnums(submissionCCLicenseFieldEnumRests);
|
||||
return submissionCCLicenseFieldRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<CCLicenseField> getModelClass() {
|
||||
return CCLicenseField.class;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.license.CCLicenseFieldEnum;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This converter is responsible for transforming the model representation of an CCLicenseFieldEnum to the REST
|
||||
* representation of an CCLicenseFieldEnum and vice versa
|
||||
* The CCLicenseFieldEnum is a sub component of the CCLicenseField object
|
||||
**/
|
||||
@Component
|
||||
public class SubmissionCCLicenseFieldEnumConverter
|
||||
implements DSpaceConverter<CCLicenseFieldEnum, SubmissionCCLicenseFieldEnumRest> {
|
||||
|
||||
/**
|
||||
* Convert a CCLicenseFieldEnum to its REST representation
|
||||
*
|
||||
* @param modelObject - the CCLicenseField to convert
|
||||
* @param projection - the projection
|
||||
* @return the corresponding SubmissionCCLicenseFieldEnumRest object
|
||||
*/
|
||||
@Override
|
||||
public SubmissionCCLicenseFieldEnumRest convert(final CCLicenseFieldEnum modelObject, final Projection projection) {
|
||||
SubmissionCCLicenseFieldEnumRest submissionCCLicenseFieldEnumRest = new SubmissionCCLicenseFieldEnumRest();
|
||||
submissionCCLicenseFieldEnumRest.setId(modelObject.getId());
|
||||
submissionCCLicenseFieldEnumRest.setLabel(modelObject.getLabel());
|
||||
submissionCCLicenseFieldEnumRest.setDescription(modelObject.getDescription());
|
||||
|
||||
return submissionCCLicenseFieldEnumRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<CCLicenseFieldEnum> getModelClass() {
|
||||
return CCLicenseFieldEnum.class;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
|
||||
import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* This converter is responsible for transforming a Submission CC License Url String to the REST
|
||||
* representation SubmissionCCLicenseUrlRest and vice versa
|
||||
*/
|
||||
@Component
|
||||
public class SubmissionCCLicenseUrlConverter
|
||||
implements DSpaceConverter<SubmissionCCLicenseUrl, SubmissionCCLicenseUrlRest> {
|
||||
|
||||
/**
|
||||
* Convert a Submission CC License Url String to its REST representation
|
||||
* @param modelObject - the CC License Url object to convert
|
||||
* @param projection - the projection
|
||||
* @return the corresponding SubmissionCCLicenseUrlRest object
|
||||
*/
|
||||
@Override
|
||||
public SubmissionCCLicenseUrlRest convert(SubmissionCCLicenseUrl modelObject, Projection projection) {
|
||||
SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest = new SubmissionCCLicenseUrlRest();
|
||||
submissionCCLicenseUrlRest.setUrl(modelObject.getUrl());
|
||||
submissionCCLicenseUrlRest.setId(modelObject.getId());
|
||||
|
||||
return submissionCCLicenseUrlRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<SubmissionCCLicenseUrl> getModelClass() {
|
||||
return SubmissionCCLicenseUrl.class;
|
||||
}
|
||||
|
||||
}
|
@@ -14,6 +14,8 @@ import java.sql.SQLException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.rest.security.RestAuthenticationService;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
@@ -43,6 +45,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionHandler {
|
||||
private static final Logger log = LogManager.getLogger(DSpaceApiExceptionControllerAdvice.class);
|
||||
|
||||
@Autowired
|
||||
private RestAuthenticationService restAuthenticationService;
|
||||
@@ -51,16 +54,16 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
protected void handleAuthorizeException(HttpServletRequest request, HttpServletResponse response, Exception ex)
|
||||
throws IOException {
|
||||
if (restAuthenticationService.hasAuthenticationData(request)) {
|
||||
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_FORBIDDEN);
|
||||
sendErrorResponse(request, response, ex, "Access is denied", HttpServletResponse.SC_FORBIDDEN);
|
||||
} else {
|
||||
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_UNAUTHORIZED);
|
||||
sendErrorResponse(request, response, ex, "Authentication is required", HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler({IllegalArgumentException.class, MultipartException.class})
|
||||
protected void handleWrongRequestException(HttpServletRequest request, HttpServletResponse response,
|
||||
Exception ex) throws IOException {
|
||||
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_BAD_REQUEST);
|
||||
sendErrorResponse(request, response, ex, "Request is invalid or incorrect", HttpServletResponse.SC_BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(SQLException.class)
|
||||
@@ -74,24 +77,24 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
protected void handleIOException(HttpServletRequest request, HttpServletResponse response, Exception ex)
|
||||
throws IOException {
|
||||
sendErrorResponse(request, response, ex,
|
||||
"An internal read or write operation failed (IO Exception)",
|
||||
"An internal read or write operation failed",
|
||||
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodNotAllowedException.class)
|
||||
protected void methodNotAllowedException(HttpServletRequest request, HttpServletResponse response,
|
||||
Exception ex) throws IOException {
|
||||
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_METHOD_NOT_ALLOWED);
|
||||
sendErrorResponse(request, response, ex, "Method is not allowed or supported",
|
||||
HttpServletResponse.SC_METHOD_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
@ExceptionHandler( {UnprocessableEntityException.class})
|
||||
protected void handleUnprocessableEntityException(HttpServletRequest request, HttpServletResponse response,
|
||||
Exception ex) throws IOException {
|
||||
|
||||
//422 is not defined in HttpServletResponse. Its meaning is "Unprocessable Entity".
|
||||
//Using the value from HttpStatus.
|
||||
sendErrorResponse(request, response, null,
|
||||
ex.getMessage(),
|
||||
"Unprocessable or invalid entity",
|
||||
HttpStatus.UNPROCESSABLE_ENTITY.value());
|
||||
}
|
||||
|
||||
@@ -100,7 +103,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
throws IOException {
|
||||
// we want the 400 status for missing parameters, see https://jira.lyrasis.org/browse/DS-4428
|
||||
sendErrorResponse(request, response, null,
|
||||
ex.getMessage(),
|
||||
"A required parameter is invalid",
|
||||
HttpStatus.BAD_REQUEST.value());
|
||||
}
|
||||
|
||||
@@ -109,7 +112,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
throws IOException {
|
||||
// we want the 400 status for missing parameters, see https://jira.lyrasis.org/browse/DS-4428
|
||||
sendErrorResponse(request, response, null,
|
||||
ex.getMessage(),
|
||||
"A required parameter is missing",
|
||||
HttpStatus.BAD_REQUEST.value());
|
||||
}
|
||||
|
||||
@@ -139,7 +142,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
} else {
|
||||
returnCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
sendErrorResponse(request, response, ex, "An Exception has occured", returnCode);
|
||||
sendErrorResponse(request, response, ex, "An exception has occurred", returnCode);
|
||||
|
||||
}
|
||||
|
||||
@@ -149,6 +152,13 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
//Make sure Spring picks up this exception
|
||||
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
|
||||
|
||||
// For now, just logging server errors.
|
||||
// We don't want to fill logs with bad/invalid REST API requests.
|
||||
if (statusCode == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) {
|
||||
// Log the full error and status code
|
||||
log.error("{} (status:{})", message, statusCode, ex);
|
||||
}
|
||||
|
||||
//Exception properties will be set by org.springframework.boot.web.support.ErrorPageFilter
|
||||
response.sendError(statusCode, message);
|
||||
}
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This filter assures that when the dspace instance supports multiple languages
|
||||
* they are noted in the Content-Language Header of the response. Where
|
||||
* appropriate the single endpoint can set the Content-Language header directly
|
||||
* to note that the response is specific for a language
|
||||
*
|
||||
* @author Mykhaylo Boychuk (at 4science.it)
|
||||
*/
|
||||
@Component
|
||||
public class ContentLanguageHeaderResponseFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
Locale[] locales = I18nUtil.getSupportedLocales();
|
||||
StringBuilder locsStr = new StringBuilder();
|
||||
for (Locale locale : locales) {
|
||||
if (locsStr.length() > 0) {
|
||||
locsStr.append(",");
|
||||
}
|
||||
locsStr.append(locale.getLanguage());
|
||||
}
|
||||
httpServletResponse.setHeader("Content-Language", locsStr.toString());
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.link;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.dspace.app.rest.AuthenticationRestController;
|
||||
import org.dspace.app.rest.model.hateoas.AuthenticationTokenResource;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.IanaLinkRelations;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This class adds the self link to the AuthenticationTokenResource.
|
||||
*/
|
||||
@Component
|
||||
public class AuthenticationTokenHalLinkFactory
|
||||
extends HalLinkFactory<AuthenticationTokenResource, AuthenticationRestController> {
|
||||
|
||||
@Override
|
||||
protected void addLinks(AuthenticationTokenResource halResource, Pageable pageable, LinkedList<Link> list)
|
||||
throws Exception {
|
||||
|
||||
list.add(buildLink(IanaLinkRelations.SELF.value(), getMethodOn().shortLivedToken(null)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<AuthenticationRestController> getControllerClass() {
|
||||
return AuthenticationRestController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<AuthenticationTokenResource> getResourceClass() {
|
||||
return AuthenticationTokenResource.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.link.process;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
import org.dspace.app.rest.link.HalLinkFactory;
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
|
||||
import org.dspace.app.rest.model.hateoas.SubmissionCCLicenseUrlResource;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* This class will provide the SubmissionCCLicenseUrlResource with links
|
||||
*/
|
||||
@Component
|
||||
public class SubmissionCCLicenseUrlResourceHalLinkFactory
|
||||
extends HalLinkFactory<SubmissionCCLicenseUrlResource, RestResourceController> {
|
||||
|
||||
@Autowired
|
||||
RequestService requestService;
|
||||
|
||||
/**
|
||||
* Add a self link based on the search parameters
|
||||
*
|
||||
* @param halResource - The halResource
|
||||
* @param pageable - The page information
|
||||
* @param list - The list of present links
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void addLinks(SubmissionCCLicenseUrlResource halResource, final Pageable pageable,
|
||||
LinkedList<Link> list)
|
||||
throws Exception {
|
||||
|
||||
halResource.removeLinks();
|
||||
Map<String, String[]> parameterMap = requestService.getCurrentRequest().getHttpServletRequest()
|
||||
.getParameterMap();
|
||||
|
||||
|
||||
UriComponentsBuilder uriComponentsBuilder = uriBuilder(getMethodOn().executeSearchMethods(
|
||||
SubmissionCCLicenseUrlRest.CATEGORY, SubmissionCCLicenseUrlRest.PLURAL, "rightsByQuestions", null, null,
|
||||
null, null, new LinkedMultiValueMap<>()));
|
||||
for (String key : parameterMap.keySet()) {
|
||||
uriComponentsBuilder.queryParam(key, parameterMap.get(key));
|
||||
}
|
||||
|
||||
list.add(buildLink("self", uriComponentsBuilder.build().toUriString()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<RestResourceController> getControllerClass() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<SubmissionCCLicenseUrlResource> getResourceClass() {
|
||||
return SubmissionCCLicenseUrlResource.class;
|
||||
}
|
||||
}
|
@@ -18,7 +18,7 @@ public class AuthenticationStatusRest extends BaseObjectRest<Integer> {
|
||||
private boolean authenticated;
|
||||
|
||||
public static final String NAME = "status";
|
||||
public static final String CATEGORY = "authn";
|
||||
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* The authentication token REST HAL Resource. The HAL Resource wraps the REST Resource
|
||||
* adding support for the links and embedded resources
|
||||
*/
|
||||
public class AuthenticationTokenRest extends RestAddressableModel {
|
||||
public static final String NAME = "shortlivedtoken";
|
||||
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;
|
||||
|
||||
private String token;
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
@@ -18,7 +18,7 @@ import org.dspace.app.rest.AuthenticationRestController;
|
||||
public class AuthnRest extends BaseObjectRest<Integer> {
|
||||
|
||||
public static final String NAME = "authn";
|
||||
public static final String CATEGORY = "authn";
|
||||
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;
|
||||
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
|
@@ -16,6 +16,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @author Jelle Pelgrims (jelle.pelgrims at atmire.com)
|
||||
*/
|
||||
@LinksRest(links = {
|
||||
@LinkRest(
|
||||
name = BundleRest.ITEM,
|
||||
method = "getItem"
|
||||
),
|
||||
@LinkRest(
|
||||
name = BundleRest.BITSTREAMS,
|
||||
method = "getBitstreams"
|
||||
@@ -30,6 +34,7 @@ public class BundleRest extends DSpaceObjectRest {
|
||||
public static final String PLURAL_NAME = "bundles";
|
||||
public static final String CATEGORY = RestAddressableModel.CORE;
|
||||
|
||||
public static final String ITEM = "item";
|
||||
public static final String BITSTREAMS = "bitstreams";
|
||||
public static final String PRIMARY_BITSTREAM = "primaryBitstream";
|
||||
|
||||
|
@@ -41,7 +41,7 @@ public class EPersonRest extends DSpaceObjectRest {
|
||||
|
||||
private boolean requireCertificate = false;
|
||||
|
||||
private boolean selfRegistered = false;
|
||||
private Boolean selfRegistered;
|
||||
|
||||
@JsonProperty(access = Access.WRITE_ONLY)
|
||||
private String password;
|
||||
@@ -92,11 +92,11 @@ public class EPersonRest extends DSpaceObjectRest {
|
||||
this.requireCertificate = requireCertificate;
|
||||
}
|
||||
|
||||
public boolean isSelfRegistered() {
|
||||
public Boolean isSelfRegistered() {
|
||||
return selfRegistered;
|
||||
}
|
||||
|
||||
public void setSelfRegistered(boolean selfRegistered) {
|
||||
public void setSelfRegistered(Boolean selfRegistered) {
|
||||
this.selfRegistered = selfRegistered;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
|
||||
/**
|
||||
* This class acts as the REST representation of the RegistrationData model class.
|
||||
* This class acts as a data holder for the RegistrationResource
|
||||
* Refer to {@link org.dspace.eperson.RegistrationData} for explanation about the properties
|
||||
*/
|
||||
public class RegistrationRest extends RestAddressableModel {
|
||||
|
||||
public static final String NAME = "registration";
|
||||
public static final String NAME_PLURAL = "registrations";
|
||||
public static final String CATEGORY = EPERSON;
|
||||
|
||||
private String email;
|
||||
private UUID user;
|
||||
|
||||
/**
|
||||
* Generic getter for the email
|
||||
* @return the email value of this RegisterRest
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the email
|
||||
* @param email The email to be set on this RegisterRest
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the user
|
||||
* @return the user value of this RegisterRest
|
||||
*/
|
||||
public UUID getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the user
|
||||
* @param user The user to be set on this RegisterRest
|
||||
*/
|
||||
public void setUser(UUID user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
@@ -32,6 +32,7 @@ public interface RestModel extends Serializable {
|
||||
public static final String WORKFLOW = "workflow";
|
||||
public static final String AUTHORIZATION = "authz";
|
||||
public static final String VERSIONING = "versioning";
|
||||
public static final String AUTHENTICATION = "authn";
|
||||
|
||||
public String getType();
|
||||
|
||||
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
/**
|
||||
* This class is the REST representation of the CCLicenseFieldEnum model object and acts as a data sub object
|
||||
* for the SubmissionCCLicenseFieldRest class.
|
||||
* Refer to {@link org.dspace.license.CCLicenseFieldEnum} for explanation of the properties
|
||||
*/
|
||||
public class SubmissionCCLicenseFieldEnumRest {
|
||||
|
||||
private String id;
|
||||
private String label;
|
||||
private String description;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(final String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is the REST representation of the CCLicenseField model object and acts as a data sub object
|
||||
* for the SubmissionCCLicenseRest class.
|
||||
* Refer to {@link org.dspace.license.CCLicenseField} for explanation of the properties
|
||||
*/
|
||||
public class SubmissionCCLicenseFieldRest {
|
||||
|
||||
private String id;
|
||||
|
||||
private String label;
|
||||
|
||||
private String description;
|
||||
|
||||
private List<SubmissionCCLicenseFieldEnumRest> enums;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(final String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public List<SubmissionCCLicenseFieldEnumRest> getEnums() {
|
||||
return enums;
|
||||
}
|
||||
|
||||
public void setEnums(final List<SubmissionCCLicenseFieldEnumRest> enums) {
|
||||
this.enums = enums;
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* This class is the REST representation of the CCLicense model object and acts as a data object
|
||||
* for the SubmissionCCLicenseResource class.
|
||||
* Refer to {@link org.dspace.license.CCLicense} for explanation of the properties
|
||||
*/
|
||||
public class SubmissionCCLicenseRest extends BaseObjectRest<String> {
|
||||
public static final String NAME = "submissioncclicense";
|
||||
public static final String PLURAL = "submissioncclicenses";
|
||||
|
||||
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<SubmissionCCLicenseFieldRest> fields;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<SubmissionCCLicenseFieldRest> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(final List<SubmissionCCLicenseFieldRest> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* This class is the REST representation of the CCLicense URL String object and acts as a data object
|
||||
* for the SubmissionCCLicenseUrlRest class.
|
||||
*/
|
||||
public class SubmissionCCLicenseUrlRest extends BaseObjectRest<String> {
|
||||
public static final String NAME = "submissioncclicenseUrl";
|
||||
public static final String PLURAL = "submissioncclicenseUrls";
|
||||
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
|
||||
|
||||
|
||||
private String url;
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(final String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return SubmissionCCLicenseUrlRest.CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.AuthenticationTokenRest;
|
||||
|
||||
/**
|
||||
* Token resource, wraps the AuthenticationToken object
|
||||
*/
|
||||
public class AuthenticationTokenResource extends HALResource<AuthenticationTokenRest> {
|
||||
|
||||
public AuthenticationTokenResource(AuthenticationTokenRest content) {
|
||||
super(content);
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.RegistrationRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
|
||||
/**
|
||||
* Registration HAL Resource. This resource adds the data from the REST object together with embedded objects
|
||||
* and a set of links if applicable
|
||||
*/
|
||||
@RelNameDSpaceResource(RegistrationRest.NAME)
|
||||
public class RegistrationResource extends HALResource<RegistrationRest> {
|
||||
public RegistrationResource(RegistrationRest content) {
|
||||
super(content);
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
|
||||
/**
|
||||
* CCLicense HAL Resource. This resource adds the data from the REST object together with embedded objects
|
||||
* and a set of links if applicable
|
||||
*/
|
||||
@RelNameDSpaceResource(SubmissionCCLicenseRest.NAME)
|
||||
public class SubmissionCCLicenseResource extends DSpaceResource<SubmissionCCLicenseRest> {
|
||||
public SubmissionCCLicenseResource(SubmissionCCLicenseRest submissionCCLicenseRest, Utils utils) {
|
||||
super(submissionCCLicenseRest, utils);
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
|
||||
/**
|
||||
* SubmissionCCLicenseUrl HAL Resource. This resource adds the data from the REST object together with embedded objects
|
||||
* and a set of links if applicable
|
||||
*/
|
||||
@RelNameDSpaceResource(SubmissionCCLicenseUrlRest.NAME)
|
||||
public class SubmissionCCLicenseUrlResource extends DSpaceResource<SubmissionCCLicenseUrlRest> {
|
||||
public SubmissionCCLicenseUrlResource(SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest, Utils utils) {
|
||||
super(submissionCCLicenseUrlRest, utils);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.step;
|
||||
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
|
||||
/**
|
||||
* Java Bean to expose the section creativecommons representing the CC License during in progress submission.
|
||||
*/
|
||||
public class DataCCLicense implements SectionData {
|
||||
|
||||
private String uri;
|
||||
|
||||
private String rights;
|
||||
|
||||
private BitstreamRest file;
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(final String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getRights() {
|
||||
return rights;
|
||||
}
|
||||
|
||||
public void setRights(final String rights) {
|
||||
this.rights = rights;
|
||||
}
|
||||
|
||||
public BitstreamRest getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(final BitstreamRest file) {
|
||||
this.file = file;
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.wrapper;
|
||||
|
||||
/**
|
||||
* This class represents an authentication token. It acts as a wrapper for a String object to differentiate between
|
||||
* actual Strings and AuthenticationToken
|
||||
*/
|
||||
public class AuthenticationToken {
|
||||
private String token;
|
||||
|
||||
public AuthenticationToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.wrapper;
|
||||
|
||||
/**
|
||||
* This class represents a model implementation for {@link org.dspace.app.rest.model.SubmissionCCLicenseUrlRest}
|
||||
* This will simply store a url and an id. it'll be used to create an object with these variables out of information
|
||||
* that came from the back-end. This object will then be used in the
|
||||
* {@link org.dspace.app.rest.converter.SubmissionCCLicenseUrlConverter} to turn it into its REST object
|
||||
*/
|
||||
public class SubmissionCCLicenseUrl {
|
||||
|
||||
/**
|
||||
* The url for ths object
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* The id for this object
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Default constructor with two parameters, url and id
|
||||
* @param url The url of this object
|
||||
* @param id The id of this object
|
||||
*/
|
||||
public SubmissionCCLicenseUrl(String url, String id) {
|
||||
this.url = url;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the url
|
||||
* @return the url value of this SubmissionCCLicenseUrl
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the url
|
||||
* @param url The url to be set on this SubmissionCCLicenseUrl
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the id
|
||||
* @return the id value of this SubmissionCCLicenseUrl
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the id
|
||||
* @param id The id to be set on this SubmissionCCLicenseUrl
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
@@ -7,10 +7,15 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.utils.DSpace;
|
||||
@@ -33,11 +38,47 @@ public abstract class AbstractDSpaceRestRepository {
|
||||
protected RequestService requestService = new DSpace().getRequestService();
|
||||
|
||||
protected Context obtainContext() {
|
||||
Context context = null;
|
||||
Request currentRequest = requestService.getCurrentRequest();
|
||||
return ContextUtil.obtainContext(currentRequest.getServletRequest());
|
||||
context = ContextUtil.obtainContext(currentRequest.getServletRequest());
|
||||
Locale currentLocale = getLocale(context, currentRequest);
|
||||
context.setCurrentLocale(currentLocale);
|
||||
return context;
|
||||
}
|
||||
|
||||
public RequestService getRequestService() {
|
||||
return requestService;
|
||||
}
|
||||
|
||||
private Locale getLocale(Context context, Request request) {
|
||||
Locale userLocale = null;
|
||||
Locale supportedLocale = null;
|
||||
|
||||
// Locales requested from client
|
||||
String locale = request.getHttpServletRequest().getHeader("Accept-Language");
|
||||
if (StringUtils.isNotBlank(locale)) {
|
||||
Enumeration<Locale> locales = request.getHttpServletRequest().getLocales();
|
||||
if (locales != null) {
|
||||
while (locales.hasMoreElements()) {
|
||||
Locale current = locales.nextElement();
|
||||
if (I18nUtil.isSupportedLocale(current)) {
|
||||
userLocale = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userLocale == null && context.getCurrentUser() != null) {
|
||||
String userLanguage = context.getCurrentUser().getLanguage();
|
||||
if (userLanguage != null) {
|
||||
userLocale = new Locale(userLanguage);
|
||||
}
|
||||
}
|
||||
if (userLocale == null) {
|
||||
return I18nUtil.getDefaultLocale();
|
||||
}
|
||||
supportedLocale = I18nUtil.getSupportedLocale(userLocale);
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -242,25 +242,27 @@ public class AuthorizationRestRepository extends DSpaceRestRepository<Authorizat
|
||||
*/
|
||||
private EPerson getUserFromRequestParameter(Context context, UUID epersonUuid)
|
||||
throws AuthorizeException, SQLException {
|
||||
|
||||
EPerson currUser = context.getCurrentUser();
|
||||
EPerson user = currUser;
|
||||
if (epersonUuid != null) {
|
||||
|
||||
if (epersonUuid == null) {
|
||||
// no user is specified in the request parameters, check the permissions for the current user
|
||||
return currUser;
|
||||
|
||||
} else {
|
||||
// a user is specified in the request parameters
|
||||
|
||||
if (currUser == null) {
|
||||
throw new AuthorizeException("attempt to anonymously access the authorization of the eperson "
|
||||
+ epersonUuid);
|
||||
} else {
|
||||
// an user is specified in the request parameters
|
||||
if (!authorizeService.isAdmin(context) && !epersonUuid.equals(currUser.getID())) {
|
||||
throw new AuthorizeException("attempt to access the authorization of the eperson " + epersonUuid
|
||||
+ " only system administrators can see the authorization of other users");
|
||||
}
|
||||
user = epersonService.find(context, epersonUuid);
|
||||
|
||||
} else if (!authorizeService.isAdmin(context) && !epersonUuid.equals(currUser.getID())) {
|
||||
throw new AuthorizeException("attempt to access the authorization of the eperson " + epersonUuid
|
||||
+ " as a non-admin; only system administrators can see the authorization of other users");
|
||||
}
|
||||
} else {
|
||||
// the request asks to check the permission for the anonymous user
|
||||
user = null;
|
||||
|
||||
return epersonService.find(context, epersonUuid);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.BundleService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Link repository for "item" subresource of an individual bundle.
|
||||
*/
|
||||
@Component(BundleRest.CATEGORY + "." + BundleRest.NAME + "." + BundleRest.ITEM)
|
||||
public class BundleItemLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
BundleService bundleService;
|
||||
|
||||
/**
|
||||
* Get the item where the provided bundle resides in
|
||||
*/
|
||||
@PreAuthorize("hasPermission(#bundleId, 'BUNDLE', 'READ')")
|
||||
public ItemRest getItem(@Nullable HttpServletRequest request,
|
||||
UUID bundleId,
|
||||
@Nullable Pageable optionalPageable,
|
||||
Projection projection) {
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
Bundle bundle = bundleService.find(context, bundleId);
|
||||
if (bundle == null) {
|
||||
throw new ResourceNotFoundException("No such bundle: " + bundleId);
|
||||
}
|
||||
Item item = bundle.getItems().get(0);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return converter.toRest(item, projection);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -16,22 +16,34 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.DiscoverableEndpointsService;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureService;
|
||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.MetadataRest;
|
||||
import org.dspace.app.rest.model.MetadataValueRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.util.AuthorizeUtil;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.RegistrationData;
|
||||
import org.dspace.eperson.service.AccountService;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.eperson.service.RegistrationDataService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -46,12 +58,26 @@ import org.springframework.stereotype.Component;
|
||||
public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, EPersonRest>
|
||||
implements InitializingBean {
|
||||
|
||||
private static final Logger log = Logger.getLogger(EPersonRestRepository.class);
|
||||
|
||||
@Autowired
|
||||
AuthorizeService authorizeService;
|
||||
|
||||
@Autowired
|
||||
DiscoverableEndpointsService discoverableEndpointsService;
|
||||
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
|
||||
@Autowired
|
||||
private AuthorizationFeatureService authorizationFeatureService;
|
||||
|
||||
@Autowired
|
||||
private SiteService siteService;
|
||||
|
||||
@Autowired
|
||||
private RegistrationDataService registrationDataService;
|
||||
|
||||
private final EPersonService es;
|
||||
|
||||
|
||||
@@ -72,7 +98,23 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
} catch (IOException e1) {
|
||||
throw new UnprocessableEntityException("error parsing the body... maybe this is not the right error code");
|
||||
}
|
||||
String token = req.getParameter("token");
|
||||
// If a token is available, we'll swap to the execution that is token based
|
||||
if (StringUtils.isNotBlank(token)) {
|
||||
try {
|
||||
return createAndReturn(context, epersonRest, token);
|
||||
} catch (SQLException e) {
|
||||
log.error("Something went wrong in the creation of an EPerson with token: " + token, e);
|
||||
throw new RuntimeException("Something went wrong in the creation of an EPerson with token: " + token);
|
||||
}
|
||||
}
|
||||
// If no token is present, we simply do the admin execution
|
||||
EPerson eperson = createEPersonFromRestObject(context, epersonRest);
|
||||
|
||||
return converter.toRest(eperson, utils.obtainProjection());
|
||||
}
|
||||
|
||||
private EPerson createEPersonFromRestObject(Context context, EPersonRest epersonRest) throws AuthorizeException {
|
||||
EPerson eperson = null;
|
||||
try {
|
||||
eperson = es.create(context);
|
||||
@@ -90,8 +132,81 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
return eperson;
|
||||
}
|
||||
|
||||
return converter.toRest(eperson, utils.obtainProjection());
|
||||
/**
|
||||
* This method will perform checks on whether or not the given Request was valid for the creation of an EPerson
|
||||
* with a token or not.
|
||||
* It'll check that the token exists, that the token doesn't yet resolve to an actual eperson already,
|
||||
* that the email in the given json is equal to the email for the token and that other properties are set to
|
||||
* what we expect in this creation.
|
||||
* It'll check if all of those constraints hold true and if we're allowed to register new accounts.
|
||||
* If this is the case, we'll create an EPerson without any authorization checks and delete the token
|
||||
* @param context The DSpace context
|
||||
* @param epersonRest The EPersonRest given to be created
|
||||
* @param token The token to be used
|
||||
* @return The EPersonRest after the creation of the EPerson object
|
||||
* @throws AuthorizeException If something goes wrong
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
private EPersonRest createAndReturn(Context context, EPersonRest epersonRest, String token)
|
||||
throws AuthorizeException, SQLException {
|
||||
if (!AuthorizeUtil.authorizeNewAccountRegistration(context, requestService
|
||||
.getCurrentRequest().getHttpServletRequest())) {
|
||||
throw new DSpaceBadRequestException(
|
||||
"Registration is disabled, you are not authorized to create a new Authorization");
|
||||
}
|
||||
RegistrationData registrationData = registrationDataService.findByToken(context, token);
|
||||
if (registrationData == null) {
|
||||
throw new DSpaceBadRequestException("The token given as parameter: " + token + " does not exist" +
|
||||
" in the database");
|
||||
}
|
||||
if (es.findByEmail(context, registrationData.getEmail()) != null) {
|
||||
throw new DSpaceBadRequestException("The token given already contains an email address that resolves" +
|
||||
" to an eperson");
|
||||
}
|
||||
String emailFromJson = epersonRest.getEmail();
|
||||
if (StringUtils.isNotBlank(emailFromJson)) {
|
||||
if (!StringUtils.equalsIgnoreCase(registrationData.getEmail(), emailFromJson)) {
|
||||
throw new DSpaceBadRequestException("The email resulting from the token does not match the email given"
|
||||
+ " in the json body. Email from token: " +
|
||||
registrationData.getEmail() + " email from the json body: "
|
||||
+ emailFromJson);
|
||||
}
|
||||
}
|
||||
if (epersonRest.isSelfRegistered() != null && !epersonRest.isSelfRegistered()) {
|
||||
throw new DSpaceBadRequestException("The self registered property cannot be set to false using this method"
|
||||
+ " with a token");
|
||||
}
|
||||
checkRequiredProperties(epersonRest);
|
||||
// We'll turn off authorisation system because this call isn't admin based as it's token based
|
||||
context.turnOffAuthorisationSystem();
|
||||
EPerson ePerson = createEPersonFromRestObject(context, epersonRest);
|
||||
context.restoreAuthSystemState();
|
||||
// Restoring authorisation state right after the creation call
|
||||
accountService.deleteToken(context, token);
|
||||
if (context.getCurrentUser() == null) {
|
||||
context.setCurrentUser(ePerson);
|
||||
}
|
||||
return converter.toRest(ePerson, utils.obtainProjection());
|
||||
}
|
||||
|
||||
private void checkRequiredProperties(EPersonRest epersonRest) {
|
||||
MetadataRest metadataRest = epersonRest.getMetadata();
|
||||
if (metadataRest != null) {
|
||||
List<MetadataValueRest> epersonFirstName = metadataRest.getMap().get("eperson.firstname");
|
||||
List<MetadataValueRest> epersonLastName = metadataRest.getMap().get("eperson.lastname");
|
||||
if (epersonFirstName == null || epersonLastName == null ||
|
||||
epersonFirstName.isEmpty() || epersonLastName.isEmpty()) {
|
||||
throw new UnprocessableEntityException("The eperson.firstname and eperson.lastname values need to be " +
|
||||
"filled in");
|
||||
}
|
||||
}
|
||||
String password = epersonRest.getPassword();
|
||||
if (!accountService.verifyPasswordStructure(password)) {
|
||||
throw new DSpaceBadRequestException("The given password is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,6 +290,18 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
||||
@PreAuthorize("hasPermission(#uuid, 'EPERSON', #patch)")
|
||||
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
||||
Patch patch) throws AuthorizeException, SQLException {
|
||||
if (StringUtils.isNotBlank(request.getParameter("token"))) {
|
||||
boolean passwordChangeFound = false;
|
||||
for (Operation operation : patch.getOperations()) {
|
||||
if (StringUtils.equalsIgnoreCase(operation.getPath(), "/password")) {
|
||||
passwordChangeFound = true;
|
||||
}
|
||||
}
|
||||
if (!passwordChangeFound) {
|
||||
throw new AccessDeniedException("Refused to perform the EPerson patch based on a token without " +
|
||||
"changing the password");
|
||||
}
|
||||
}
|
||||
patchDSpaceObject(apiCategory, model, uuid, patch);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user