Skip to content

Commit

Permalink
SAK-43155 Assignments Work Log Feature (sakaiproject#9888)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgecanovas authored Oct 5, 2021
1 parent defd008 commit 13b5e70
Show file tree
Hide file tree
Showing 47 changed files with 2,036 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,6 @@ public enum SubmissionStatus {
*/
public static final String SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM = "assignment.allowLinkToExistingGBItem";
public static final boolean SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM_DFLT = true;

public static final String ASSIGNMENT_INPUT_ADD_SUBMISSION_TIME_SPENT = "value_ASSIGNMENT_INPUT_ADD_SUBMISSION_TIME_SPENT";
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.sakaiproject.assignment.api.model.AssignmentSubmission;
import org.sakaiproject.assignment.api.model.AssignmentSubmissionSubmitter;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.assignment.api.model.TimeSheetEntry;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.Reference;
Expand Down Expand Up @@ -758,6 +759,8 @@ public String getDeepLinkWithPermissions(String context, String assignmentId, bo
*/
public void postReviewableSubmissionAttachments(AssignmentSubmission submission);

boolean isTimeSheetEnabled(String siteId);

/**
* This will return the internationalized title of the tool.
* This is used when creating a new gradebook item.
Expand Down Expand Up @@ -820,6 +823,16 @@ public String getDeepLinkWithPermissions(String context, String assignmentId, bo
*/
public List<MultiGroupRecord> checkSubmissionForUsersInMultipleGroups(String siteId, Group submissionGroup, Collection<Group> asnGroups);

public boolean isValidTimesheetTime(String timeSheet);

public TimeSheetEntry getTimeSheetEntry(Long timeSheetId) throws PermissionException;

public void newTimeSheetEntry(AssignmentSubmissionSubmitter submissionSubmitter, TimeSheetEntry timeSheet) throws PermissionException;

public void deleteTimeSheetEntry(Long timeSheetId) throws PermissionException;

public String getTimeSpent(AssignmentSubmission submission);

/**
* Returns true if the content review implementation successfully created the assignment
* @param a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ public final class AssignmentServiceConstants {

public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String SAK_PROP_ASSIGNMENT_IMPORT_SUBMISSIONS = "assignment.merge.import.submissions";
public static final String SAK_PROP_ASSIGNMENT_TIMESHEET_SITES_ALLOWED = "assignment.timesheet.sites.allowed";
public static final String SAK_PROP_ASSIGNMENT_TIMESHEET_TIME_PATTERN_DEFAULT = "^([0-9]?[0-9]h|[0-9]?[0-9]H)$|([0-9]?[0-9]m|[0-9]?[0-9]M)$|(([0-9]?[0-9]h|[0-9]?[0-9]H)[ ]?([0-9]?[0-9]m|[0-9]?[0-9]M))$";

private AssignmentServiceConstants() {
throw new RuntimeException(this.getClass().getCanonicalName() + " is not to be instantiated");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ public class Assignment {
@Column(name = "CONTENT_REVIEW")
private Boolean contentReview = Boolean.FALSE;

@Column(name = "ESTIMATE_REQUIRED", length = 1, nullable = false)
private Boolean estimateRequired = Boolean.FALSE;

@Column(name = "ESTIMATE", length = 255)
private String estimate;

@Column(name = "CONTENT_ID")
private Integer contentId = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;

import com.fasterxml.jackson.annotation.JsonManagedReference;

/**
* Defines a relation between a submission and the submission's submitters.
* <br/> - A submitter can have its own grade separate from the grade of the submission,
Expand Down Expand Up @@ -83,4 +92,13 @@ public class AssignmentSubmissionSubmitter {
@Lob
@Column(name = "FEEDBACK", length = 65535)
private String feedback;

@Column(name = "TIME_SPENT", length = 255)
private String timeSpent;

@OneToMany(mappedBy = "assignmentSubmissionSubmitter", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy("startTime ASC")
@JsonManagedReference
private Set<TimeSheetEntry> timeSheetEntries = new HashSet<>();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2003-2017 The Apereo Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/ecl2
*
* 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 org.sakaiproject.assignment.api.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.annotations.Type;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.time.Instant;

/**
* Defines a relation between a submission and the submission's submitters.
* <br/> - A submitter can have its own grade separate from the grade of the submission,
* useful in providing user with different grades in group submissions.
* <br/> - A submitter can have its own feedback separate from the feedback of the submission,
* useful when different feedback is needed in group submissions
* <p>
* <b>Constraints</b>
* <br/>- submission and submitter are unique,
* meaning a user can't be a submitter more than once on a submission.
* Notice that equals and hashcode also reflect this relationship.
*/
@Entity
@Table(name = "ASN_SUBMITTER_TIMESHEET")
@Data
@NoArgsConstructor
@ToString(exclude = {"submitter"})
@EqualsAndHashCode(of = "id")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TimeSheetEntry {

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "assignment_submission_submitter_timesheet_sequence")
@SequenceGenerator(name = "assignment_submission_submitter_timesheet_sequence", sequenceName = "ASN_SUBMITTER_TIMESHEET_S")
private Long id;


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SUBMISSION_SUBMITTER_ID", nullable = false)
@JsonBackReference
private AssignmentSubmissionSubmitter assignmentSubmissionSubmitter;

@Type(type = "org.hibernate.type.InstantType")
@Column(name = "START_TIME", nullable = false)
private Instant startTime;

@Column(name = "DURATION", length = 255)
private String duration;

@Column(name = "COMMENT", length = 4096)
private String comment;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.sakaiproject.assignment.api.model.Assignment;
import org.sakaiproject.assignment.api.model.AssignmentSubmission;
import org.sakaiproject.assignment.api.model.AssignmentSubmissionSubmitter;
import org.sakaiproject.assignment.api.model.TimeSheetEntry;
import org.sakaiproject.serialization.SerializableRepository;

/**
Expand Down Expand Up @@ -56,6 +57,8 @@ public interface AssignmentRepository extends SerializableRepository<Assignment,

boolean existsSubmission(String submissionId);

boolean existsSubmissionSubmitter(Long submissionSubmitterId);

AssignmentSubmission newSubmission(String assignmentId,
Optional<String> groupId,
Optional<Set<AssignmentSubmissionSubmitter>> submitters,
Expand Down Expand Up @@ -91,4 +94,13 @@ AssignmentSubmission newSubmission(String assignmentId,
String findAssignmentIdForGradebookLink(String context, String linkId);

Collection<String> findGroupsForAssignmentById(String assignmentId);

void newTimeSheetEntry(AssignmentSubmissionSubmitter submissionSubmitter, TimeSheetEntry timeSheetEntry);

boolean existsTimeSheetEntry(Long timeSheetId);

TimeSheetEntry findTimeSheetEntry(Long timeSheetId);

void deleteTimeSheetEntry(Long timeSheetId);

}
51 changes: 50 additions & 1 deletion assignment/api/src/resources/assignment.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,6 @@ email.reminder.andhours=and {0} hours.
email.reminder.hours={0} hours.
email.reminder.days={0} days


defaultGrade.notGrade=a Grade
defaultGrade.notSubmit=Not Submit

Expand All @@ -1181,3 +1180,53 @@ stuviewsubm.start.recording = Start Recording
stuviewsubm.stop.recording = Stop Recording
stuviewsubm.submitted.video = The video has been submitted for the assignment, if you record a new video this recording will be lost.
instrviewsubm.video = The student submitted a video, you can watch the video before grading the student.

#Timesheet
gen.estimate=Estimate
gen.estimatedselfempl=Estimated self-employed work
gen.isestimate=Include estimated time to complete the assigment
gen.reqestimate=Mandatory
gen.timestimate=Indicate the estimated time
timeempty=Please specify the estimated duration of the assigment.
timeformat=The format of the estimated time of the task is not correct. This must be XXh XXm.
gen.sorbytime=Sort by time estimate
gen.timesheet.instructor=Avg. submission time / Estimated
gen.timesheet.student=Time spent / Estimated
gen.spenttime=Time spent
gen.sorbyspenttime=Sort by time spent
gen.totaltimespent=Total time spent on the task
gen.totaltimespentconfirm=Total time spent on the task:
gen.useimputedtime=Use imputted time in
gen.notimeimputted=There's no imputted time in
gen.notimeimputted.enter=, record the time spent.
gen.noestimate=Without record

ts.tab.assignment=Assignment
ts.tab.timesheet=Time Sheet
ts.btn.add.record=Add record
ts.btn.del.record=Remove record
ts.msg.no.timesheet.record=There are no timesheet records.
ts.title.timesheet=Timesheet
ts.table.tab.date=Date
ts.table.tab.comment=Comment
ts.table.tab.time=Time
ts.table.tab.del=Delete
ts.modal.new=New record
ts.modal.msg.err=Format error in time spent field
ts.modal.field.date=Date:
ts.modal.field.comment=Comment:
ts.modal.field.tspent=Time spent:
ts.modal.field.tspent.format=XXh YYm
ts.modal.btn.save=Save

ts.add.err.userId=You need to be logged in to add time sheet entry
ts.add.err.assignmentId=You need to supply the assignmentId and ref
ts.add.err.startTime=You must set a start time
ts.add.err.comment=You need to fill the comment field
ts.add.err.duration=The format of the estimated time of the task is not correct. This must be XXh XXm.
ts.add.err.permission=You can't modify this sumbitter
ts.add.err.submitter=You submitter does not exist.
ts.rem.err.userId=You need to be logged in to add time sheet entry
ts.rem.err.empty=Selected time sheet must be provided
ts.rem.err.submitterId=You need to supply the submissionId and ref
ts.rem.err.permission=You can't modify this sumbitter
52 changes: 51 additions & 1 deletion assignment/api/src/resources/assignment_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1156,4 +1156,54 @@ email.reminder.hours={0} horas.
email.reminder.days={0} d\u00edas

defaultGrade.notGrade=Sin calificar
defaultGrade.notSubmit=Sin env\u00EDo
defaultGrade.notSubmit=Sin env\u00EDo

#Timesheet
gen.estimate=Estimado
gen.estimatedselfempl=Trabajo aut\u00F3nomo estimado
gen.isestimate=Incluir tiempo aut\u00F3nomo del alumno en realizar la tarea
gen.reqestimate=Obligatoriedad
gen.timestimate=Indique el tiempo estimado
timeempty=Por favor, especifique la duraci\u00f3n estimada de la tarea.
timeformat=El formato del tiempo estimado de la tarea no es el correcto. Este debe de ser XXh XXm.
gen.sorbytime=Ordenar por tiempo estimado
gen.timesheet.instructor=T. Medio env\u00EDos / Estimaci\u00F3n
gen.timesheet.student=T. Dedicado / Estimado
gen.spenttime=Tiempo dedicado
gen.sorbyspenttime=Ordenar por tiempo dedicado
gen.totaltimespent=Tiempo de trabajo aut\u00F3nomo dedicado
gen.totaltimespentconfirm=Tiempo de trabajo aut\u00F3nomo dedicado:
gen.useimputedtime=Utilizar el tiempo imputado en
gen.notimeimputted=No hay tiempo registrado en
gen.notimeimputted.enter=, registre manualmente el tiempo dedicado.
gen.noestimate=Sin registro

ts.tab.assignment=Env\u00EDo
ts.tab.timesheet=Bit\u00e1cora
ts.btn.add.record=A\u00F1adir registro
ts.btn.del.record=Eliminar registro
ts.msg.no.timesheet.record=No hay registros de bit\u00e1cora.
ts.title.timesheet=Bit\u00e1cora
ts.table.tab.date=Fecha
ts.table.tab.comment=Comentario
ts.table.tab.time=Tiempo
ts.table.tab.del=Borrar
ts.modal.new=Nuevo registro
ts.modal.msg.err=Error de formato en el campo tiempo empleado.
ts.modal.field.date=Fecha:
ts.modal.field.comment=Comentario:
ts.modal.field.tspent=Tiempo dedicado:
ts.modal.field.tspent.format=XXh YYm
ts.modal.btn.save=Guardar

ts.add.err.userId=Debe estar registrado para a\u00F1adir registros de bit\u00e1cora
ts.add.err.assignmentId=Debe proporcionar un assignmentId y ref
ts.add.err.startTime=Debe especificar una fecha de bit\u00e1cora
ts.add.err.comment=Necesita completar el campo comentario
ts.add.err.duration=El formato del tiempo estimado de la tarea no es el correcto. Este debe de ser XXh XXm.
ts.add.err.permission=Usted no puede modificar el sumbitter
ts.add.err.submitter=El submitter asociado no existe.
ts.rem.err.userId=Debe estar registrado para eliminar registros de bit\u00e1cora
ts.rem.err.empty=Debe proporcionar la bit\u00e1cora seleccionada
ts.rem.err.submitterId=Debe proporcionar un submissionId y ref
ts.rem.err.permission=Usted no puede modificar el sumbitter
Loading

0 comments on commit 13b5e70

Please sign in to comment.