Skip to content

Commit

Permalink
UBO-96 ORCID-Anbindung optimieren (#284)
Browse files Browse the repository at this point in the history
* UBO-96 Added button to unlink user account from ORCID

UBO-96 Added i18n key 'orcid.integration.unlink'

UBO-96 Added DozBibUserServlet

UBO-96 Code format web-fragment.xml

UBO-96 Placed orcid button inside <p>-element

UBO-96 Added Testing Servlet

UBO-96 Store updated UserAttributes

UBO-96 Check for guest user

* UBO-96 Added dependency to org.mycore:mycore-orcid2

* UBO-96 Removed dependency to org.mycore:mycore-orcid
Commented code to make ubo-common compile

* UBO-96 Set redirect url to $WebApplicationBaseURL/orcid

* UBO-96 Added ORCIDTools.js
UBO-96 Renamed mycore-orcid properties to their equivalent mycore-orcid2 properties

* UBO-96 Updated check for presence of orcid token

* UBO-96 Updated DozBibUserServlet to use mycore-orcid2 api

* UBO-96 Added method 'revoke' to ORCIDTools.js

* UBO-96 Added ubo-dialog.xsl

* UBO-96 Show confirm dialog when user trys to revoke orcid connection

* UBO-96 Read number of publications for user from orcid
UBO-96 Added DozBibORCIDUtils (WIP)

* UBO-96 Test for orcid_credential attribute rather than orcid_id

* UBO-96 Added public static boolean weAreTrustedParty() to DozBibORCIDUtils

* UBO-96 Renamed DozBibUserServlet to DozBibORCIDUserServlet and moved class to package /org/mycore/ubo/orcid/

* UBO-96 Migrated orcid list import

* UBO-96 Renamed property MCR.ORCID.LinkURL to MCR.ORCID2.LinkURL in mods-display.xsl

* UBO-96 Migrated mycore2orcid.js to mycore-orcid2

* UBO-96 Added simple notification dialog to ubo-dialog.xsl

* UBO-96 Fixed grammar

* UBO-96 Do not use slang as button label

* UBO-96 Changed upload to orcid button type

* UBO-96 Fixed orcid indicator title/tooltip

* UBO-96 Fixed link to orcid in user profile

* UBO-96 Reflect changes from /rsc to /api in mycore-orcic2 (WIP)

* UBO-96 Added orcid2 properties

* UBO-96 Deprecated ORCIDTools.js

* UBO-96 Use JWT and include /modules/orcid2/js/orcid-auth.js from mycore-orcid2

* UBO-96 Removed ORCIDTools.js

* UBO-96 Removed method loadScript()

* UBO-96 Reflect recent changes in mycore-orcid2

* UBO-96 Use POST http method for pushing a publication to ORCID

* UBO-96 Changed position of MCRORCIDWorkEventHandler

* UBO-96 Endpoint is splitted into update and create

* UBO-96 Allow user to activate automatic update of ORCID® profile

* UBO-96 Reflect sync status in orcid status headline

* UBO-96 Renamed user attribute to orcid_update_profile (name might change later)

* UBO-96 Changed some i18n values in messages_en.properties

* UBO-96 Fixed NPE and updated javadoc

* UBO-96 Remove TODO in MCRUserMatcherUtils

* UBO-96 Delete user attribute 'orcid_update_profile' when orcid auth is removed

* UBO-96 Added action parameter to DozBibORCIDUserServlet

* UBO-96 Do not die on invalid token

* UBO-96 Set propert MCR.ORCID2.WorkEventHandler.UpdateOnlyExisting = true

* UBO-96 Format

* UBO-96 Disable upload to orcid button once it was clicked

* UBO-96 Test for property MCR.ORCID2.Client.V3.APIMode

* UBO-96 Added include in html-layout.xsl to user-orcid.xsl

* UBO-96 public static String getFirstOrcidByCurrentUser() to DozBibORCIDUtils to enable linking to orcid

* UBO-96 Updated import of MCRORCIDWorkUtils to org.mycore.orcid2.v3.work.MCRORCIDWorkUtils

* UBO-96 Updated MCR.EventHandler.MCRObject.018A.Class

* UBO-96 Updated properties reflecting latest changes in mycore-orcid2

* UBO-96 Disabled update by user

* UBO-96 Show id of publication when logging to js console

* UBO-96 adopt to new orcid2 version

* UBO-96 update ORCIDWorkEventHandler to new version

* UBO-96 updated create-work path

* Improve orcid unlinking and allow to change user settings

* UBO-96 Added i18n orcid.integration.list to messages_en.properties

* UBO-96 Added i18n orcid.integration.settings.title to messages_en.properties

* UBO-96 Added i18n orcid.integration.settings.createFirstWork, orcid.integration.settings.alwaysUpdateWork, orcid.integration.settings.createDuplicateWork, orcid.integration.settings.recreateDeletedWork to messages_en.properties

* UBO-96 reformat message properties for better diff

* UBO-96 fix translation bug

* UBO-96 set editable user attributes, to prevent editing of orcid token

* UBO-96 Added public static int getNumWorks(String orcid) to DozBibORCIDUtils.java

* UBO-96 Added javadoc and altered public static int getNumWorks() (returns now the total of publications based on all connected orcids)

* UBO-96 Display orcid id in summary line

* UBO-96 Added public static boolean isConnected(String orcid) to DozBibORCIDUtils

* UBO-96 Removed public static boolean hasSyncEnabled() from DozBibORCIDUtils since it is obsolete

* UBO-96 Fixed javadoc in DozBibORCIDUserServlet

* UBO-96 update information text

---------

Co-authored-by: Kathleen Neumann <[email protected]>
Co-authored-by: Sebastian Hofmann <[email protected]>
  • Loading branch information
3 people committed Sep 5, 2023
1 parent 96db3d8 commit f50ef50
Show file tree
Hide file tree
Showing 20 changed files with 3,418 additions and 2,496 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.mycore</groupId>
<artifactId>mycore-orcid2</artifactId>
<version>${mycore.version}</version>
</dependency>
<dependency>
<groupId>org.mycore.ubo</groupId>
<artifactId>ubo-cli</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion ubo-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@
</dependency>
<dependency>
<groupId>org.mycore</groupId>
<artifactId>mycore-orcid</artifactId>
<artifactId>mycore-orcid2</artifactId>
</dependency>
<dependency>
<groupId>org.mycore</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
package org.mycore.ubo.importer.orcid;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.mycore.common.content.MCRContent;
import org.mycore.common.content.MCRJDOMContent;
import org.mycore.common.content.transformer.MCRContentTransformer;
import org.mycore.orcid.MCRORCIDProfile;
import org.mycore.orcid.works.MCRWorksSection;
import org.xml.sax.SAXException;
import org.mycore.orcid2.MCRORCIDUtils;
import org.mycore.orcid2.client.exception.MCRORCIDRequestException;
import org.mycore.orcid2.v3.client.MCRORCIDClientHelper;
import org.mycore.orcid2.v3.client.MCRORCIDSectionImpl;
import org.mycore.orcid2.v3.work.MCRORCIDWorkUtils;
import org.orcid.jaxb.model.v3.release.record.Work;
import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup;
import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary;
import org.orcid.jaxb.model.v3.release.record.summary.Works;

public class Orcid2WorksTransformer extends MCRContentTransformer {

protected Logger LOGGER = LogManager.getLogger(Orcid2WorksTransformer.class);

public MCRJDOMContent transform(MCRContent source) throws IOException {
String orcid = source.asString();

MCRORCIDProfile profile = new MCRORCIDProfile(orcid);
try {
MCRWorksSection worksSection = profile.getWorksSection();
worksSection.fetchDetails();

Element modsCollection = worksSection.buildMODSCollection();
return new MCRJDOMContent(modsCollection);
} catch (JDOMException | SAXException ex) {
throw new IOException(ex);
}
List<Work> workList = new ArrayList<>();

Arrays.stream(source.asString().split("\\s"))
.filter(orcid -> orcid.trim().length() > 0)
.forEach(orcid -> {
try {
Works works = MCRORCIDClientHelper.getClientFactory().createReadClient().fetch(orcid,
MCRORCIDSectionImpl.WORKS, Works.class);

for (WorkGroup wg : works.getWorkGroup()) {
WorkSummary ws = wg.getWorkSummary().stream()
.filter(workSummary -> workSummary.getDisplayIndex().equals("1")).findFirst().get();

Work work = MCRORCIDClientHelper.getClientFactory().createReadClient().fetch(orcid,
MCRORCIDSectionImpl.WORK, Work.class, ws.getPutCode());
workList.add(work);
}
} catch (MCRORCIDRequestException e) {
LOGGER.warn("Could not get works for ORCID {}. {}", orcid, e.getMessage());
}
});

List<Element> workElements = MCRORCIDWorkUtils.buildUnmergedMODSFromWorks(workList);
Element modsCollection = MCRORCIDUtils.buildMODSCollection(workElements);

return new MCRJDOMContent(modsCollection);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.mycore.common.config.MCRConfiguration2;
import org.mycore.datamodel.metadata.MCRObject;
import org.mycore.mods.MCRMODSWrapper;
import org.mycore.orcid.user.MCRORCIDUser;
import org.mycore.orcid2.user.MCRORCIDUser;
import org.mycore.ubo.ldap.LDAPObject;
import org.mycore.user2.MCRRealmFactory;
import org.mycore.user2.MCRUser;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.mycore.ubo.orcid;

import java.io.IOException;
import java.util.Set;
import java.util.SortedSet;

import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mycore.common.MCRSessionMgr;
import org.mycore.common.xml.MCRXMLFunctions;
import org.mycore.frontend.MCRFrontendUtil;
import org.mycore.frontend.servlets.MCRServlet;
import org.mycore.frontend.servlets.MCRServletJob;
import org.mycore.orcid2.user.MCRORCIDSessionUtils;
import org.mycore.orcid2.user.MCRORCIDUser;
import org.mycore.orcid2.user.MCRORCIDUserUtils;
import org.mycore.user2.MCRUser;
import org.mycore.user2.MCRUserAttribute;
import org.mycore.user2.MCRUserManager;

/**
* Servlet removes all orcid access tokens of the current user. If you want to remove a single access token for
* a given orcid please see {@link org.mycore.orcid2.rest.resources.MCRORCIDResource#revoke(String)} )}
*
* @author shermann
* */
public class DozBibORCIDUserServlet extends MCRServlet {

public final static Logger LOGGER = LogManager.getLogger(DozBibORCIDUserServlet.class);

@Override
protected void doGetPost(MCRServletJob job) throws Exception {
if (MCRXMLFunctions.isCurrentUserGuestUser()) {
job.getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
}

String action = job.getRequest().getParameter("action");
if (action == null) {
redirectToProfile(job);
return;
}

MCRORCIDUser orcidUser = MCRORCIDSessionUtils.getCurrentUser();
Set<String> orcidIdentifiers = orcidUser.getORCIDs();

if (orcidIdentifiers.isEmpty()) {
redirectToProfile(job);
return;
}

switch (action) {
case "sync":
toggleSync();
break;
case "revoke":
orcidUser.getUser()
.getAttributes()
.removeIf(a -> a.getName().equals("orcid_update_profile"));

orcidIdentifiers.forEach(orcid -> {
LOGGER.info("Unlinking ORCID {} for user {}", orcid, orcidUser.getUser().getUserID());
MCRORCIDUserUtils.revokeCredentialByORCID(orcidUser, orcid);
});
break;
}

redirectToProfile(job);
}

private void toggleSync() {
MCRUser user = MCRUserManager.getUser(MCRSessionMgr.getCurrentSession().getUserInformation().getUserID());
SortedSet<MCRUserAttribute> attributes = user.getAttributes();

attributes.stream()
.filter(attr -> attr.getName().equals("orcid_update_profile"))
.findFirst()
.ifPresentOrElse(present -> {
attributes.remove(present);
}, () -> {
attributes.add(new MCRUserAttribute("orcid_update_profile", String.valueOf(true)));
});
}

protected void redirectToProfile(MCRServletJob job) throws IOException {
job.getResponse().sendRedirect(MCRFrontendUtil.getBaseURL() + "servlets/MCRUserServlet?action=show");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.mycore.ubo.orcid;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mycore.common.xml.MCRXMLFunctions;
import org.mycore.orcid2.client.MCRORCIDCredential;
import org.mycore.orcid2.client.MCRORCIDUserClient;
import org.mycore.orcid2.client.exception.MCRORCIDRequestException;
import org.mycore.orcid2.user.MCRORCIDSessionUtils;
import org.mycore.orcid2.user.MCRORCIDUser;
import org.mycore.orcid2.v3.client.MCRORCIDClientHelper;
import org.mycore.orcid2.v3.client.MCRORCIDSectionImpl;
import org.orcid.jaxb.model.v3.release.record.summary.Works;

public class DozBibORCIDUtils {

protected static final Logger LOGGER = LogManager.getLogger(DozBibORCIDUtils.class);

/**
* Get the total number of publications for all orcids connected with UBO.
*
* @return the total number of publications
* */
public static int getNumWorks() {
MCRORCIDUser orcidUser = MCRORCIDSessionUtils.getCurrentUser();
Set<String> orcidIdentifiers = orcidUser.getORCIDs();

AtomicInteger numWorks = new AtomicInteger(0);

orcidIdentifiers.forEach(orcid -> {
MCRORCIDCredential credential = orcidUser.getCredentialByORCID(orcid);
if (credential != null) {
try {
MCRORCIDUserClient client = MCRORCIDClientHelper.getClientFactory()
.createUserClient(orcid, credential);
Works works = client.fetch(MCRORCIDSectionImpl.WORKS, Works.class);
numWorks.addAndGet(works.getWorkGroup().size());
} catch (MCRORCIDRequestException e) {
LOGGER.error(e.getMessage(), e);
}
}
});

return numWorks.get();
}

/**
* Returns the number of publications for the given orcid. The orcid must be connected with UBO otherwise 0
* will be returned.
*
* @param orcid the orcid for which the number of publications will be retrieved
*
* @return the number of publications for the given orcid
* */
public static int getNumWorks(String orcid) {
MCRORCIDUser orcidUser = MCRORCIDSessionUtils.getCurrentUser();
MCRORCIDCredential credentialByORCID = orcidUser.getCredentialByORCID(orcid);

MCRORCIDUserClient client = MCRORCIDClientHelper.getClientFactory().createUserClient(orcid, credentialByORCID);
AtomicInteger numWorks = new AtomicInteger(0);

try {
Works works = client.fetch(MCRORCIDSectionImpl.WORKS, Works.class);
numWorks.addAndGet(works.getWorkGroup().size());
} catch (MCRORCIDRequestException e) {
LOGGER.error(e.getMessage(), e);
}

return numWorks.get();
}

public static String getFirstOrcidByCurrentUser() {
MCRORCIDUser orcidUser = MCRORCIDSessionUtils.getCurrentUser();
return orcidUser.getORCIDs().isEmpty() ? "" : orcidUser.getORCIDs().iterator().next();
}

public static boolean weAreTrustedParty() {
if (MCRXMLFunctions.isCurrentUserGuestUser()) {
return false;
}

MCRORCIDUser orcidUser = MCRORCIDSessionUtils.getCurrentUser();
Map<String, MCRORCIDCredential> credentials = orcidUser.getCredentials();

return !credentials.isEmpty();
}

public static boolean isConnected(String orcid) {
return MCRORCIDSessionUtils.getCurrentUser().getCredentialByORCID(orcid) != null;
}
}
Loading

0 comments on commit f50ef50

Please sign in to comment.