Skip to content

Commit

Permalink
continue work on it
Browse files Browse the repository at this point in the history
  • Loading branch information
astappiev committed Oct 5, 2023
1 parent 4e03893 commit 49a3daf
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 104 deletions.
26 changes: 13 additions & 13 deletions src/main/java/de/l3s/learnweb/resource/Annotation.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ public class Annotation implements Serializable {
@Serial
private static final long serialVersionUID = 6321296603254649454L;

private int annotationId;
private int resourceId;
private int userId;
private String action;
private String selection;
private String annotation;
private Instant timestamp;
private Instant createdAt;

// cached values
private transient User user;
Expand All @@ -25,13 +26,12 @@ public class Annotation implements Serializable {
public Annotation() {
}

public Annotation(int resourceId, int userId, String action, String selection, String annotation) {
this.resourceId = resourceId;
this.userId = userId;
this.action = action;
this.selection = selection;
this.annotation = annotation;
this.timestamp = Instant.now();
public int getAnnotationId() {
return annotationId;
}

public void setAnnotationId(final int annotationId) {
this.annotationId = annotationId;
}

public int getResourceId() {
Expand Down Expand Up @@ -74,17 +74,17 @@ public void setAction(String action) {
this.action = action;
}

public Instant getTimestamp() {
return timestamp;
public Instant getCreatedAt() {
return createdAt;
}

public void setTimestamp(Instant timestamp) {
this.timestamp = timestamp;
public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}

public User getUser() {
if (null == user) {
user = Learnweb.dao().getUserDao().findByIdOrElseThrow(getUserId());
user = Learnweb.dao().getUserDao().findByIdOrElseThrow(userId);
}
return user;
}
Expand Down
21 changes: 13 additions & 8 deletions src/main/java/de/l3s/learnweb/resource/AnnotationDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,28 @@

import de.l3s.util.SqlHelper;

@RegisterRowMapper(AnnotationDao.AnnotationMapper.class)
public interface AnnotationDao extends SqlObject, Serializable {

@RegisterRowMapper(AnnotationMapper.class)
@SqlQuery("SELECT a.* FROM lw_transcript_log a JOIN lw_resource USING(resource_id) WHERE user_id IN(<userIds>) and deleted = 0 ORDER BY user_id, created_at DESC")
List<Annotation> findLogsByUserIds(@BindList("userIds") Collection<Integer> userIds);

@SqlQuery("SELECT a.* FROM lw_resource_annotation a WHERE resource_id = ?")
List<Annotation> findAllByResourceId(int resourceId);

default void save(Annotation annotation) {
if (annotation.getTimestamp() == null) {
annotation.setTimestamp(Instant.now());
if (annotation.getCreatedAt() == null) {
annotation.setCreatedAt(Instant.now());
}

LinkedHashMap<String, Object> params = new LinkedHashMap<>();
params.put("annotation_id", annotation.getAnnotationId());
params.put("resource_id", annotation.getResourceId());
params.put("user_id", annotation.getUserId());
params.put("action", annotation.getAction());
params.put("action", SqlHelper.toNullable(annotation.getAction()));
params.put("selection", SqlHelper.toNullable(annotation.getSelection()));
params.put("annotation", SqlHelper.toNullable(annotation.getAnnotation()));
params.put("created_at", annotation.getTimestamp());
params.put("created_at", annotation.getCreatedAt());

SqlHelper.handleSave(getHandle(), "lw_resource_annotation", params).execute();
}
Expand All @@ -43,12 +47,13 @@ class AnnotationMapper implements RowMapper<Annotation> {
@Override
public Annotation map(final ResultSet rs, final StatementContext ctx) throws SQLException {
Annotation log = new Annotation();
log.setAnnotationId(rs.getInt("annotation_id"));
log.setResourceId(rs.getInt("resource_id"));
log.setUserId(rs.getInt("user_id"));
log.setAction(rs.getString("action"));
log.setSelection(rs.getString("words_selected"));
log.setAnnotation(rs.getString("user_annotation"));
log.setTimestamp(rs.getTimestamp("created_at").toInstant());
log.setSelection(rs.getString("selection"));
log.setAnnotation(rs.getString("annotation"));
log.setCreatedAt(rs.getTimestamp("created_at").toInstant());
return log;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/de/l3s/learnweb/resource/Resource.java
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,9 @@ public void setTypeFromFormat(String format) {
return;
}

if (format.equals("text/html") || format.equals("application/xhtml+xml")) {
if (StringUtils.equalsAny(format, "text/html", "application/xhtml+xml")) {
this.type = ResourceType.website;
} else if (format.startsWith("text/") || StringUtils.equalsAny(format, "application/json", "application/xml")) {
} else if (format.startsWith("text/") || StringUtils.equalsAny(format, "application/json", "application/xml", "application/sql")) {
this.type = ResourceType.text;
} else if (format.startsWith("image/")) {
this.type = ResourceType.image;
Expand Down
47 changes: 42 additions & 5 deletions src/main/java/de/l3s/learnweb/resource/ResourceAnnotationBean.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package de.l3s.learnweb.resource;

import java.io.IOException;
import java.io.Serial;
import java.io.Serializable;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

Expand All @@ -12,10 +15,15 @@
import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.omnifaces.util.Beans;
import org.omnifaces.util.Faces;
import org.omnifaces.util.Messages;
import org.primefaces.PrimeFaces;

import com.google.gson.Gson;

import de.l3s.learnweb.beans.ApplicationBean;
import de.l3s.learnweb.beans.BeanAssert;
import de.l3s.util.NlpHelper;
Expand All @@ -25,15 +33,42 @@
public class ResourceAnnotationBean extends ApplicationBean implements Serializable {
@Serial
private static final long serialVersionUID = -6100755972011969429L;
private static final Logger log = LogManager.getLogger(ResourceAnnotationBean.class);

private static final Pattern SPACES = Pattern.compile("\\s+");
private Resource resource;

@Inject
private AnnotationDao annotationDao;

@PostConstruct
public void onLoad() {
BeanAssert.authorized(isLoggedIn());

resource = Beans.getInstance(ResourceDetailBean.class).getResource();
}

public void convert() {
if (resource.getType() == ResourceType.text) {
if (resource.getMainFile() != null) {
try {
String lines = Files.readString(resource.getMainFile().getActualFile().toPath());
lines = lines.replace("\n", "<br/>");
resource.setTranscript(lines);
resource.save();
return;
} catch (IOException e) {
log.error("Error reading file while extracting transcript", e);
}
}
}

addGrowl(FacesMessage.SEVERITY_ERROR, "Unfortunately, we could not extract the text from the file.");
}

public String getAnnotationsAsJson() {
List<Annotation> annotations = annotationDao.findAllByResourceId(resource.getId());
return new Gson().toJson(annotations);
}

/**
Expand All @@ -46,8 +81,6 @@ public void commandSaveAnnotation(final Resource resource) {
resource.setTranscript(annotatedText);
resource.save();

annotationDao.save(new Annotation(resource.getId(), getUser().getId(), "save transcript", null, null));

getUser().clearCaches();
addGrowl(FacesMessage.SEVERITY_INFO, "Changes_saved");
}
Expand All @@ -63,8 +96,6 @@ public void commandCommitAnnotation(final Resource resource) {
resource.setReadOnlyTranscript(true);
resource.save();

annotationDao.save(new Annotation(resource.getId(), getUser().getId(), "submit transcript", null, null));

getUser().clearCaches();
addGrowl(FacesMessage.SEVERITY_INFO, "Annotation Submitted");
}
Expand All @@ -76,7 +107,13 @@ public void commandLogAnnotation(final Resource resource) {
BeanAssert.authorized(resource.canAnnotateResource(getUser()));

Map<String, String> params = Faces.getRequestParameterMap();
annotationDao.save(new Annotation(resource.getId(), getUser().getId(), params.get("action"), params.get("selection"), params.get("annotation")));
Annotation annotation = new Annotation();
annotation.setResourceId(resource.getId());
annotation.setUserId(getUser().getId());
annotation.setAction(params.get("action"));
annotation.setSelection(params.get("selection"));
annotation.setAnnotation(params.get("annotation"));
annotationDao.save(annotation);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/de/l3s/learnweb/resource/ResourceType.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public enum ResourceType {
audio,
pdf,
website,
spreadsheet,
presentation,
document,
spreadsheet, // onlyoffice
presentation, // onlyoffice
document, // onlyoffice
file, // applications, archives, etc

// learnweb types
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
CREATE TABLE IF NOT EXISTS `lw_resource_annotation` (
`annotation_id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`resource_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`action` CHAR(25) NOT NULL,
`selection` LONGTEXT NOT NULL,
`annotation` MEDIUMTEXT NOT NULL,
`annotation` MEDIUMTEXT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns:h="jakarta.faces.html"
xmlns:f="jakarta.faces.core"
xmlns:ui="jakarta.faces.facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:c="jakarta.tags.core"
xmlns:p="http://primefaces.org/ui">

<!--@elvariable id="res" type="de.l3s.learnweb.resource.survey.SurveyResource"-->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,73 +1,80 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:h="jakarta.faces.html"
xmlns:f="jakarta.faces.core"
xmlns:c="jakarta.tags.core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
xmlns:faces="jakarta.faces"
xmlns:ui="jakarta.faces.facelets">

<!--@elvariable id="res" type="de.l3s.learnweb.resource.Resource"-->

<h:outputStylesheet name="bundle/pickr.min.css"/>
<h:outputScript name="bundle/pickr.min.js" target="body"/>
<h:outputScript name="bundle/jquery.contextMenu.min.js" target="body"/>
<h:outputScript name="learnweb/js/lib/annotator.js" target="body"/>

<h:form styleClass="d-none">
<p:remoteCommand name="commandSaveLog" actionListener="${resourceAnnotationBean.commandLogAnnotation(resourceDetailBean.resource)}" immediate="true" process="@this" update="@none"/>
<p:remoteCommand name="commandSaveResource" actionListener="${resourceAnnotationBean.commandSaveAnnotation(resourceDetailBean.resource)}" immediate="true" process="@this"/>
<p:remoteCommand name="commandGetDefinition" actionListener="${resourceAnnotationBean.commandGetDefinition()}" immediate="true" process="@this" oncomplete="annotator.saveDefinition(xhr,status,args);" async="false"/>
</h:form>

<h:outputStylesheet name="bundle/pickr.min.css"/>
<h:outputScript name="bundle/pickr.min.js" target="body"/>
<h:outputScript name="bundle/jquery.contextMenu.min.js" target="body"/>
<h:outputScript name="learnweb/js/lib/annotator.js" target="body"/>
<h:form styleClass="text_res_toolbar mx-3 my-1">
<p:commandButton styleClass="ui-button-warning" value="#{msg.convert_to_edit}"
actionListener="#{resourceAnnotationBean.convert()}" update="@form :text_res_content" rendered="#{empty res.transcript}"/>
<p:tooltip for="@previous" value="#{msg.convert_to_edit_tooltip}"/>

<p:tabView styleClass="res-view-tabs res-embedded-tabs">
<p:tab title="Normal">
<iframe src="#{res.downloadUrl}" title="#{res.title}" class="bg-body p-1"></iframe>
</p:tab>
<p:tab title="Annotated">
<h:form>
<div class="d-block position-absolute top-0 end-0 mx-3 my-1">
<p:commandButton styleClass="me-2" value="#{msg.save}" onclick="annotator.saveAnnotatedText();"/>
<p:tooltip for="@previous" value="#{msg.save_tooltip}" position="left"/>
</div>
</h:form>
<p:commandButton styleClass="me-2" value="#{msg.save}" onclick="annotator.saveAnnotatedText();" rendered="#{false}"/>
<p:tooltip for="@previous" value="#{msg.save_tooltip}" position="left"/>
</h:form>

<div faces:id="text_res_content" class="p-3 h-100">
<ui:fragment rendered="#{empty res.transcript}">
<iframe id="embedded_text" src="#{res.downloadUrl}" title="#{res.title}" class="bg-body-secondary"></iframe>
</ui:fragment>

<ui:fragment rendered="#{not empty res.transcript}">
<div id="annotated_text" class="w-100 bg-body" style="padding: 12px;">
<pre style="height: 100%">
<h:outputText value="testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" escape="false"/>
</pre>
<h:outputText value="#{res.transcript}" escape="false"/>
</div>
</p:tab>
</p:tabView>

<p:dialog widgetVar="updateNote" header="#{msg.userAnnotation}"
modal="true" resizable="false" draggable="false" responsive="true" closeOnEscape="true" dynamic="true">
<h:form id="update_note_form" prependId="false" styleClass="d-flex flex-column">
<p:outputLabel for="@next" value="#{msg.justify_selection}:"/>
<p:inputText/>
<p:dialog widgetVar="updateNote" header="#{msg.userAnnotation}" modal="true" dynamic="true"
closeOnEscape="true" resizable="false" draggable="false" closable="false">
<h:form id="update_note_form" prependId="false">
<div class="field">
<p:outputLabel for="@next" value="#{msg.justify_selection}:"/>
<p:inputText/>
</div>

<div class="d-flex flex-row-reverse mt-2">
<p:commandButton value="#{msg['save']}" onclick="annotator.saveAnnotation(); return false;"/>
<p:commandButton styleClass="secondary-btn" value="#{msg.cancel}" onclick="annotator.cancelAnnotation(); return false;"/>
</div>
</h:form>
</p:dialog>
<div class="d-flex flex-row-reverse">
<p:commandButton value="#{msg.save}" styleClass="ms-1" onclick="annotator.saveAnnotation(); return false;"/>
<p:commandButton styleClass="ui-button-secondary" value="#{msg.cancel}" onclick="annotator.cancelAnnotation(); return false;"/>
</div>
</h:form>
</p:dialog>

<h:outputScript target="body">
const annotator = new Annotator('#annotated_text', {
readOnly: false,
lastNoteId: 0,
editNoteFormSelector: '#update_note_form',
noteContextMenu: [
{ action: 'add-annotation', icon: 'fa-plus', name: '#{msg.add_annotation}' },
{ action: 'edit-annotation', icon: 'fa-pencil-alt', name: '#{msg.edit_annotation}' },
{ action: 'delete-annotation', icon: 'fa-minus', name: '#{msg.delete_annotation}' },
{ action: 'add-wordnet-definition', icon: 'fa-language', name: '#{msg.add_wordnet_definition}' },
{ action: 'delete-selection', icon: 'fa-trash', name: '#{msg.delete_selection}' },
{ action: 'colorpicker', icon: 'fa-folder', name: '#{msg.color}' }
],
locale: {
deleteSelection: '#{msg.delete_selection}'
}
});
</h:outputScript>
<h:outputScript target="body">
const annotator = new Annotator('#annotated_text', {
readOnly: false,
lastNoteId: 0,
editNoteFormSelector: '#update_note_form',
noteContextMenu: [
{ action: 'add-annotation', icon: 'fa-plus', name: '#{msg.add_annotation}' },
{ action: 'edit-annotation', icon: 'fa-pencil-alt', name: '#{msg.edit_annotation}' },
{ action: 'delete-annotation', icon: 'fa-minus', name: '#{msg.delete_annotation}' },
{ action: 'add-wordnet-definition', icon: 'fa-language', name: '#{msg.add_wordnet_definition}' },
{ action: 'delete-selection', icon: 'fa-trash', name: '#{msg.delete_selection}' },
{ action: 'colorpicker', icon: 'fa-folder', name: '#{msg.color}' }
],
annotations: [
#{resourceAnnotationBean.getAnnotationsAsJson()}
],
locale: {
deleteSelection: '#{msg.delete_selection}'
}
});
</h:outputScript>
</ui:fragment>
</div>

</ui:composition>
Loading

0 comments on commit 49a3daf

Please sign in to comment.