Skip to content

Commit

Permalink
Merge pull request #4236 from inception-project/bugfix/4235-Direct-ac…
Browse files Browse the repository at this point in the history
…cess-by-URL-to-sidebar-curation-mode-sometimes-does-not-work

#4235 - Direct access-by-URL to sidebar curation mode sometimes does not work
  • Loading branch information
reckart authored Oct 9, 2023
2 parents 483d09e + d823fbf commit c6aa0a5
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.context.ApplicationEvent;

import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
import de.tudarmstadt.ukp.clarin.webanno.support.wicket.event.HybridApplicationUIEvent;

/**
* Fire BeforeDocumentOpenedEvent to give listeners a chance to look at or even modify the CAS
Expand All @@ -29,6 +30,7 @@
*/
public class BeforeDocumentOpenedEvent
extends ApplicationEvent
implements HybridApplicationUIEvent
{
private static final long serialVersionUID = -4644605041626140906L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.event.Broadcast;
import org.apache.wicket.feedback.IFeedback;
import org.apache.wicket.request.RequestHandlerExecutor.ReplaceHandlerException;
import org.apache.wicket.request.cycle.RequestCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -66,12 +67,18 @@ public void routeEvent(HybridApplicationUIEvent aEvent)
try {
page.send(page, Broadcast.BREADTH, aEvent);
}
catch (ReplaceHandlerException e) {
throw e;
}
catch (Throwable e) {
log.error("Exception while processing UI-routed event", e);
page.error("Exception while processing UI-routed event: " + e.getMessage());
handler.get().addChildren(page, IFeedback.class);
}
}
catch (ReplaceHandlerException e) {
throw e;
}
catch (Throwable e) {
log.error("Unable to route event to UI", e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Licensed to the Technische Universität Darmstadt under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Technische Universität Darmstadt
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.tudarmstadt.ukp.inception.ui.curation.sidebar;

import static de.tudarmstadt.ukp.clarin.webanno.support.WebAnnoConst.CURATION_USER;
import static de.tudarmstadt.ukp.clarin.webanno.ui.core.page.ProjectPageBase.setProjectPageParameter;
import static java.util.Arrays.asList;

import java.lang.invoke.MethodHandles;

import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage;
import de.tudarmstadt.ukp.inception.annotation.events.BeforeDocumentOpenedEvent;

public class CurationSidebarBehavior
extends Behavior
{
private static final long serialVersionUID = -6224298395673360592L;

private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private static final String STAY = "stay";
private static final String OFF = "off";
private static final String ON = "on";

private static final String PARAM_CURATION_SESSION = "curationSession";
private static final String PARAM_CURATION_TARGET_OWN = "curationTargetOwn";

private @SpringBean CurationSidebarService curationSidebarService;
private @SpringBean UserDao userService;

@Override
public void onConfigure(Component aComponent)
{
super.onConfigure(aComponent);

var page = aComponent.getPage();
if (!(page instanceof AnnotationPage)) {
return;
}

var annotationPage = (AnnotationPage) page;

if (annotationPage.getModelObject().getDocument() == null) {
return;
}

handleCurationSessionPageParameters(annotationPage);

handleWrongAnnotatorUserInState(annotationPage);
}

@Override
public void onEvent(Component aComponent, IEvent<?> aEvent)
{
if (aEvent.getPayload() instanceof BeforeDocumentOpenedEvent) {
var event = (BeforeDocumentOpenedEvent) aEvent.getPayload();
var page = event.getRequestTarget().getPage();

if (!(page instanceof AnnotationPage)) {
return;
}

var annotationPage = (AnnotationPage) page;

handleCurationSessionPageParameters(annotationPage);

handleWrongAnnotatorUserInState(annotationPage);
}
}

private void handleWrongAnnotatorUserInState(AnnotationPage aPage)
{
if (isViewingPotentialCurationTarget(aPage) && isSessionActive(aPage)) {
var sessionOwner = userService.getCurrentUsername();
var state = aPage.getModelObject();

// If curation is possible and the curation target user is different from the user set
// in the annotation state, then we need to update the state and reload.
var curationTarget = curationSidebarService.getCurationTargetUser(sessionOwner,
state.getProject().getId());
if (!state.getUser().equals(curationTarget)) {
LOG.trace("Wrong user in state, setting and reloading");
state.setUser(curationTarget);
aPage.actionLoadDocument(null);
RequestCycle.get().setResponsePage(aPage);
}
}
}

private void handleCurationSessionPageParameters(AnnotationPage aPage)
{
var params = aPage.getPageParameters();

var curationSessionParameterValue = params.get(PARAM_CURATION_SESSION);
var curationTargetOwnParameterValue = params.get(PARAM_CURATION_TARGET_OWN);
var project = aPage.getModelObject().getProject();
var sessionOwner = userService.getCurrentUsername();

switch (curationSessionParameterValue.toString(STAY)) {
case ON:
LOG.trace("Checking if to start curation session");
// Start a new session or switch to new curation target
if (!isSessionActive(aPage) || !curationTargetOwnParameterValue.isEmpty()) {
curationSidebarService.startSession(sessionOwner, project,
curationTargetOwnParameterValue.toBoolean(false));
}
break;
case OFF:
LOG.trace("Checking if to stop curation session");
if (isSessionActive(aPage)) {
curationSidebarService.closeSession(sessionOwner, project.getId());
}
break;
default:
// Ignore
}

if (!curationSessionParameterValue.isEmpty()) {
LOG.trace("Reloading page without session parameters");
params.remove(PARAM_CURATION_TARGET_OWN);
params.remove(PARAM_CURATION_SESSION);
setProjectPageParameter(params, project);
params.set(AnnotationPage.PAGE_PARAM_DOCUMENT,
aPage.getModelObject().getDocument().getId());
throw new RestartResponseException(aPage.getClass(), params);
}
}

private boolean isViewingPotentialCurationTarget(AnnotationPage aPage)
{
// Curation sidebar is not allowed when viewing another users annotations
var sessionOwner = userService.getCurrentUsername();
var state = aPage.getModelObject();
return asList(CURATION_USER, sessionOwner).contains(state.getUser().getUsername());
}

private boolean isSessionActive(AnnotationPage aPage)
{
var sessionOwner = userService.getCurrentUsername();
var project = aPage.getModelObject().getProject();
if (project != null
&& curationSidebarService.existsSession(sessionOwner, project.getId())) {
return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ public AnnotationSidebar_ImplBase create(String aId, IModel<AnnotatorState> aMod
AnnotationActionHandler aActionHandler, CasProvider aCasProvider,
AnnotationPage aAnnotationPage)
{
return new CurationSidebar(aId, aModel, aActionHandler, aCasProvider, aAnnotationPage);
var sidebar = new CurationSidebar(aId, aModel, aActionHandler, aCasProvider,
aAnnotationPage);
if (aAnnotationPage.getBehaviors(CurationSidebarBehavior.class).isEmpty()) {
aAnnotationPage.add(new CurationSidebarBehavior());
}

return sidebar;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,48 +17,27 @@
*/
package de.tudarmstadt.ukp.inception.ui.curation.sidebar;

import static de.tudarmstadt.ukp.clarin.webanno.support.WebAnnoConst.CURATION_USER;
import static de.tudarmstadt.ukp.clarin.webanno.ui.core.page.ProjectPageBase.setProjectPageParameter;
import static java.util.Arrays.asList;

import java.lang.invoke.MethodHandles;
import java.util.Set;

import org.apache.wicket.ClassAttributeModifier;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;
import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType;
import de.tudarmstadt.ukp.clarin.webanno.api.ProjectService;
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage;
import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState;

public class CurationSidebarIcon
extends Panel
{
private static final long serialVersionUID = -1870047500327624860L;

private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private static final String STAY = "stay";
private static final String OFF = "off";
private static final String ON = "on";

private static final String PARAM_CURATION_SESSION = "curationSession";
private static final String PARAM_CURATION_TARGET_OWN = "curationTargetOwn";

private @SpringBean CurationSidebarService curationSidebarService;
private @SpringBean UserDao userService;
private @SpringBean ProjectService projectService;

public CurationSidebarIcon(String aId, IModel<AnnotatorState> aState)
{
Expand Down Expand Up @@ -86,63 +65,6 @@ protected Set<String> update(Set<String> aClasses)
}));
}

@Override
protected void onInitialize()
{
super.onInitialize();

handleCurationSessionPageParameters();

if (isViewingPotentialCurationTarget() && isSessionActive()) {
String sessionOwner = userService.getCurrentUsername();
AnnotatorState state = getModelObject();

// If curation is possible and the curation target user is different from the user set
// in the annotation state, then we need to update the state and reload.
User curationTarget = curationSidebarService.getCurationTargetUser(sessionOwner,
state.getProject().getId());
if (!state.getUser().equals(curationTarget)) {
state.setUser(curationTarget);
findParent(AnnotationPage.class).actionLoadDocument(null);
throw new RestartResponseException(getPage());
}
}
}

private void handleCurationSessionPageParameters()
{
var params = getPage().getPageParameters();
var curationSessionParameterValue = params.get(PARAM_CURATION_SESSION);
var curationTargetOwnParameterValue = params.get(PARAM_CURATION_TARGET_OWN);
var project = getModelObject().getProject();
String sessionOwner = userService.getCurrentUsername();

switch (curationSessionParameterValue.toString(STAY)) {
case ON:
// Start a new session or switch to new curation target
if (!isSessionActive() || !curationTargetOwnParameterValue.isEmpty()) {
curationSidebarService.startSession(sessionOwner, project,
curationTargetOwnParameterValue.toBoolean(false));
}
break;
case OFF:
if (isSessionActive()) {
curationSidebarService.closeSession(sessionOwner, project.getId());
}
break;
default:
// Ignore
}

if (!curationSessionParameterValue.isEmpty()) {
params.remove(PARAM_CURATION_TARGET_OWN);
params.remove(PARAM_CURATION_SESSION);
setProjectPageParameter(params, project);
params.set(AnnotationPage.PAGE_PARAM_DOCUMENT, getModelObject().getDocument().getId());
throw new RestartResponseException(getPage().getClass(), params);
}
}

@SuppressWarnings("unchecked")
public IModel<AnnotatorState> getModel()
{
Expand All @@ -154,6 +76,15 @@ public AnnotatorState getModelObject()
return (AnnotatorState) getDefaultModelObject();
}

private IconType getStateIcon()
{
if (isSessionActive()) {
return FontAwesome5IconType.play_circle_s;
}

return FontAwesome5IconType.stop_circle_s;
}

private boolean isSessionActive()
{
var project = getModelObject().getProject();
Expand All @@ -164,21 +95,4 @@ private boolean isSessionActive()

return false;
}

private boolean isViewingPotentialCurationTarget()
{
// Curation sidebar is not allowed when viewing another users annotations
String currentUsername = userService.getCurrentUsername();
AnnotatorState state = getModelObject();
return asList(CURATION_USER, currentUsername).contains(state.getUser().getUsername());
}

private IconType getStateIcon()
{
if (isSessionActive()) {
return FontAwesome5IconType.play_circle_s;
}

return FontAwesome5IconType.stop_circle_s;
}
}

0 comments on commit c6aa0a5

Please sign in to comment.