diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index b573abd4..d343cfa7 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -11,12 +11,14 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Git Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: JDK 11 - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: java-version: 11 + distribution: temurin architecture: x64 + cache: maven - name: Build with Maven env: MAVEN_OPTS: -Djava.awt.headless=true -Dorg.slf4j.simpleLogger.defaultLogLevel=info -Dmaven.wagon.http.retryHandler.count=2 -Dmaven.wagon.http.pool=true diff --git a/README.md b/README.md index 83757780..cfc27e22 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ # Attendance A simple [Sakai](https://github.com/sakaiproject/sakai) tool for tracking attendance that integrates with the Gradebook. -## Performance Improvements - MUST READ -With the release of 20170215, statistics are now stored in a table. As such, a job was created to calculate these stats. -This job should be run once after the deployment of 20170215; afterwards it may be run as needed or at regular interval -as determined by the administrators. The job **MUST BE** run at least once to calculate & save the statistics to begin with, afterwards the job is only needed to be run to sync up the stats to the current roster (in -the case of users attending an item and then later leaving the site). This job is titled "Attendance Stat Calc - SEE DOCS". - ## Resources Pages: http://sakaicontrib.github.io/attendance/ diff --git a/api/pom.xml b/api/pom.xml index 16a6776a..cd99868e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -18,10 +18,11 @@ 4.0.0 - attendance - org.sakaiproject.attendance - 23-SNAPSHOT - + attendance + org.sakaiproject.attendance + 24-SNAPSHOT + ../pom.xml + attendance - API attendance-api @@ -36,24 +37,24 @@ - - org.projectlombok - lombok - org.hibernate hibernate-core - commons-lang - commons-lang + org.apache.commons + commons-lang3 + + + org.springframework.data + spring-data-jpa - - org.sakaiproject.kernel - sakai-kernel-api - + + org.sakaiproject.kernel + sakai-kernel-api + diff --git a/api/src/java/org/sakaiproject/attendance/api/AttendanceGradebookProvider.java b/api/src/java/org/sakaiproject/attendance/api/AttendanceGradebookProvider.java index c523d8a7..9764366b 100644 --- a/api/src/java/org/sakaiproject/attendance/api/AttendanceGradebookProvider.java +++ b/api/src/java/org/sakaiproject/attendance/api/AttendanceGradebookProvider.java @@ -16,8 +16,8 @@ package org.sakaiproject.attendance.api; -import org.sakaiproject.attendance.model.AttendanceGrade; -import org.sakaiproject.attendance.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.AttendanceGrade; +import org.sakaiproject.attendance.api.model.AttendanceSite; import java.util.List; import java.util.Map; diff --git a/api/src/java/org/sakaiproject/attendance/export/PDFEventExporter.java b/api/src/java/org/sakaiproject/attendance/api/export/PDFEventExporter.java similarity index 92% rename from api/src/java/org/sakaiproject/attendance/export/PDFEventExporter.java rename to api/src/java/org/sakaiproject/attendance/api/export/PDFEventExporter.java index 5ba9195f..fc9d5e23 100644 --- a/api/src/java/org/sakaiproject/attendance/export/PDFEventExporter.java +++ b/api/src/java/org/sakaiproject/attendance/api/export/PDFEventExporter.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.sakaiproject.attendance.export; +package org.sakaiproject.attendance.api.export; -import org.sakaiproject.attendance.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceEvent; import org.sakaiproject.user.api.User; import java.io.OutputStream; diff --git a/api/src/java/org/sakaiproject/attendance/logic/AttendanceLogic.java b/api/src/java/org/sakaiproject/attendance/api/logic/AttendanceLogic.java similarity index 87% rename from api/src/java/org/sakaiproject/attendance/logic/AttendanceLogic.java rename to api/src/java/org/sakaiproject/attendance/api/logic/AttendanceLogic.java index 5264fba3..1c597599 100644 --- a/api/src/java/org/sakaiproject/attendance/logic/AttendanceLogic.java +++ b/api/src/java/org/sakaiproject/attendance/api/logic/AttendanceLogic.java @@ -14,13 +14,16 @@ * limitations under the License. */ -package org.sakaiproject.attendance.logic; +package org.sakaiproject.attendance.api.logic; -import java.io.Serializable; import java.util.List; import java.util.Map; +import java.util.Optional; -import org.sakaiproject.attendance.model.*; +import org.sakaiproject.attendance.api.model.*; +import org.sakaiproject.attendance.api.model.stats.AttendanceItemStats; +import org.sakaiproject.attendance.api.model.stats.AttendanceStats; +import org.sakaiproject.attendance.api.model.stats.AttendanceUserStats; import org.sakaiproject.entity.api.EntityProducer; /** @@ -37,7 +40,7 @@ public interface AttendanceLogic extends EntityProducer { * * @param siteID, sakai Site ID * @return the Attendance Site - */ + */ AttendanceSite getAttendanceSite(String siteID); /** @@ -45,8 +48,8 @@ public interface AttendanceLogic extends EntityProducer { * * @param aS, the AttendanceSite to update (must not be null) * @return success of the operation - */ - boolean updateAttendanceSite(AttendanceSite aS) throws IllegalArgumentException; + */ + AttendanceSite updateAttendanceSite(AttendanceSite aS) throws IllegalArgumentException; /** * Get's the current AttendanceSite @@ -82,32 +85,31 @@ public interface AttendanceLogic extends EntityProducer { * * @param e, the AttendanceEvent to add * @return the Long ID of the AttendanceEvent added - */ - Serializable addAttendanceEventNow(AttendanceEvent e); + */ + AttendanceEvent addAttendanceEventNow(AttendanceEvent e); /** * Updates an AttendanceEvent * * @param aE, the event to update (must not be null) * @return success of the operation - */ - boolean updateAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException; + */ + AttendanceEvent updateAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException; /** * Deletes an AttendanceEvent * * @param aE, the event to delete (must not be null) // though this can probably be changed - * @return success of the operation - */ - boolean deleteAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException; + */ + void deleteAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException; /** * Get's an AttendanceRecord by ID * * @param id, the id of the attendanceRecord * @return the attendanceRecord - */ - AttendanceRecord getAttendanceRecord(Long id); + */ + Optional getAttendanceRecord(Long id); /** * get AttendanceRecords For a User in the current site @@ -154,16 +156,16 @@ public interface AttendanceLogic extends EntityProducer { * * @param id, the id of the AttendanceStatus * @return the AttendanceStatus - */ - AttendanceStatus getAttendanceStatusById(Long id); + */ + Optional getAttendanceStatusById(Long id); /** * Update an AttendanceRecord * * @param aR, the AttendanceRecord to update (must not be null) * @return the success of the operation - */ - boolean updateAttendanceRecord(AttendanceRecord aR, Status oldStatus) throws IllegalArgumentException; + */ + AttendanceRecord updateAttendanceRecord(AttendanceRecord aR, Status oldStatus) throws IllegalArgumentException; /** * Update all AttendanceRecords for an AttendanceEvent @@ -180,7 +182,7 @@ public interface AttendanceLogic extends EntityProducer { * @param aE, the AttendanceEvent * @param s, the Status to use (if null, use the Site's default status) * @param groupId, only update the AttendanceRecords for members of the groupID (if null or empty calls - * {@link org.sakaiproject.attendance.logic.AttendanceLogic#updateAttendanceRecordsForEvent(AttendanceEvent, Status)}) + * {@link AttendanceLogic#updateAttendanceRecordsForEvent(AttendanceEvent, Status)}) */ void updateAttendanceRecordsForEvent(AttendanceEvent aE, Status s, String groupId); @@ -240,8 +242,8 @@ public interface AttendanceLogic extends EntityProducer { * * @param id, the ID (must not be null) * @return the AttendanceGrade - */ - AttendanceGrade getAttendanceGrade(Long id) throws IllegalArgumentException; + */ + Optional getAttendanceGrade(Long id) throws IllegalArgumentException; /** * Get's the AttendanceGrade for user in current site @@ -271,8 +273,8 @@ public interface AttendanceLogic extends EntityProducer { * * @param aG, the AG to update (must not be null) * @return the success of the operation - */ - boolean updateAttendanceGrade(AttendanceGrade aG) throws IllegalArgumentException; + */ + AttendanceGrade updateAttendanceGrade(AttendanceGrade aG) throws IllegalArgumentException; /** * Returns the stats for a specified Status from an AttendanceStats object @@ -288,15 +290,14 @@ public interface AttendanceLogic extends EntityProducer { * @param gradingRule, The GradingRule to be added. * @return the success of the operation */ - boolean addGradingRule(GradingRule gradingRule); + GradingRule addGradingRule(GradingRule gradingRule); /** * Deletes a grading rule. * * @param gradingRule, The GradingRule to be deleted. - * @return the success of the operation */ - boolean deleteGradingRule(GradingRule gradingRule); + void deleteGradingRule(GradingRule gradingRule); /** * Get a list of Grading Rules that have been created for a given diff --git a/api/src/java/org/sakaiproject/attendance/logic/SakaiProxy.java b/api/src/java/org/sakaiproject/attendance/api/logic/SakaiProxy.java similarity index 99% rename from api/src/java/org/sakaiproject/attendance/logic/SakaiProxy.java rename to api/src/java/org/sakaiproject/attendance/api/logic/SakaiProxy.java index 0521d94a..6d4bafd6 100644 --- a/api/src/java/org/sakaiproject/attendance/logic/SakaiProxy.java +++ b/api/src/java/org/sakaiproject/attendance/api/logic/SakaiProxy.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.sakaiproject.attendance.logic; +package org.sakaiproject.attendance.api.logic; import org.sakaiproject.user.api.User; diff --git a/api/src/java/org/sakaiproject/attendance/api/model/AttendanceEvent.java b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceEvent.java new file mode 100644 index 00000000..9439fce3 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceEvent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.annotations.Type; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.springframework.data.PersistableEntity; + +import javax.persistence.CascadeType; +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.OneToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import java.io.Serializable; +import java.time.Instant; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Represents an AttendanceEvent, such as a class meeting or seminar + * + * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu]) + * @author David Bauer [dbauer1 (at) udayton (dot) edu] + * @author Steve Swinsburg (steve.swinsburg@gmail.com) + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_EVENT_T") +@Getter +@Setter +@RequiredArgsConstructor +@ToString +@AllArgsConstructor +public class AttendanceEvent implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "A_EVENT_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "attendance_event_id_sequence") + @SequenceGenerator(name = "attendance_event_id_sequence", sequenceName = "ATTENDANCE_EVENT_S") + private Long id; + + @Column(name = "NAME") + private String name; + + @Type(type = "org.hibernate.type.InstantType") + @Column(name = "START_DATE_TIME") + private Instant startDateTime; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "A_SITE_ID") + @ToString.Exclude + private AttendanceSite attendanceSite; + + @OneToMany(mappedBy = "attendanceEvent", cascade = CascadeType.ALL, orphanRemoval = true) + @ToString.Exclude + private Set records = new HashSet<>(0); + + // Copy constructor + public AttendanceEvent(AttendanceEvent attendanceEvent) { + this.name = attendanceEvent.name; + this.startDateTime = attendanceEvent.startDateTime; + this.attendanceSite = attendanceEvent.attendanceSite; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + AttendanceEvent that = (AttendanceEvent) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/api/model/AttendanceGrade.java b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceGrade.java new file mode 100644 index 00000000..e3bbea02 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceGrade.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.springframework.data.PersistableEntity; + +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 java.io.Serializable; +import java.util.Objects; + +/** + * The AttendanceGrade earned for the all AttendanceItems + * + * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu]au) + * @author Steve Swinsburg (steve.swinsburg@gmail.com) + */ + +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_GRADE_T") +@Getter +@Setter +@RequiredArgsConstructor +@ToString +@AllArgsConstructor +public class AttendanceGrade implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "A_GRADE_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "attendance_grade_id_sequence") + @SequenceGenerator(name = "attendance_grade_id_sequence", sequenceName = "ATTENDANCE_GRADE_S") + private Long id; + + @Column(name = "GRADE") + private Double grade; + + @Column(name = "USER_ID", length = 99) + private String userID; + + @Column(name = "OVERRIDE") + private Boolean override; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "A_SITE_ID") + @ToString.Exclude + private AttendanceSite attendanceSite; + + public AttendanceGrade(AttendanceSite aS, String userId) { + this.attendanceSite = aS; + this.userID = userId; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + AttendanceGrade that = (AttendanceGrade) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/api/model/AttendanceRecord.java b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceRecord.java new file mode 100644 index 00000000..1fd27b33 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceRecord.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.springframework.data.PersistableEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Objects; + +/** + * An AttendanceRecord for a specific user for a specific AttendanceEvent + * + * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] + * @author David Bauer [dbauer1 (at) udayton (dot) edu] + * @author Steve Swinsburg (steve.swinsburg@gmail.com) + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_RECORD_T", + indexes = { + @Index(name = "ATTEN_EVENT_STATUS_I", columnList = "A_EVENT_ID, STATUS"), + @Index(name = "ATTEN_EVENT_USER_STATUS_I", columnList = "A_EVENT_ID, USER_ID, STATUS") + }) +@Getter +@Setter +@RequiredArgsConstructor +@ToString +@AllArgsConstructor +public class AttendanceRecord implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "A_RECORD_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "attendance_record_id_sequence") + @SequenceGenerator(name = "attendance_record_id_sequence", sequenceName = "ATTENDANCE_RECORD_S") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "A_EVENT_ID") + @ToString.Exclude + private AttendanceEvent attendanceEvent; + + @Column(name = "USER_ID", length = 99) + private String userID; + + @Enumerated(value = EnumType.STRING) + @Column(name = "STATUS", nullable = false, length = 20) + private Status status = Status.UNKNOWN; + + @Lob + @Column(name = "RECORD_COMMENT", length = 4000) + private String comment; + + public AttendanceRecord(AttendanceEvent e, String uId, Status s) { + this.attendanceEvent = e; + this.userID = uId; + this.status = s; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + AttendanceRecord that = (AttendanceRecord) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/api/model/AttendanceSite.java b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceSite.java new file mode 100644 index 00000000..3afa24be --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceSite.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.attendance.api.util.AttendanceConstants; +import org.sakaiproject.springframework.data.PersistableEntity; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * An AttendanceSite represents all the Attendance related data for a specific Sakai Site. + * + * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] + * @author David Bauer [dbauer1 (at) udayton (dot) edu] + * @author Steve Swinsburg (steve.swinsburg@gmail.com) + */ + +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_SITE_T") +@Getter +@Setter +@RequiredArgsConstructor +@ToString +@AllArgsConstructor +public class AttendanceSite implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "A_SITE_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "attendance_site_id_sequence") + @SequenceGenerator(name = "attendance_site_id_sequence", sequenceName = "ATTENDANCE_SITE_S") + private Long id; + + @Column(name = "SITE_ID", length = 99, nullable = false) + private String siteID; + + @Enumerated(value = EnumType.STRING) + @Column(name = "DEFAULT_STATUS", nullable = false, length = 20) + private Status defaultStatus = Status.UNKNOWN; + + @Column(name = "MAXIMUM_GRADE") + private Double maximumGrade; + + @Column(name = "IS_GRADE_SHOWN") + private Boolean isGradeShown = Boolean.FALSE; + + @Column(name = "SEND_TO_GRADEBOOK") + private Boolean sendToGradebook = Boolean.FALSE; + + @Column(name = "AUTO_GRADING") + private Boolean useAutoGrading = Boolean.FALSE; + + @Column(name = "GRADE_BY_SUBTRACTION") + private Boolean autoGradeBySubtraction = Boolean.TRUE; + + @Column(name = "GRADEBOOK_ITEM_NAME") + private String gradebookItemName; + + @Column(name = "SHOW_COMMENTS") + private Boolean showCommentsToStudents = Boolean.FALSE; + + @OneToMany(mappedBy = "attendanceSite", cascade = CascadeType.ALL, orphanRemoval = true) + @ToString.Exclude + private Set attendanceStatuses = new HashSet<>(0); + + public AttendanceSite(String siteID) { + this.siteID = siteID; + this.gradebookItemName = AttendanceConstants.GRADEBOOK_ITEM_NAME; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + AttendanceSite that = (AttendanceSite) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/api/model/AttendanceStatus.java b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceStatus.java new file mode 100644 index 00000000..a2113eb6 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/AttendanceStatus.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.springframework.data.PersistableEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +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 java.io.Serializable; +import java.util.Objects; + +/** + * An AttendanceStatus is a wrapper around the Status enum type defining meta information on individual Statuses. + * + * @author David Bauer [dbauer1 (at) udayton (dot) edu] + * @author Steve Swinsburg (steve.swinsburg@gmail.com) + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_STATUS_T") +@Getter +@Setter +@RequiredArgsConstructor +@ToString +@AllArgsConstructor +public class AttendanceStatus implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "A_STATUS_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "attendance_status_id_sequence") + @SequenceGenerator(name = "attendance_status_id_sequence", sequenceName = "ATTENDANCE_STATUS_S") + private Long id; + + @Column(name = "IS_ACTIVE") + private Boolean isActive = Boolean.TRUE; + + @Enumerated(value = EnumType.STRING) + @Column(name = "STATUS", nullable = false, length = 20) + private Status status; + + @Column(name = "SORT_ORDER") + private int sortOrder; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "A_SITE_ID") + @ToString.Exclude + private AttendanceSite attendanceSite; + + // Create a copy constructor + public AttendanceStatus(AttendanceStatus attendanceStatus) { + this.isActive = attendanceStatus.getIsActive(); + this.status = attendanceStatus.getStatus(); + this.sortOrder = attendanceStatus.getSortOrder(); + this.attendanceSite = attendanceStatus.getAttendanceSite(); + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + AttendanceStatus that = (AttendanceStatus) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/api/model/GradingRule.java b/api/src/java/org/sakaiproject/attendance/api/model/GradingRule.java new file mode 100644 index 00000000..ada9187d --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/GradingRule.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, University of Dayton + * + * 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.attendance.api.model; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxy; +import org.sakaiproject.springframework.data.PersistableEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +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 java.io.Serializable; +import java.util.Objects; + +/** + * @author David P. Bauer [dbauer1 (at) udayton (dot) edu] + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@Table(name = "ATTENDANCE_RULE_T") +@Getter +@Setter +@RequiredArgsConstructor +@ToString +public class GradingRule implements Serializable, PersistableEntity { + private static final long serialVersionUID = 1L; + + @Id + @Column(name = "GRADING_RULE_ID", length = 19) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "grading_rule_id_sequence") + @SequenceGenerator(name = "grading_rule_id_sequence", sequenceName = "ATTENDANCE_GRADING_RULE_S") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "A_SITE_ID") + @ToString.Exclude + private AttendanceSite attendanceSite; + + @Enumerated(value = EnumType.STRING) + @Column(name = "STATUS", nullable = false, length = 20) + private Status status; + + @Column(name = "START_RANGE", nullable = false) + private Integer startRange = 0; + + @Column(name = "END_RANGE") + private Integer endRange; + + @Column(name = "POINTS", nullable = false) + private Double points = 0D; + + public GradingRule(AttendanceSite attendanceSite) { + this.attendanceSite = attendanceSite; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + GradingRule that = (GradingRule) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } +} diff --git a/api/src/java/org/sakaiproject/attendance/model/GradingRule.java b/api/src/java/org/sakaiproject/attendance/api/model/ImportConfirmList.java similarity index 59% rename from api/src/java/org/sakaiproject/attendance/model/GradingRule.java rename to api/src/java/org/sakaiproject/attendance/api/model/ImportConfirmList.java index 727811c5..7bdd4d8b 100644 --- a/api/src/java/org/sakaiproject/attendance/model/GradingRule.java +++ b/api/src/java/org/sakaiproject/attendance/api/model/ImportConfirmList.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package org.sakaiproject.attendance.model; +package org.sakaiproject.attendance.api.model; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -23,23 +24,26 @@ import java.io.Serializable; /** - * @author David P. Bauer [dbauer1 (at) udayton (dot) edu] + * Holds the records that are being changed by the Import function. + * + * Created by james on 6/9/17. */ @Data -@EqualsAndHashCode(of = "id") +@EqualsAndHashCode(of = {"id","attendanceEvent","userID","status","comment","oldComment","oldStatus"}) @NoArgsConstructor -public class GradingRule implements Serializable { +@AllArgsConstructor +public class ImportConfirmList implements Serializable { private static final long serialVersionUID = 1L; private Long id; + private AttendanceEvent attendanceEvent; + private AttendanceRecord attendanceRecord; private AttendanceSite attendanceSite; + private String userID; private Status status; - private Integer startRange; - private Integer endRange; - private Double points; - - public GradingRule(AttendanceSite attendanceSite) { - this.attendanceSite = attendanceSite; - } - + private Status oldStatus; + private String comment; + private String oldComment; + private String eventName; + private String eventDate; } diff --git a/api/src/java/org/sakaiproject/attendance/model/Status.java b/api/src/java/org/sakaiproject/attendance/api/model/Status.java similarity index 95% rename from api/src/java/org/sakaiproject/attendance/model/Status.java rename to api/src/java/org/sakaiproject/attendance/api/model/Status.java index d76dc35d..66cfeb3b 100644 --- a/api/src/java/org/sakaiproject/attendance/model/Status.java +++ b/api/src/java/org/sakaiproject/attendance/api/model/Status.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.sakaiproject.attendance.model; +package org.sakaiproject.attendance.api.model; /** * The Different Statuses defined within the Tool diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceItemStats.java b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceItemStats.java similarity index 76% rename from api/src/java/org/sakaiproject/attendance/model/AttendanceItemStats.java rename to api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceItemStats.java index 14472696..fda87427 100644 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceItemStats.java +++ b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceItemStats.java @@ -14,12 +14,15 @@ * limitations under the License. */ -package org.sakaiproject.attendance.model; +package org.sakaiproject.attendance.api.model.stats; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import org.sakaiproject.attendance.api.model.AttendanceEvent; + +import java.util.List; /** * Created by Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] @@ -27,7 +30,7 @@ @Data @NoArgsConstructor @AllArgsConstructor -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) public class AttendanceItemStats extends AttendanceStats{ private static final long serialVersionUID = 1L; @@ -38,4 +41,8 @@ public AttendanceItemStats(AttendanceEvent attendanceEvent) { this.attendanceEvent = attendanceEvent; } + public AttendanceItemStats(AttendanceEvent attendanceEvent, List statusCounts) { + this.attendanceEvent = attendanceEvent; + super.setTotalsFromCounts(statusCounts); + } } diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceStats.java b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceStats.java similarity index 64% rename from api/src/java/org/sakaiproject/attendance/model/AttendanceStats.java rename to api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceStats.java index b820e63c..cc2d9be0 100644 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceStats.java +++ b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceStats.java @@ -14,12 +14,13 @@ * limitations under the License. */ -package org.sakaiproject.attendance.model; +package org.sakaiproject.attendance.api.model.stats; import lombok.Getter; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; +import java.util.List; /** * Created by Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] @@ -27,18 +28,40 @@ @Slf4j @EqualsAndHashCode public class AttendanceStats implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; @Getter - private int present = 0; + private int present = 0; @Getter - private int unexcused = 0; + private int unexcused = 0; @Getter - private int excused = 0; + private int excused = 0; @Getter - private int late = 0; + private int late = 0; @Getter - private int leftEarly = 0; + private int leftEarly = 0; + + void setTotalsFromCounts(List statusCounts) { + for (StatusCount statusCount : statusCounts) { + switch (statusCount.getStatus()) { + case LATE: + this.setLate(statusCount.getTotal().intValue()); + break; + case LEFT_EARLY: + this.setLeftEarly(statusCount.getTotal().intValue()); + break; + case EXCUSED_ABSENCE: + this.setExcused(statusCount.getTotal().intValue()); + break; + case PRESENT: + this.setPresent(statusCount.getTotal().intValue()); + break; + case UNEXCUSED_ABSENCE: + this.setUnexcused((statusCount.getTotal().intValue())); + break; + } + } + } public void setPresent(int present) { if(present < 0) { diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceUserStats.java b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceUserStats.java similarity index 76% rename from api/src/java/org/sakaiproject/attendance/model/AttendanceUserStats.java rename to api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceUserStats.java index 86b188a1..65031cfe 100644 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceUserStats.java +++ b/api/src/java/org/sakaiproject/attendance/api/model/stats/AttendanceUserStats.java @@ -14,12 +14,15 @@ * limitations under the License. */ -package org.sakaiproject.attendance.model; +package org.sakaiproject.attendance.api.model.stats; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import org.sakaiproject.attendance.api.model.AttendanceSite; + +import java.util.List; /** * Created by Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] @@ -27,7 +30,7 @@ @Data @NoArgsConstructor @AllArgsConstructor -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) public class AttendanceUserStats extends AttendanceStats { private static final long serialVersionUID = 1L; @@ -40,4 +43,10 @@ public AttendanceUserStats(String userID, AttendanceSite attendanceSite) { this.attendanceSite = attendanceSite; } + public AttendanceUserStats(String userId, AttendanceSite attendanceSite, List statusCounts) { + this.userID = userId; + this.attendanceSite = attendanceSite; + super.setTotalsFromCounts(statusCounts); + } + } diff --git a/api/src/java/org/sakaiproject/attendance/api/model/stats/StatusCount.java b/api/src/java/org/sakaiproject/attendance/api/model/stats/StatusCount.java new file mode 100644 index 00000000..fd8316e2 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/model/stats/StatusCount.java @@ -0,0 +1,12 @@ +package org.sakaiproject.attendance.api.model.stats; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.sakaiproject.attendance.api.model.Status; + +@AllArgsConstructor +public class StatusCount { + @Getter @Setter private Status status; + @Getter @Setter private Long total; +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceEventRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceEventRepository.java new file mode 100644 index 00000000..7e421094 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceEventRepository.java @@ -0,0 +1,14 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.stats.AttendanceItemStats; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; + +public interface AttendanceEventRepository extends SpringCrudRepository { + + List findAllByAttendanceSite(AttendanceSite attendanceSite); + AttendanceItemStats calculateStatsForEvent(AttendanceEvent event); +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceGradeRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceGradeRepository.java new file mode 100644 index 00000000..d3d46795 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceGradeRepository.java @@ -0,0 +1,14 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceGrade; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; +import java.util.Optional; + +public interface AttendanceGradeRepository extends SpringCrudRepository { + + List findAllByAttendanceSite(AttendanceSite attendanceSite); + Optional findByAttendanceSiteAndUserId(AttendanceSite attendanceSite, String userId); +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceRecordRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceRecordRepository.java new file mode 100644 index 00000000..73f647d8 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceRecordRepository.java @@ -0,0 +1,12 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceRecord; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; + +public interface AttendanceRecordRepository extends SpringCrudRepository { + + List findAllByAttendanceEvent(AttendanceEvent attendanceEvent); +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceSiteRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceSiteRepository.java new file mode 100644 index 00000000..9f3a3675 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceSiteRepository.java @@ -0,0 +1,13 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.stats.AttendanceUserStats; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; + +public interface AttendanceSiteRepository extends SpringCrudRepository { + + AttendanceSite findBySiteId(String siteId); + AttendanceUserStats calculateAttendanceUserStats(String userId, AttendanceSite attendanceSite); +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceStatusRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceStatusRepository.java new file mode 100644 index 00000000..d4290622 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/AttendanceStatusRepository.java @@ -0,0 +1,13 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.AttendanceStatus; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; + +public interface AttendanceStatusRepository extends SpringCrudRepository { + + List findAllByAttendanceSite(AttendanceSite attendanceSite); + List findAllActiveByAttendanceSite(AttendanceSite attendanceSite); +} diff --git a/api/src/java/org/sakaiproject/attendance/api/repository/GradingRuleRepository.java b/api/src/java/org/sakaiproject/attendance/api/repository/GradingRuleRepository.java new file mode 100644 index 00000000..665a1e26 --- /dev/null +++ b/api/src/java/org/sakaiproject/attendance/api/repository/GradingRuleRepository.java @@ -0,0 +1,12 @@ +package org.sakaiproject.attendance.api.repository; + +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.GradingRule; +import org.sakaiproject.springframework.data.SpringCrudRepository; + +import java.util.List; + +public interface GradingRuleRepository extends SpringCrudRepository { + + List findAllByAttendanceSite(AttendanceSite attendanceSite); +} diff --git a/api/src/java/org/sakaiproject/attendance/util/AttendanceConstants.java b/api/src/java/org/sakaiproject/attendance/api/util/AttendanceConstants.java similarity index 96% rename from api/src/java/org/sakaiproject/attendance/util/AttendanceConstants.java rename to api/src/java/org/sakaiproject/attendance/api/util/AttendanceConstants.java index cc26763e..407f02a6 100644 --- a/api/src/java/org/sakaiproject/attendance/util/AttendanceConstants.java +++ b/api/src/java/org/sakaiproject/attendance/api/util/AttendanceConstants.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.sakaiproject.attendance.util; +package org.sakaiproject.attendance.api.util; /** * Class to hold constants (defaults, etc) for Attendance. diff --git a/api/src/java/org/sakaiproject/attendance/cache/CacheManager.java b/api/src/java/org/sakaiproject/attendance/cache/CacheManager.java deleted file mode 100644 index 44666c20..00000000 --- a/api/src/java/org/sakaiproject/attendance/cache/CacheManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.cache; - -import org.sakaiproject.memory.api.Cache; - -/** - * Created by Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - */ -public interface CacheManager { - Cache createCache(String cacheName); -} diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceEvent.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceEvent.hbm.xml deleted file mode 100644 index 2eef4b95..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceEvent.hbm.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_EVENT_S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceGrade.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceGrade.hbm.xml deleted file mode 100644 index b798a42a..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceGrade.hbm.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_GRADE_S - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceItemStats.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceItemStats.hbm.xml deleted file mode 100644 index cfb4a3f3..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceItemStats.hbm.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - attendanceEvent - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceRecord.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceRecord.hbm.xml deleted file mode 100644 index af612019..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceRecord.hbm.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_RECORD_S - - - - - - - - - - - - - - - - - - diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceSite.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceSite.hbm.xml deleted file mode 100644 index 8940dfa3..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceSite.hbm.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_SITE_S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - :id - ORDER BY id ASC - ]]> - - - - - - - - - - diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceStatus.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceStatus.hbm.xml deleted file mode 100644 index 559a872a..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceStatus.hbm.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_STATUS_S - - - - - - - - - - - - - - - - - - - - - diff --git a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceUserStats.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/AttendanceUserStats.hbm.xml deleted file mode 100644 index a436a4ef..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/AttendanceUserStats.hbm.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_USER_STATS_S - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/src/java/org/sakaiproject/attendance/hbm/GradingRule.hbm.xml b/api/src/java/org/sakaiproject/attendance/hbm/GradingRule.hbm.xml deleted file mode 100644 index 689b11b2..00000000 --- a/api/src/java/org/sakaiproject/attendance/hbm/GradingRule.hbm.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - ATTENDANCE_GRADING_RULE_S - - - - - - - - - - - - - - - - - diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceEvent.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceEvent.java deleted file mode 100644 index fef9b37b..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceEvent.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.*; - -import java.io.Serializable; -import java.util.*; - -/** - * Represents an AttendanceEvent, such as a class meeting or seminar - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu]) - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(exclude={"records","stats"}) -public class AttendanceEvent implements Serializable { - private static final long serialVersionUID = 1L; - - @Getter @Setter private Long id; - @Getter @Setter private String name; - @Getter @Setter private Date startDateTime; - @Getter @Setter private Date endDateTime; - @Getter @Setter private Boolean isReoccurring; - @Getter @Setter private Long reoccurringID; - @Getter @Setter private Boolean isRequired; - @Getter @Setter private String releasedTo; - @Getter @Setter private AttendanceSite attendanceSite; - @Getter @Setter private String location; - @Getter @Setter private Set records = new HashSet(0); - @Getter @Setter private AttendanceItemStats stats; - - // Copy constructor - public AttendanceEvent(AttendanceEvent attendanceEvent){ - this.name = attendanceEvent.name; - this.startDateTime = attendanceEvent.startDateTime; - this.endDateTime = attendanceEvent.endDateTime; - this.isReoccurring = attendanceEvent.isReoccurring; - this.reoccurringID = attendanceEvent.reoccurringID; - this.isRequired = attendanceEvent.isRequired; - this.releasedTo = attendanceEvent.releasedTo; - this.attendanceSite = attendanceEvent.attendanceSite; - this.location = attendanceEvent.location; - } - -} diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceGrade.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceGrade.java deleted file mode 100644 index 8ec14dbc..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceGrade.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.io.Serializable; - -/** - * The AttendanceGrade earned for the all AttendanceItems - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu]au) - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class AttendanceGrade implements Serializable { - private static final long serialVersionUID = 1L; - - private Long id; - private Double grade; - private String userID; - private Boolean override; - - private AttendanceSite attendanceSite; - - public AttendanceGrade(AttendanceSite aS, String userId){ - this.attendanceSite = aS; - this.userID = userId; - } -} diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceRecord.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceRecord.java deleted file mode 100644 index 0541a328..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceRecord.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.*; - -import java.io.Serializable; -import java.util.Objects; - -/** - * An AttendanceRecord for a specific user for a specific AttendanceEvent - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode -public class AttendanceRecord implements Serializable { - private static final long serialVersionUID = 1L; - - @Getter @Setter private Long id; - @Getter @Setter private AttendanceEvent attendanceEvent; - @Getter @Setter private String userID; - @Getter @Setter private Status status; - @Getter @Setter private String comment; - - public AttendanceRecord(AttendanceEvent e, String uId, Status s) { - this.attendanceEvent = e; - this.userID = uId; - this.status = s; - } - -} diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceSite.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceSite.java deleted file mode 100644 index 0383ff17..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceSite.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.*; -import org.sakaiproject.attendance.util.AttendanceConstants; - -import java.io.Serializable; -import java.util.*; - -/** - * An AttendanceSite represents all the Attendance related data for a specific Sakai Site. - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(exclude="attendanceStatuses") -public class AttendanceSite implements Serializable { - private static final long serialVersionUID = 1L; - - @Getter @Setter private Long id; - @Getter @Setter private String siteID; - @Getter @Setter private Status defaultStatus; - @Getter @Setter private Double maximumGrade; - @Getter @Setter private Boolean isGradeShown; - @Setter private Boolean sendToGradebook; - @Setter private Boolean useAutoGrading; - @Setter private Boolean autoGradeBySubtraction; - @Getter @Setter private String gradebookItemName; - @Getter @Setter private Boolean showCommentsToStudents; - @Setter private Boolean isSyncing; - @Getter @Setter private Date syncTime; - @Getter @Setter private Set attendanceStatuses = new HashSet<>(0); - - public AttendanceSite(String siteID){ - this.siteID = siteID; - this.defaultStatus = Status.UNKNOWN; - this.isGradeShown = false; - this.sendToGradebook = false; - this.useAutoGrading = false; - this.autoGradeBySubtraction = true; - this.gradebookItemName = AttendanceConstants.GRADEBOOK_ITEM_NAME; - this.showCommentsToStudents = false; - this.isSyncing = false; - } - - public Boolean getSendToGradebook() { - if(this.sendToGradebook == null) { - return false; - } - - return this.sendToGradebook; - } - - public Boolean getIsSyncing() { - if(this.isSyncing == null) { - return false; - } - - return this.isSyncing; - } - - public Boolean getUseAutoGrading() { - if(this.useAutoGrading == null) { - return false; - } - - return this.useAutoGrading; - } - - public Boolean getAutoGradeBySubtraction() { - if(this.autoGradeBySubtraction == null) { - return true; - } - - return this.autoGradeBySubtraction; - } - -} diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceStatus.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceStatus.java deleted file mode 100644 index 0d5fe6b0..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceStatus.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.io.Serializable; -import java.util.Objects; - -/** - * An AttendanceStatus is a wrapper around the Status enum type defining meta information on individual Statuses. - * - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(of = {"id"}) -public class AttendanceStatus implements Serializable { - private static final long serialVersionUID = 1L; - - @Getter @Setter private Long id; - @Getter @Setter private Boolean isActive; - @Getter @Setter private Status status; - @Getter @Setter private int sortOrder; - @Getter @Setter private AttendanceSite attendanceSite; - - // Create a copy constructor - public AttendanceStatus(AttendanceStatus attendanceStatus) { - this.isActive = attendanceStatus.getIsActive(); - this.status = attendanceStatus.getStatus(); - this.sortOrder = attendanceStatus.getSortOrder(); - this.attendanceSite = attendanceStatus.getAttendanceSite(); - } - -} diff --git a/api/src/java/org/sakaiproject/attendance/model/AttendanceUserGroupStats.java b/api/src/java/org/sakaiproject/attendance/model/AttendanceUserGroupStats.java deleted file mode 100644 index b6daee30..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/AttendanceUserGroupStats.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; - -/** - * Created by james on 7/11/17. - */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class AttendanceUserGroupStats { - private static final long serialVersionUID = 1L; - - private String userID; - private String groupId; - private AttendanceSite attendanceSite; - - - public AttendanceUserGroupStats(String userID, AttendanceSite attendanceSite) { - this.userID = userID; - this.attendanceSite = attendanceSite; - } - - @Override - public boolean equals (final Object obj) { - if(obj == null) { - return false; - } - - if(obj == this) { - return true; - } - - if(obj.getClass() != getClass()) { - return false; - } - - final AttendanceUserGroupStats other = (AttendanceUserGroupStats) obj; - return new EqualsBuilder() - .appendSuper(super.equals(obj)) - .append(this.userID, other.userID) - .append(this.groupId, other.groupId) - .append(this.attendanceSite, other.attendanceSite) - .isEquals(); - } - - @Override - public int hashCode() { - return new HashCodeBuilder() - .appendSuper(super.hashCode()) - .append(this.userID) - .append(this.groupId) - .append(this.attendanceSite.getId()) - .toHashCode(); - } -} diff --git a/api/src/java/org/sakaiproject/attendance/model/ImportConfirmList.java b/api/src/java/org/sakaiproject/attendance/model/ImportConfirmList.java deleted file mode 100644 index cd0f75e4..00000000 --- a/api/src/java/org/sakaiproject/attendance/model/ImportConfirmList.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * Holds the records that are being changed by the Import function. - * - * Created by james on 6/9/17. - */ -@NoArgsConstructor -@AllArgsConstructor -public class ImportConfirmList implements Serializable { - private static final long serialVersionUID = 1L; - - @Getter @Setter private Long id; - @Getter @Setter private AttendanceEvent attendanceEvent; - @Getter @Setter private AttendanceRecord attendanceRecord; - @Getter @Setter private AttendanceSite attendanceSite; - @Getter @Setter private String userID; - @Getter @Setter private Status status; - @Getter @Setter private Status oldStatus; - @Getter @Setter private String comment; - @Getter @Setter private String oldComment; - @Getter @Setter private String eventName; - @Getter @Setter private String eventDate; - - - public ImportConfirmList(AttendanceEvent e, String uId, Status newStatus) { - this.attendanceEvent = e; - this.userID = uId; - this.status = newStatus; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final org.sakaiproject.attendance.model.ImportConfirmList that = (org.sakaiproject.attendance.model.ImportConfirmList) o; - return Objects.equals(id, that.id) && - Objects.equals(attendanceEvent, that.attendanceEvent) && - Objects.equals(userID, that.userID) && - status == that.status && - Objects.equals(comment, that.comment) && - Objects.equals(oldComment, that.oldComment) && - Objects.equals(oldStatus, that.oldStatus); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} diff --git a/api/src/java/org/sakaiproject/attendance/types/StatusUserType.java b/api/src/java/org/sakaiproject/attendance/types/StatusUserType.java deleted file mode 100644 index c991a6c8..00000000 --- a/api/src/java/org/sakaiproject/attendance/types/StatusUserType.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.types; - -import org.sakaiproject.attendance.model.Status; -import org.sakaiproject.springframework.orm.hibernate.EnumUserType; - -/** - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - * @author Duffy Gillman - * Modeled after org.sakaiproject.scheduler.events.hibernate.TriggerEventEnumUserType.java - */ -public class StatusUserType extends EnumUserType { - public StatusUserType(){ - super(Status.class); - } -} diff --git a/docs/sql/sakai23-conversion-mysql.sql b/docs/sql/sakai23-conversion-mysql.sql new file mode 100644 index 00000000..c3ad095d --- /dev/null +++ b/docs/sql/sakai23-conversion-mysql.sql @@ -0,0 +1,27 @@ +ALTER TABLE ATTENDANCE_EVENT_T + DROP END_DATE_TIME, + DROP IS_REOCCURRING, + DROP REOCCURRING_ID, + DROP IS_REQUIRED, + DROP RELEASED_TO, + DROP LOCATION; + +ALTER TABLE ATTENDANCE_GRADE_T CHANGE USER_ID USER_ID VARCHAR(99) NULL DEFAULT NULL; + +DROP TABLE ATTENDANCE_ITEM_STATS_T; + +ALTER TABLE ATTENDANCE_SITE_T CHANGE IS_GRADE_SHOWN IS_GRADE_SHOWN BIT(1) NULL DEFAULT b'0', CHANGE SEND_TO_GRADEBOOK SEND_TO_GRADEBOOK BIT(1) NULL DEFAULT b'0', CHANGE AUTO_GRADING AUTO_GRADING BIT(1) NULL DEFAULT b'0', CHANGE GRADE_BY_SUBTRACTION GRADE_BY_SUBTRACTION BIT(1) NULL DEFAULT b'1', CHANGE SHOW_COMMENTS SHOW_COMMENTS BIT(1) NULL DEFAULT b'0'; + +ALTER TABLE ATTENDANCE_SITE_T + DROP SYNC, + DROP SYNC_TIME; + +ALTER TABLE ATTENDANCE_RULE_T CHANGE START_RANGE START_RANGE INT(11) NOT NULL DEFAULT '0'; + +ALTER TABLE ATTENDANCE_RULE_T CHANGE POINTS POINTS DOUBLE NOT NULL DEFAULT '0'; + +ALTER TABLE ATTENDANCE_STATUS_T CHANGE IS_ACTIVE IS_ACTIVE BIT(1) NULL DEFAULT b'1'; + +ALTER TABLE ATTENDANCE_STATUS_T CHANGE STATUS STATUS VARCHAR(20) NULL DEFAULT NULL; + +DROP TABLE ATTENDANCE_USER_STATS_T; \ No newline at end of file diff --git a/docs/sql/sakai23-conversion-oracle.sql b/docs/sql/sakai23-conversion-oracle.sql new file mode 100644 index 00000000..8a040e03 --- /dev/null +++ b/docs/sql/sakai23-conversion-oracle.sql @@ -0,0 +1,29 @@ +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN END_DATE_TIME; +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN IS_REOCCURRING; +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN REOCCURRING_ID; +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN IS_REQUIRED; +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN RELEASED_TO; +ALTER TABLE ATTENDANCE_EVENT_T DROP COLUMN LOCATION; + +ALTER TABLE ATTENDANCE_GRADE_T MODIFY USER_ID VARCHAR2(99) NULL DEFAULT NULL; + +DROP TABLE ATTENDANCE_ITEM_STATS_T; + +ALTER TABLE ATTENDANCE_SITE_T MODIFY IS_GRADE_SHOWN NUMBER(1) NULL DEFAULT 0; +ALTER TABLE ATTENDANCE_SITE_T MODIFY SEND_TO_GRADEBOOK NUMBER(1,0) NULL DEFAULT 0; +ALTER TABLE ATTENDANCE_SITE_T MODIFY AUTO_GRADING NUMBER(1,0) NULL DEFAULT 0; +ALTER TABLE ATTENDANCE_SITE_T MODIFY GRADE_BY_SUBTRACTION NUMBER(1,0) NULL DEFAULT 1; +ALTER TABLE ATTENDANCE_SITE_T MODIFY SHOW_COMMENTS NUMBER(1,0) NULL DEFAULT 0; + +ALTER TABLE ATTENDANCE_SITE_T DROP COLUMN SYNC; +ALTER TABLE ATTENDANCE_SITE_T DROP COLUMN SYNC_TIME; + +ALTER TABLE ATTENDANCE_RULE_T MODIFY START_RANGE NUMBER(11, 0) NOT NULL DEFAULT '0'; + +ALTER TABLE ATTENDANCE_RULE_T MODIFY POINTS NUMBER(19,4) NOT NULL DEFAULT '0'; + +ALTER TABLE ATTENDANCE_STATUS_T MODIFY IS_ACTIVE NUMBER(1,0) NULL DEFAULT 1; + +ALTER TABLE ATTENDANCE_STATUS_T MODIFY STATUS VARCHAR2(20) NULL DEFAULT NULL; + +DROP TABLE ATTENDANCE_USER_STATS_T; \ No newline at end of file diff --git a/impl/pom.xml b/impl/pom.xml index 5b281a71..e5c8d003 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -18,10 +18,11 @@ 4.0.0 - attendance - org.sakaiproject.attendance - 23-SNAPSHOT - + attendance + org.sakaiproject.attendance + 24-SNAPSHOT + ../pom.xml + attendance - Implementation attendance-impl @@ -41,29 +42,29 @@ - - org.projectlombok - lombok - org.springframework spring-core + + org.springframework.data + spring-data-jpa + org.springframework - spring-orm + spring-context - net.sf.ehcache - ehcache-core + org.springframework + spring-orm - commons-lang - commons-lang + org.springframework + spring-tx - commons-configuration - commons-configuration + org.apache.commons + commons-lang3 org.hibernate @@ -78,21 +79,13 @@ quartz - - org.sakaiproject.kernel - sakai-kernel-api - - - org.sakaiproject.kernel - sakai-component-manager - - + org.sakaiproject.kernel - sakai-kernel-util + sakai-kernel-api - org.sakaiproject.genericdao - generic-dao + org.sakaiproject.kernel + sakai-component-manager org.sakaiproject.grading diff --git a/impl/src/java/org/sakaiproject/attendance/cache/CacheManagerImpl.java b/impl/src/java/org/sakaiproject/attendance/cache/CacheManagerImpl.java deleted file mode 100644 index 84b15e44..00000000 --- a/impl/src/java/org/sakaiproject/attendance/cache/CacheManagerImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.cache; - -import lombok.Setter; -import org.sakaiproject.memory.api.Cache; -import org.sakaiproject.memory.api.MemoryService; - -/** - * A shell to eventually implement caching - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - */ -public class CacheManagerImpl implements CacheManager { - - /** - * {@inheritDoc} - */ - public Cache createCache(String cacheName) { - return memoryService.newCache(cacheName); - } - - @Setter - private MemoryService memoryService; -} diff --git a/impl/src/java/org/sakaiproject/attendance/dao/AttendanceDao.java b/impl/src/java/org/sakaiproject/attendance/dao/AttendanceDao.java deleted file mode 100644 index e46ad97b..00000000 --- a/impl/src/java/org/sakaiproject/attendance/dao/AttendanceDao.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.dao; - -import org.sakaiproject.attendance.model.*; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -/** - * DAO interface for the Attendance Tool - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -public interface AttendanceDao { - /** - * Get an AttendanceSite - * - * @param siteId, the Sakai SiteID - * @return the AttendanceSite - */ - AttendanceSite getAttendanceSite(String siteId); - - /** - * Return attendanceSite by ID - * @param id, the attendance Site ID - * @return {@link AttendanceSite} - */ - AttendanceSite getAttendanceSite(Long id); - - /** - * Add a new AttendanceSite record to the database - * - * @param as, the AttendanceSite to add - * @return success of the operation - */ - boolean addAttendanceSite(AttendanceSite as); - - /** - * Updates an attendanceSite - * - * @param aS, the AttendanceSite with updated values - * @return success of the operation - */ - boolean updateAttendanceSite(AttendanceSite aS); - - /** - * Gets a single AttendanceEvent from the db - * - * @return the AttendanceEvent, may be null - */ - AttendanceEvent getAttendanceEvent(long id); - - /** - * get all the events by attendanceSite - * - * @param aS, the AttendanceSite - * @return a list of events or empty if no items. - */ - List getAttendanceEventsForSite(AttendanceSite aS); - - /** - * Serializable function used to save an AttendanceEvent as part of the "Take Attendance Now" feature - * - * @param e, the AttendanceEvent - * @return the Long ID of the newly added AttendanceEvent - */ - Serializable addAttendanceEventNow(AttendanceEvent e); - - /** - * Update an AttendanceEvent - * - * @param aE, the AttendanceEvent - * @return success of the operation - */ - boolean updateAttendanceEvent(AttendanceEvent aE); - - /** - * Deletes an AttendanceEvent - * - * @param aE, the AttendanceEvent - * @return success of the operation - */ - boolean deleteAttendanceEvent(AttendanceEvent aE); - - /** - * Get Status Record by ID - * - * @param id, the id of the status record - * @return the status record (may be null if DB operation fails) - */ - AttendanceRecord getStatusRecord(long id); - - /** - * Add an AttendanceRecord - * - * @param aR, the AttendanceRecord to add - * @return true if success, false if not - */ - boolean addAttendanceRecord(AttendanceRecord aR); - - /** - * Updates an AttendanceRecord - * - * @param aR, the AttendanceRecord to update with new values - * @return success of the operation - */ - boolean updateAttendanceRecord(AttendanceRecord aR); - - /** - * Update a set of AttendanceRecords - * - * @param aRs, a List of AttendanceRecords - * @return success of the operation - */ - void updateAttendanceRecords(List aRs); - - /** - * Update a set of AttendanceStatuses - * - * @param attendanceStatusList, a List of AttendanceStatuses - * @return success of the operation - */ - void updateAttendanceStatuses(List attendanceStatusList); - - /** - * Get a list of the active statuses in an Attendance Site - * - * @param attendanceSite, the AttendanceSite - * @return List of Active AttendanceStatuses, null if DB issues - */ - List getActiveStatusesForSite(AttendanceSite attendanceSite); - - /** - * Get a lit of all of the attendance statuses for a site - * - * @param attendanceSite, the AttendanceSite - * @return list of all AttendanceStatuses, null if DB issues - */ - List getAllStatusesForSite(AttendanceSite attendanceSite); - - /** - * Get an attendance status record by its id - * - * @param id, the ID of the AttendanceStatus - * @return the AttendanceStatus (null if DB issues) - */ - AttendanceStatus getAttendanceStatusById(Long id); - - /** - * Get AttendanceGrade by ID - * - * @param id, the AttendanceGrade ID - * @return the AttendanceGrade (null if DB issues) - */ - AttendanceGrade getAttendanceGrade(Long id); - - /** - * Get an AttendanceGrade - * - * @param userID, the userID of owner of Grade - * @param aS, the site the Grade is present in - * @return the AttendanceGrade, null if DB issues - */ - AttendanceGrade getAttendanceGrade(String userID, AttendanceSite aS); - - /** - * Get a list of AttendanceGrades - * - * @param aS, the AttendanceSite to get the AGs for. - * @return List of AttendanceGrades, null if DB issues - */ - List getAttendanceGrades(AttendanceSite aS); - - /** - * Add an AttendanceGrade to DB - * - * @param aG, AttendanceGrade to add - * @return success of operation - */ - boolean addAttendanceGrade(AttendanceGrade aG); - - /** - * Updates an AttendanceGrade - * - * @param aG, the AG to update - * @return success of operation - */ - boolean updateAttendanceGrade(AttendanceGrade aG); - - /** - * Get the AttendanceUserStats for a User and Site - * @param userId - * @param aS - * @return - */ - AttendanceUserStats getAttendanceUserStats(String userId, AttendanceSite aS); - - /** - * Return the AttendanceUserStats for a Site - * @param aS, the AttendanceSite to get UserStats for - * @return a List of {@link AttendanceUserStats} - */ - List getAttendanceUserStatsForSite(AttendanceSite aS); - - /** - * Update the AttendanceUserStats - * @param aUS, the AttendanceUserStats to update - * @return success or failure of the operation - */ - boolean updateAttendanceUserStats(AttendanceUserStats aUS); - - /** - * Get the AttendanceItemStats for an AttendanceEvent - * @param aE, the AttendanceEvent to get the stats for - * @return the AttendanceItemStats, null if DB issue - */ - AttendanceItemStats getAttendanceItemStats(AttendanceEvent aE); - - /** - * Update the AttendanceItemStats - * @param aIS, the AttendanceItemStats to update - * @return success or failure of the operation - */ - boolean updateAttendanceItemStats(AttendanceItemStats aIS); - - /** - * Return a batch of AttendanceSites - * @return a List of AttendanceSite IDs (max 5) - */ - List getAttendanceSiteBatch(Date syncTime, Long lastId); - - /** - * Return a list of all AttendanceSites In Sync - * @return List of IDs - */ - List getAttendanceSitesInSync(); - - /** - * Mark a set of AttendanceSites as currently syncing - * @param ids, a list of IDs to mark - * @return boolean value of success - */ - boolean markAttendanceSiteForSync(List ids, Date syncTime); - - /** - * Returns a list containing all of the grading rules for a given AttendanceSite. - * - * @param attendanceSite, An existing attendance site. - * @return A list of all of the GradingRules for the provided attendance site. - */ - List getGradingRulesForSite(AttendanceSite attendanceSite); - - /** - * Add a new GradingRule. - * - * @param gradingRule, The GradingRule to be added. - * @return The success of the save operation. - */ - boolean addGradingRule(GradingRule gradingRule); - - /** - * Delete an existing GradingRule. - * - * @param gradingRule, The GradingRule to be deleted. - * @return The success of the delete operation. - */ - boolean deleteGradingRule(GradingRule gradingRule); - - // Hibernate Query Constants - String QUERY_GET_ATTENDANCE_EVENT = "getAttendanceEvent"; - String QUERY_GET_ATTENDANCE_EVENTS_FOR_SITE = "getAttendanceEventsForSite"; - String QUERY_GET_ATTENDANCE_EVENTS = "getAttendanceEvents"; - - String QUERY_GET_SITE_BY_SITE_ID = "getSiteBySiteID"; - String QUERY_GET_SITE_BY_ID = "getSiteByID"; - - String QUERY_GET_ATTENDANCE_RECORD = "getAttendanceRecord"; - String QUERY_GET_ATTENDANCE_RECORDS_FOR_ATTENDANCE_EVENT = "getRecordsForAttendanceEvent"; - - String QUERY_GET_ATTENDANCE_STATUS = "getAttendanceStatus"; - String QUERY_GET_ACTIVE_ATTENDANCE_STATUSES_FOR_SITE = "getActiveAttendanceStatusesForSite"; - String QUERY_GET_ALL_ATTENDANCE_STATUSES_FOR_SITE = "getAllAttendanceStatusesForSite"; - - String QUERY_GET_ATTENDANCE_GRADES_FOR_SITE = "getAttendanceGradesForSite"; - String QUERY_GET_ATTENDANCE_GRADE_BY_ID = "getAttendanceGradeByID"; - String QUERY_GET_ATTENDANCE_GRADE = "getAttendanceGrade"; - - String QUERY_GET_ATTENDANCE_USER_STATS = "getAttendanceUserStats"; - String QUERY_GET_ATTENDANCE_USER_STATS_FOR_SITE = "getAttendanceUserStatsForSite"; - String QUERY_GET_ATTENDANCE_ITEM_STATS = "getAttendanceItemStats"; - - // Attendance Sync for Statistics Queries - String QUERY_GET_ATTENDANCE_SITE_BATCH = "getAttendanceSiteBatch"; - String QUERY_GET_ATTENDANCE_SITES_IN_SYNC = "getAttendanceSitesInSync"; - String QUERY_MARK_ATTENDANCE_SITE_IN_SYNC = "markAttendanceSiteForSync"; - - String QUERY_GET_GRADING_RULES_FOR_SITE = "getGradingRulesForSite"; - - // Hibernate Object Fields - String ID = "id"; - String IDS = "ids"; - String USER_ID = "userID"; - String SITE_ID = "siteID"; - String ATTENDANCE_SITE = "attendanceSite"; - String ATTENDANCE_EVENT = "attendanceEvent"; - String SYNC_TIME = "syncTime"; -} diff --git a/impl/src/java/org/sakaiproject/attendance/dao/impl/AttendanceDaoImpl.java b/impl/src/java/org/sakaiproject/attendance/dao/impl/AttendanceDaoImpl.java deleted file mode 100644 index 5591d5c5..00000000 --- a/impl/src/java/org/sakaiproject/attendance/dao/impl/AttendanceDaoImpl.java +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.dao.impl; - -import org.hibernate.HibernateException; -import org.hibernate.Session; -import org.hibernate.query.Query; -import org.hibernate.type.LongType; -import org.hibernate.type.StringType; -import org.sakaiproject.attendance.dao.AttendanceDao; -import org.sakaiproject.attendance.model.*; -import org.springframework.dao.DataAccessException; -import org.springframework.orm.hibernate5.HibernateCallback; -import org.springframework.orm.hibernate5.support.HibernateDaoSupport; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -import lombok.extern.slf4j.Slf4j; - -/** - * Implementation of AttendanceDao - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - * @author David Bauer [dbauer1 (at) udayton (dot) edu] - * @author Steve Swinsburg (steve.swinsburg@gmail.com) - */ -@Slf4j -public class AttendanceDaoImpl extends HibernateDaoSupport implements AttendanceDao { - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public AttendanceSite getAttendanceSite(final String siteID) { - if(log.isDebugEnabled()){ - log.debug("getSiteBySite_ID "); - } - - HibernateCallback hcb = new HibernateCallback() { - @Override - public Object doInHibernate(Session session) throws HibernateException { - Query q = session.getNamedQuery(QUERY_GET_SITE_BY_SITE_ID); - q.setParameter(SITE_ID, siteID, new StringType()); - return q.uniqueResult(); - } - }; - - return (AttendanceSite) getHibernateTemplate().execute(hcb); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public AttendanceSite getAttendanceSite(final Long id) { - log.debug("getAttendanceSite by ID: " + id); - - return (AttendanceSite) getByIDHelper(id, QUERY_GET_SITE_BY_ID); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public boolean addAttendanceSite(AttendanceSite aS) { - if(log.isDebugEnabled()) { - log.debug("addAttendanceSite ( " + aS.toString() + ")"); - } - - try { - getHibernateTemplate().save(aS); - return true; - } catch (DataAccessException de) { - log.error("addAttendanceSite failed", de); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceSite(AttendanceSite aS) { - try{ - getHibernateTemplate().saveOrUpdate(aS); - return true; - } catch (DataAccessException e) { - log.error("updateAttendanceSite aS '" + aS.getSiteID() + "' failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public AttendanceEvent getAttendanceEvent(final long id) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceEvent()" + String.valueOf(id)); - } - - return (AttendanceEvent) getByIDHelper(id, QUERY_GET_ATTENDANCE_EVENT); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAttendanceEventsForSite(final AttendanceSite aS) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceEventsForSite(AttendanceSite id)"); - } - - return getEventsForAttendanceSiteHelper(aS); - } - - /** - * {@inheritDoc} - */ - public Serializable addAttendanceEventNow(AttendanceEvent attendanceEvent) { - - if(log.isDebugEnabled()) { - log.debug("addAttendanceEventNow( " + attendanceEvent.toString() + ")"); - } - - try{ - return getHibernateTemplate().save(attendanceEvent); - } catch (DataAccessException de) { - log.error("addAttendanceEventNow failed.", de); - return null; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceEvent(AttendanceEvent aE) { - if(log.isDebugEnabled()) { - log.debug("updateAttendanceEvent aE: " + aE.getName()); - } - - try{ - getHibernateTemplate().saveOrUpdate(aE); - return true; - } catch (DataAccessException e){ - log.error("updateAttendanceEvent failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean deleteAttendanceEvent(AttendanceEvent aE) { - if(log.isDebugEnabled()) { - log.debug("deleteAttendanceEvent aE: " + aE.getName()); - } - - if(aE.getStats() !=null && aE.getStats().getId() == null){ - aE.setStats(null); - } - - try { - getHibernateTemplate().delete(getHibernateTemplate().merge(aE)); - return true; - } catch (DataAccessException e) { - log.error("deleteAttendanceEvent, " + aE.getId() + ", failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public AttendanceRecord getStatusRecord(final long id) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceRecord()" + String.valueOf(id)); - } - - return (AttendanceRecord) getByIDHelper(id, QUERY_GET_ATTENDANCE_RECORD); - } - - /** - * {@inheritDoc} - */ - public boolean addAttendanceRecord(AttendanceRecord aR) { - if(log.isDebugEnabled()){ - log.debug("addAttendanceRecord sR for User '" + aR.getUserID() + "' event " + aR.getAttendanceEvent().getName() + " with Status " + aR.getStatus().toString()); - } - - try { - getHibernateTemplate().save(aR); - return true; - } catch (DataAccessException de) { - log.error("addAttendanceRecord failed.", de); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceRecord(AttendanceRecord aR) { - try { - getHibernateTemplate().saveOrUpdate(aR); - return true; - } catch (Exception e) { - log.error("update attendanceRecord failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public void updateAttendanceRecords(List aRs) { - for(AttendanceRecord aR : aRs) { - try { - getHibernateTemplate().saveOrUpdate(aR); - log.debug("save attendanceRecord id: " + aR.getId()); - } catch (Exception e) { - log.error("update attendanceRecords failed.", e); - } - } - } - - /** - * {@inheritDoc} - */ - public void updateAttendanceStatuses(List attendanceStatusList) { - for(AttendanceStatus aS : attendanceStatusList) { - try { - getHibernateTemplate().saveOrUpdate(aS); - log.debug("AttendanceStatus saved, id: " + aS.getId()); - } catch (Exception e) { - log.error("update attendanceStatuses failed.", e); - } - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getActiveStatusesForSite(final AttendanceSite attendanceSite) { - if(log.isDebugEnabled()){ - log.debug("getActiveStatusesForSite(AttendanceSite " + attendanceSite.getSiteID() + " )"); - } - - try { - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ACTIVE_ATTENDANCE_STATUSES_FOR_SITE) - .setParameter(ATTENDANCE_SITE, attendanceSite) - .getResultList()); - } catch (DataAccessException e) { - log.error("getActiveStatusesForSite failed", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAllStatusesForSite(final AttendanceSite attendanceSite) { - if(log.isDebugEnabled()){ - log.debug("getAllStatusesForSite(AttendanceSite attendanceSite)"); - } - - try { - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ALL_ATTENDANCE_STATUSES_FOR_SITE) - .setParameter(ATTENDANCE_SITE, attendanceSite) - .getResultList()); - } catch (DataAccessException e) { - log.error("getAllStatusesForSite failed", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - public AttendanceStatus getAttendanceStatusById(final Long id) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceStatus()" + String.valueOf(id)); - } - - return (AttendanceStatus) getByIDHelper(id, QUERY_GET_ATTENDANCE_STATUS); - } - - /** - * {@inheritDoc} - */ - public AttendanceGrade getAttendanceGrade(final Long id) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceGrade, id: " + id.toString()); - } - - return (AttendanceGrade) getByIDHelper(id, QUERY_GET_ATTENDANCE_GRADE_BY_ID); - } - - /** - * {@inheritDoc} - */ - public AttendanceGrade getAttendanceGrade(final String userID, final AttendanceSite aS) { - if(log.isDebugEnabled()) { - log.debug("getAttendanceGrades for user " + userID + " in site " + aS.getSiteID()); - } - - try{ - return (AttendanceGrade) getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_GRADE) - .setParameter(ATTENDANCE_SITE, aS) - .setParameter(USER_ID, userID) - .uniqueResult()); - } catch (DataAccessException e) { - log.error("Failed to get AttendanceGrade for " + userID + " in " + aS.getSiteID()); - return null; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAttendanceGrades(final AttendanceSite aS) { - if(log.isDebugEnabled()){ - log.debug("getAttendanceGrades for: " + aS.getSiteID()); - } - - try{ - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_GRADES_FOR_SITE) - .setParameter(ATTENDANCE_SITE, aS) - .getResultList()); - } catch (DataAccessException e) { - log.error("DataAccessException getting AttendanceGrades for " + aS.getSiteID() + ". E:", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - public boolean addAttendanceGrade(AttendanceGrade aG) { - if(log.isDebugEnabled()){ - log.debug("addAttendanceGrade for User '" + aG.getUserID() + "' grade " + aG.getGrade() + " for site " + aG.getAttendanceSite().getSiteID()); - } - - try { - getHibernateTemplate().save(aG); - return true; - } catch (DataAccessException de) { - log.error("addAttendanceGrade failed.", de); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceGrade(AttendanceGrade aG) { - if(log.isDebugEnabled()){ - log.debug("updateAttendanceGrade for User '" + aG.getUserID() + "' grade " + aG.getGrade() + " for site " + aG.getAttendanceSite().getSiteID()); - } - - try { - getHibernateTemplate().saveOrUpdate(aG); - return true; - } catch (DataAccessException de) { - log.error("updateAttendanceGrade failed.", de); - return false; - } - } - - /** - * {@inheritDoc} - */ - public AttendanceUserStats getAttendanceUserStats(final String userId, final AttendanceSite aS) { - log.debug("getAttendanceUserStats for User '" + userId + "' and Site: '" + aS.getSiteID() + "'."); - - try{ - return (AttendanceUserStats) getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_USER_STATS) - .setParameter(ATTENDANCE_SITE, aS) - .setParameter(USER_ID, userId) - .uniqueResult()); - } catch (DataAccessException e) { - log.error("DataAccessException getting AttendanceUserStats for User '" + userId + "' and Site: '" + aS.getSiteID() + "'.", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAttendanceUserStatsForSite(final AttendanceSite aS) { - log.debug("getAttendanceUserStatsForSite for site: " + aS.getSiteID()); - - try{ - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_USER_STATS_FOR_SITE) - .setParameter(ATTENDANCE_SITE, aS) - .getResultList()); - } catch (DataAccessException e) { - log.error("DataAccessException getting AttendanceUserStats for Site: " + aS.getSiteID() + ".", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceUserStats(AttendanceUserStats aUS) { - log.debug("updateAttendanceUserStats for User '" + aUS.getUserID() + "' and Site: '" + aUS.getAttendanceSite().getSiteID() + "'."); - - try { - getHibernateTemplate().saveOrUpdate(aUS); - return true; - } catch (DataAccessException e) { - log.error("updateAttendanceUserStats, id: '" + aUS.getId() + "' failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean addGradingRule(GradingRule gradingRule) { - if (log.isDebugEnabled()) { - log.debug("add grading rule to site " + gradingRule.getAttendanceSite().getSiteID() + - " status: " + gradingRule.getStatus() + - " range: " + gradingRule.getStartRange() + - " - " + gradingRule.getEndRange() + - " points: " + gradingRule.getPoints()); - } - try { - getHibernateTemplate().save(gradingRule); - return true; - } catch (DataAccessException dae) { - log.error("addGradingRule failed.", dae); - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean deleteGradingRule(GradingRule gradingRule) { - log.debug("Delete grading rule from site " + gradingRule.getAttendanceSite().getSiteID() + " grading rule: " + gradingRule.getId()); - - try { - getHibernateTemplate().delete(getHibernateTemplate().merge(gradingRule)); - return true; - } catch (DataAccessException e) { - log.error("deleteGradingRule, " + gradingRule.getId() + ", failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public AttendanceItemStats getAttendanceItemStats(AttendanceEvent aE) { - log.debug("getAttendanceUserStats for Event '" + aE.getName() + "' and Site: '" + aE.getAttendanceSite().getSiteID() + "'."); - - try{ - return (AttendanceItemStats) getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_ITEM_STATS) - .setParameter(ATTENDANCE_EVENT, aE) - .uniqueResult()); - } catch (DataAccessException e) { - log.error("DataAccessException getting AttendanceItemStats for Event '" + aE.getName() + "' and Site: '" + aE.getAttendanceSite().getSiteID() + "'.", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - public boolean updateAttendanceItemStats(AttendanceItemStats aIS) { - log.debug("updateAttendanceItemStats, '" + aIS.getId() + "', for Event '" + aIS.getAttendanceEvent().getName() + "' and site: '" + aIS.getAttendanceEvent().getAttendanceSite().getSiteID() + "'."); - - try { - getHibernateTemplate().saveOrUpdate(aIS); - return true; - } catch (DataAccessException e) { - log.error("updateAttendanceItemStats, '" + aIS.getId() + "' failed.", e); - return false; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getGradingRulesForSite(AttendanceSite attendanceSite) { - if(log.isDebugEnabled()){ - log.debug("getGradingRulesForSite(AttendanceSite " + attendanceSite.getSiteID() + " )"); - } - - try { - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_GRADING_RULES_FOR_SITE) - .setParameter(ATTENDANCE_SITE, attendanceSite) - .getResultList()); - } catch (DataAccessException e) { - log.error("getGradingRulesForSite failed", e); - return null; - } - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAttendanceSiteBatch(final Date syncTime, final Long lastId) { - final HibernateCallback> hcb = new HibernateCallback>() { - @Override - public List doInHibernate(Session session) throws HibernateException { - Query q = session.getNamedQuery(QUERY_GET_ATTENDANCE_SITE_BATCH); - q.setTimestamp(SYNC_TIME, syncTime); - q.setLong(ID, lastId); - q.setMaxResults(5); - return q.list(); - } - }; - - return getHibernateTemplate().execute(hcb); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getAttendanceSitesInSync() { - final HibernateCallback> hcb = new HibernateCallback>() { - @Override - public List doInHibernate(Session session) throws HibernateException { - Query q = session.getNamedQuery(QUERY_GET_ATTENDANCE_SITES_IN_SYNC); - return q.list(); - } - }; - - return getHibernateTemplate().execute(hcb); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public boolean markAttendanceSiteForSync(final List ids, final Date syncTime) { - final HibernateCallback hcb = new HibernateCallback() { - @Override - public Integer doInHibernate(Session session) throws HibernateException { - Query q = session.getNamedQuery(QUERY_MARK_ATTENDANCE_SITE_IN_SYNC); - q.setParameterList(IDS, ids); - q.setTimestamp(SYNC_TIME, syncTime); - return q.executeUpdate(); - } - }; - - return getHibernateTemplate().execute(hcb).equals(ids.size()); - } - - /** - * init - */ - public void init() { - log.debug("AttendanceDaoImpl init()"); - } - - @SuppressWarnings("unchecked") - private List getEventsForAttendanceSiteHelper(final AttendanceSite aS){ - if(log.isDebugEnabled()){ - log.debug("getAttendanceEventsForSiteHelper()"); - } - - try { - return getHibernateTemplate().execute(session -> session - .getNamedQuery(QUERY_GET_ATTENDANCE_EVENTS_FOR_SITE) - .setParameter(ATTENDANCE_SITE, aS) - .getResultList()); - - } catch (DataAccessException e) { - log.error("getEventsForAttendanceSiteHelper failed", e); - return null; - } - } - - // Generic Function to get something by it's ID. - private Object getByIDHelper(final long id, final String queryString) { - if(log.isDebugEnabled()) { - log.debug("getByIDHelper() id: '" + String.valueOf(id) + "' String: " + queryString); - } - - try { - return getHibernateTemplate().execute(session -> session - .getNamedQuery(queryString) - .setParameter(ID, id, new LongType()) - .setMaxResults(1) - .uniqueResult()); - - } catch (DataAccessException e) { - log.error("getByIDHelper for " + queryString + " failed", e); - return null; - } - } - -} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/AttendanceGradebookProviderImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/AttendanceGradebookProviderImpl.java index 7a5a8ee2..27221c88 100644 --- a/impl/src/java/org/sakaiproject/attendance/impl/AttendanceGradebookProviderImpl.java +++ b/impl/src/java/org/sakaiproject/attendance/impl/AttendanceGradebookProviderImpl.java @@ -19,16 +19,15 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.sakaiproject.attendance.api.AttendanceGradebookProvider; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.logic.SakaiProxy; -import org.sakaiproject.attendance.model.AttendanceGrade; -import org.sakaiproject.attendance.model.AttendanceSite; -import org.sakaiproject.attendance.util.AttendanceConstants; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.logic.SakaiProxy; +import org.sakaiproject.attendance.api.model.AttendanceGrade; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.util.AttendanceConstants; import org.sakaiproject.grading.api.AssessmentNotFoundException; import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.GradingService; -import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolManager; import java.util.HashMap; diff --git a/impl/src/java/org/sakaiproject/attendance/export/PDFEventExporterImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/export/PDFEventExporterImpl.java similarity index 87% rename from impl/src/java/org/sakaiproject/attendance/export/PDFEventExporterImpl.java rename to impl/src/java/org/sakaiproject/attendance/impl/export/PDFEventExporterImpl.java index 1d48c3d8..062b4837 100644 --- a/impl/src/java/org/sakaiproject/attendance/export/PDFEventExporterImpl.java +++ b/impl/src/java/org/sakaiproject/attendance/impl/export/PDFEventExporterImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.sakaiproject.attendance.export; +package org.sakaiproject.attendance.impl.export; import com.lowagie.text.*; import com.lowagie.text.pdf.PdfPCell; @@ -22,23 +22,26 @@ import com.lowagie.text.pdf.PdfWriter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.sakaiproject.attendance.export.util.SortNameUserComparator; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.logic.SakaiProxy; -import org.sakaiproject.attendance.model.AttendanceEvent; -import org.sakaiproject.attendance.model.AttendanceStatus; -import org.sakaiproject.attendance.model.Status; +import org.sakaiproject.attendance.api.export.PDFEventExporter; +import org.sakaiproject.attendance.impl.export.util.SortNameUserComparator; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.logic.SakaiProxy; +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceStatus; +import org.sakaiproject.attendance.api.model.Status; +import org.sakaiproject.time.api.UserTimeService; import org.sakaiproject.user.api.User; import java.awt.Color; import java.io.OutputStream; -import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.Collections; -import java.util.Date; import java.util.List; /** - * Implementation of PDFEventExporter, {@link org.sakaiproject.attendance.export.PDFEventExporter} + * Implementation of PDFEventExporter, {@link PDFEventExporter} * * @author David Bauer [dbauer1 (at) udayton (dot) edu] */ @@ -84,10 +87,10 @@ public void createAttendanceSheetPdf(AttendanceEvent event, OutputStream outputS private void buildDocumentShell(OutputStream outputStream, boolean isSignInSheet) { String eventName = event.getName(); - Date eventDate = event.getStartDateTime(); + Instant eventDate = event.getStartDateTime(); - - SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d, yyyy h:mm a"); + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.SHORT) + .withZone(userTimeService.getLocalTimeZone().toZoneId()); try { PdfWriter.getInstance(document, outputStream); @@ -101,7 +104,7 @@ private void buildDocumentShell(OutputStream outputStream, boolean isSignInSheet document.add(title); - String eventDateString = eventDate==null?"":" (" + dateFormat.format(eventDate) + ")"; + String eventDateString = eventDate==null?"":" (" + formatter.format(eventDate) + ")"; Paragraph eventHeader = new Paragraph(eventName + eventDateString, h3); eventHeader.setSpacingBefore(14); @@ -250,4 +253,7 @@ private String getStatusString(Status s, int numStatuses) { @Setter private AttendanceLogic attendanceLogic; + @Setter + private UserTimeService userTimeService; + } diff --git a/impl/src/java/org/sakaiproject/attendance/export/util/SortNameUserComparator.java b/impl/src/java/org/sakaiproject/attendance/impl/export/util/SortNameUserComparator.java similarity index 94% rename from impl/src/java/org/sakaiproject/attendance/export/util/SortNameUserComparator.java rename to impl/src/java/org/sakaiproject/attendance/impl/export/util/SortNameUserComparator.java index cf7cc9e3..ab888f28 100644 --- a/impl/src/java/org/sakaiproject/attendance/export/util/SortNameUserComparator.java +++ b/impl/src/java/org/sakaiproject/attendance/impl/export/util/SortNameUserComparator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.sakaiproject.attendance.export.util; +package org.sakaiproject.attendance.impl.export.util; import org.sakaiproject.user.api.User; import java.util.Comparator; diff --git a/impl/src/java/org/sakaiproject/attendance/logic/AttendanceLogicImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/logic/AttendanceLogicImpl.java similarity index 65% rename from impl/src/java/org/sakaiproject/attendance/logic/AttendanceLogicImpl.java rename to impl/src/java/org/sakaiproject/attendance/impl/logic/AttendanceLogicImpl.java index 2989c305..335a3fde 100644 --- a/impl/src/java/org/sakaiproject/attendance/logic/AttendanceLogicImpl.java +++ b/impl/src/java/org/sakaiproject/attendance/impl/logic/AttendanceLogicImpl.java @@ -14,21 +14,24 @@ * limitations under the License. */ -package org.sakaiproject.attendance.logic; +package org.sakaiproject.attendance.impl.logic; -import java.io.Serializable; import java.util.*; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.sakaiproject.attendance.api.AttendanceGradebookProvider; -import org.sakaiproject.attendance.dao.AttendanceDao; -import org.sakaiproject.attendance.model.*; -import org.sakaiproject.entity.api.Entity; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.logic.SakaiProxy; +import org.sakaiproject.attendance.api.model.*; +import org.sakaiproject.attendance.api.model.stats.AttendanceItemStats; +import org.sakaiproject.attendance.api.model.stats.AttendanceStats; +import org.sakaiproject.attendance.api.model.stats.AttendanceUserStats; +import org.sakaiproject.attendance.api.repository.*; import org.sakaiproject.entity.api.EntityManager; -import org.sakaiproject.entity.api.EntityProducer; import org.sakaiproject.entity.api.EntityTransferrer; import org.sakaiproject.user.api.User; @@ -40,13 +43,32 @@ * @author Steve Swinsburg (steve.swinsburg@gmail.com) */ @Slf4j +@Setter public class AttendanceLogicImpl implements AttendanceLogic, EntityTransferrer { + private AttendanceEventRepository attendanceEventRepository; + + private AttendanceGradeRepository attendanceGradeRepository; + + private AttendanceRecordRepository attendanceRecordRepository; + + private AttendanceSiteRepository attendanceSiteRepository; + + private AttendanceStatusRepository attendanceStatusRepository; + + private GradingRuleRepository gradingRuleRepository; + + private SakaiProxy sakaiProxy; + + private AttendanceGradebookProvider attendanceGradebookProvider; + + private EntityManager entityManager; + /** * {@inheritDoc} - */ + */ public AttendanceSite getAttendanceSite(String siteID) { - AttendanceSite attendanceSite = dao.getAttendanceSite(siteID); + AttendanceSite attendanceSite = attendanceSiteRepository.findBySiteId(siteID); if (attendanceSite == null) { attendanceSite = new AttendanceSite(siteID); @@ -57,7 +79,7 @@ public AttendanceSite getAttendanceSite(String siteID) { } // We need to re-load the AttendanceSite because of the status creation above - attendanceSite = dao.getAttendanceSite(siteID); + attendanceSite = attendanceSiteRepository.findBySiteId(siteID); } return attendanceSite; @@ -66,12 +88,11 @@ public AttendanceSite getAttendanceSite(String siteID) { /** * {@inheritDoc} */ - public boolean updateAttendanceSite(AttendanceSite aS) throws IllegalArgumentException { + public AttendanceSite updateAttendanceSite(AttendanceSite aS) throws IllegalArgumentException { if(aS == null) { throw new IllegalArgumentException("AttendanceSite must not be null"); } - - return dao.updateAttendanceSite(aS); + return attendanceSiteRepository.save(aS); } /** @@ -86,73 +107,60 @@ public AttendanceSite getCurrentAttendanceSite() { * {@inheritDoc} */ public AttendanceEvent getAttendanceEvent(long id) { - return dao.getAttendanceEvent(id); + return attendanceEventRepository.findById(id).orElseThrow( + () -> new IllegalArgumentException("No event for id " + id) + ); } /** * {@inheritDoc} */ public List getAttendanceEventsForSite(AttendanceSite aS) { - return safeAttendanceEventListReturn(dao.getAttendanceEventsForSite(aS)); + return attendanceEventRepository.findAllByAttendanceSite(aS); } /** * {@inheritDoc} */ public List getAttendanceEventsForCurrentSite(){ - return getAttendanceEventsForSite(getCurrentAttendanceSite()); + return attendanceEventRepository.findAllByAttendanceSite(getCurrentAttendanceSite()); } /** * {@inheritDoc} */ - public Serializable addAttendanceEventNow(AttendanceEvent e) { - return dao.addAttendanceEventNow(e); + public AttendanceEvent addAttendanceEventNow(AttendanceEvent e) { + return attendanceEventRepository.save(e); } /** * {@inheritDoc} */ - public boolean updateAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException { + public AttendanceEvent updateAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException { if(aE == null) { throw new IllegalArgumentException("AttendanceEvent is null"); } - - return dao.updateAttendanceEvent(aE); + return attendanceEventRepository.save(aE); } /** * {@inheritDoc} */ - public boolean deleteAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException { + public void deleteAttendanceEvent(AttendanceEvent aE) throws IllegalArgumentException { if(aE == null) { throw new IllegalArgumentException("AttendanceEvent is null"); } - - Set records = aE.getRecords(); - AttendanceSite site = aE.getAttendanceSite(); - for(AttendanceRecord record : records) { - AttendanceUserStats userStats = dao.getAttendanceUserStats(record.getUserID(), site); - if(userStats != null) { - Status recordStatus = record.getStatus(); - removeStatusFromStats(userStats, recordStatus); - - dao.updateAttendanceUserStats(userStats); - } - } - - return dao.deleteAttendanceEvent(aE); + attendanceEventRepository.deleteById(aE.getId()); } /** * {@inheritDoc} */ - public AttendanceRecord getAttendanceRecord(Long id) { + public Optional getAttendanceRecord(Long id) { if(id == null) { - return null; + return Optional.empty(); } - - return dao.getStatusRecord(id); + return attendanceRecordRepository.findById(id); } /** @@ -180,34 +188,32 @@ public List getActiveStatusesForCurrentSite() { * {@inheritDoc} */ public List getActiveStatusesForSite(AttendanceSite attendanceSite) { - return safeAttendanceStatusListReturn(dao.getActiveStatusesForSite(attendanceSite)); + return attendanceStatusRepository.findAllActiveByAttendanceSite(attendanceSite); } /** * {@inheritDoc} */ public List getAllStatusesForSite(AttendanceSite attendanceSite) { - return safeAttendanceStatusListReturn(dao.getAllStatusesForSite(attendanceSite)); + return attendanceStatusRepository.findAllByAttendanceSite(attendanceSite); } /** * {@inheritDoc} */ - public AttendanceStatus getAttendanceStatusById(Long id) { - return dao.getAttendanceStatusById(id); + public Optional getAttendanceStatusById(Long id) { + return attendanceStatusRepository.findById(id); } /** * {@inheritDoc} */ - public boolean updateAttendanceRecord(AttendanceRecord aR, Status oldStatus) throws IllegalArgumentException { + public AttendanceRecord updateAttendanceRecord(AttendanceRecord aR, Status oldStatus) throws IllegalArgumentException { if(aR == null) { throw new IllegalArgumentException("AttendanceRecord cannot be null"); } - - updateStats(aR, oldStatus); regradeForAttendanceRecord(aR); - return dao.updateAttendanceRecord(aR); + return attendanceRecordRepository.save(aR); } /** @@ -216,18 +222,12 @@ public boolean updateAttendanceRecord(AttendanceRecord aR, Status oldStatus) thr public List updateAttendanceRecordsForEvent(AttendanceEvent aE, Status s) { aE = getAttendanceEvent(aE.getId()); List records = new ArrayList<>(aE.getRecords()); - if(records.isEmpty()) { return generateAttendanceRecords(aE, s); } - - Status oldStatus; for(AttendanceRecord aR : records) { - oldStatus = aR.getStatus(); aR.setStatus(s); - updateStats(aR, oldStatus); } - return records; } @@ -238,7 +238,6 @@ public void updateAttendanceRecordsForEvent(AttendanceEvent aE, Status s, String aE = getAttendanceEvent(aE.getId()); //why are we getting this as a new event when it's a parameter passed in already? List allRecords = new ArrayList<>(aE.getRecords()); List recordsToUpdate = new ArrayList<>(); - if(allRecords.isEmpty()) { allRecords = generateAttendanceRecords(aE, null); } else { @@ -246,7 +245,6 @@ public void updateAttendanceRecordsForEvent(AttendanceEvent aE, Status s, String allRecords.forEach(record -> ids.remove(record.getUserID())); allRecords.addAll(updateMissingRecordsForEvent(aE, null, ids)); } - if(groupId == null || groupId.isEmpty()) { recordsToUpdate.addAll(allRecords); } else { @@ -260,48 +258,11 @@ public void updateAttendanceRecordsForEvent(AttendanceEvent aE, Status s, String } } } - - Status oldStatus; - int present =0, unexcused =0, excused =0, late=0, leftEarly =0; for(AttendanceRecord aR : recordsToUpdate) { - oldStatus = aR.getStatus(); - if (oldStatus == Status.PRESENT) { - present++; - } else if (oldStatus == Status.UNEXCUSED_ABSENCE) { - unexcused++; - } else if (oldStatus == Status.EXCUSED_ABSENCE) { - excused++; - } else if (oldStatus == Status.LATE) { - late++; - } else if (oldStatus == Status.LEFT_EARLY ) { - leftEarly++; - } aR.setStatus(s); - updateUserStats(aR, oldStatus); regradeForAttendanceRecord(aR); - dao.updateAttendanceRecord(aR); //change the actual data for the student we've just iterated past. This saves looping through it again as part of dao.updateAttendanceRecords on a whole array. - } - - AttendanceItemStats itemStats = getStatsForEvent(aE); - itemStats.setPresent(itemStats.getPresent() - present); - itemStats.setUnexcused(itemStats.getUnexcused() - unexcused); - itemStats.setExcused(itemStats.getExcused() - excused); - itemStats.setLate(itemStats.getLate() - late); - itemStats.setLeftEarly(itemStats.getLeftEarly() - leftEarly); - - if (s == Status.PRESENT) { - itemStats.setPresent(itemStats.getPresent()+ recordsToUpdate.size()); - } else if (s == Status.UNEXCUSED_ABSENCE) { - itemStats.setUnexcused(itemStats.getUnexcused() + recordsToUpdate.size()); - } else if (s == Status.EXCUSED_ABSENCE) { - itemStats.setExcused(itemStats.getExcused() + recordsToUpdate.size()); - } else if (s == Status.LATE) { - itemStats.setLate(itemStats.getLate() + recordsToUpdate.size()); - } else if (s == Status.LEFT_EARLY) { - itemStats.setLeftEarly(itemStats.getLeftEarly() + recordsToUpdate.size()); } - - dao.updateAttendanceItemStats(itemStats); + attendanceRecordRepository.saveAll(recordsToUpdate); } /** @@ -333,14 +294,7 @@ public List updateMissingRecordsForEvent(AttendanceEvent atten * {@inheritDoc} */ public AttendanceItemStats getStatsForEvent(AttendanceEvent event) { - AttendanceItemStats itemStats = dao.getAttendanceItemStats(event); - - if(itemStats == null) { - itemStats = new AttendanceItemStats(event); - } - event.setStats(itemStats); - - return itemStats; + return attendanceEventRepository.calculateStatsForEvent(event); } /** @@ -354,13 +308,7 @@ public AttendanceUserStats getStatsForUser(String userId) { * {@inheritDoc} */ public AttendanceUserStats getStatsForUser(String userId, AttendanceSite aS) { - AttendanceUserStats userStats = dao.getAttendanceUserStats(userId, aS); - - if(userStats == null) { - userStats = new AttendanceUserStats(userId, aS); - } - - return userStats; + return attendanceSiteRepository.calculateAttendanceUserStats(userId, aS); } /** @@ -374,67 +322,40 @@ public List getUserStatsForCurrentSite(String group) { * {@inheritDoc} */ public List getUserStatsForSite(AttendanceSite aS, String group) { - List userStatsList = dao.getAttendanceUserStatsForSite(aS); List users; if(group == null || group.isEmpty()) { users = sakaiProxy.getCurrentSiteMembershipIds(); } else { users = sakaiProxy.getGroupMembershipIds(aS.getSiteID(), group); } - List missingUsers = new ArrayList<>(); List returnList = new ArrayList<>(users.size()); - - if(userStatsList != null && !userStatsList.isEmpty()) { - users.forEach(user -> { - boolean found = false; - for(AttendanceUserStats userStat : userStatsList) { - if(user.equals(userStat.getUserID())) { - found = true; - returnList.add(userStat); - } - } - if(!found) { - missingUsers.add(user); - } - }); - } else { - missingUsers.addAll(users); - } - - if (!missingUsers.isEmpty()) { - missingUsers.forEach(user -> returnList.add(new AttendanceUserStats(user, aS))); - } - + users.forEach(user -> { + returnList.add(attendanceSiteRepository.calculateAttendanceUserStats(user, aS)); + }); return returnList; } /** * {@inheritDoc} */ - public AttendanceGrade getAttendanceGrade(Long id) throws IllegalArgumentException { + public Optional getAttendanceGrade(Long id) throws IllegalArgumentException { if(id == null) { throw new IllegalArgumentException("ID must not be null"); } - - return dao.getAttendanceGrade(id); + return attendanceGradeRepository.findById(id); } /** * {@inheritDoc} */ - public AttendanceGrade getAttendanceGrade(String uID) throws IllegalArgumentException { - if(uID == null || uID.isEmpty()) { + public AttendanceGrade getAttendanceGrade(String userId) throws IllegalArgumentException { + if(StringUtils.isBlank(userId)) { throw new IllegalArgumentException("uID must not be null or empty."); } - final AttendanceSite currentSite = getCurrentAttendanceSite(); - final AttendanceGrade grade = dao.getAttendanceGrade(uID, currentSite); - - if(grade == null) { - return new AttendanceGrade(currentSite, uID); - } - - return grade; + return attendanceGradeRepository.findByAttendanceSiteAndUserId(currentSite, userId).orElse( + new AttendanceGrade(currentSite, userId) + ); } /** @@ -443,7 +364,7 @@ public AttendanceGrade getAttendanceGrade(String uID) throws IllegalArgumentExce public Map getAttendanceGrades() { Map aGHashMap = new HashMap<>(); AttendanceSite aS = getCurrentAttendanceSite(); - List aGs = dao.getAttendanceGrades(aS); + List aGs = attendanceGradeRepository.findAllByAttendanceSite(aS); if(aGs == null || aGs.isEmpty()) { aGs = generateAttendanceGrades(aS); } else { @@ -487,18 +408,19 @@ public Map getAttendanceGradeScores() { /** * {@inheritDoc} */ - public boolean updateAttendanceGrade(AttendanceGrade aG) throws IllegalArgumentException { + public AttendanceGrade updateAttendanceGrade(AttendanceGrade aG) throws IllegalArgumentException { if(aG == null) { throw new IllegalArgumentException("AttendanceGrade cannot be null"); } - boolean saved = dao.updateAttendanceGrade(aG); + AttendanceGrade savedGrade = attendanceGradeRepository.save(aG); - if(saved && aG.getAttendanceSite().getSendToGradebook()) { - return attendanceGradebookProvider.sendToGradebook(aG); + if(aG.getAttendanceSite().getSendToGradebook()) { + if (!attendanceGradebookProvider.sendToGradebook(aG)) { + log.warn("Unable to send attendance grade to the Gradebook in site " + aG.getAttendanceSite().getSiteID()); + } } - - return saved; + return savedGrade; } /** @@ -525,22 +447,22 @@ public int getStatsForStatus(AttendanceStats stats, Status status) { /** * {@inheritDoc} */ - public boolean addGradingRule(GradingRule gradingRule) { - return gradingRule != null && dao.addGradingRule(gradingRule); + public GradingRule addGradingRule(GradingRule gradingRule) { + return gradingRuleRepository.save(gradingRule); } /** * {@inheritDoc} */ - public boolean deleteGradingRule(GradingRule gradingRule) { - return gradingRule != null && dao.deleteGradingRule(gradingRule); + public void deleteGradingRule(GradingRule gradingRule) { + gradingRuleRepository.deleteById(gradingRule.getId()); } /** * {@inheritDoc} */ public List getGradingRulesForSite(AttendanceSite attendanceSite) { - return dao.getGradingRulesForSite(attendanceSite); + return gradingRuleRepository.findAllByAttendanceSite(attendanceSite); } /** @@ -571,17 +493,9 @@ public Double regrade(AttendanceGrade attendanceGrade, boolean saveGrade) { return grade; } - /** - * init - perform any actions required here for when this bean starts up - */ - public void init() { - log.debug("AttendanceLogicImpl init()"); - - entityManager.registerEntityProducer(this, Entity.SEPARATOR + "attendance"); - } - private boolean addSite(AttendanceSite s) { - if (dao.addAttendanceSite(s)) { + AttendanceSite attendanceSite = attendanceSiteRepository.save(s); + if (attendanceSite != null) { generateMissingAttendanceStatusesForSite(s); return true; } @@ -688,7 +602,7 @@ private void generateMissingAttendanceStatusesForSite(AttendanceSite attendanceS } } - dao.updateAttendanceStatuses(statusesToBeAdded); + attendanceStatusRepository.saveAll(statusesToBeAdded); } private int getNextSortOrder(List attendanceStatusList) { @@ -703,92 +617,6 @@ private int getNextSortOrder(List attendanceStatusList) { return maxSortOrder + 1; } - private List safeAttendanceEventListReturn(List l) { - if(l == null) { - return new ArrayList<>(); - } - - return l; - } - - private List safeAttendanceStatusListReturn(List l) { - if(l == null) { - return new ArrayList<>(); - } - - return l; - } - - private void updateStats(AttendanceRecord aR, Status oldStatus) { - if(aR.getStatus() == oldStatus) { - return; - } - - updateUserStats(aR, oldStatus); - - AttendanceEvent aE = aR.getAttendanceEvent(); - AttendanceItemStats itemStats = getStatsForEvent(aE); - updateStats(null, itemStats, oldStatus, aR.getStatus()); - } - - private boolean updateUserStats(AttendanceRecord record, Status oldStatus) { - AttendanceUserStats userStats = dao.getAttendanceUserStats(record.getUserID(), record.getAttendanceEvent().getAttendanceSite()); - if(userStats == null) { // assume null userStats means stats haven't been calculated yet - userStats = new AttendanceUserStats(record.getUserID(), record.getAttendanceEvent().getAttendanceSite()); - } - return updateStats(userStats, null, oldStatus, record.getStatus()); - } - - private boolean updateStats(AttendanceUserStats userStats, AttendanceItemStats itemStats, Status oldStatus, Status newStatus) { - AttendanceStats stats; - if(userStats != null) { - stats = userStats; - } else { - stats = itemStats; - } - - if(oldStatus != newStatus) { - removeStatusFromStats(stats, oldStatus); - - if (newStatus == Status.PRESENT) { - stats.setPresent(stats.getPresent() + 1); - } else if (newStatus == Status.UNEXCUSED_ABSENCE) { - stats.setUnexcused(stats.getUnexcused() + 1); - } else if (newStatus == Status.EXCUSED_ABSENCE) { - stats.setExcused(stats.getExcused() + 1); - } else if (newStatus == Status.LATE) { - stats.setLate(stats.getLate() + 1); - } else if (newStatus == Status.LEFT_EARLY) { - stats.setLeftEarly(stats.getLeftEarly() + 1); - } - } - - boolean returnVariable; - if(userStats != null) { - returnVariable = dao.updateAttendanceUserStats((AttendanceUserStats) stats); - } else { - returnVariable = dao.updateAttendanceItemStats((AttendanceItemStats) stats); - } - - return returnVariable; - } - - private void removeStatusFromStats(AttendanceStats stats, Status status) { - if (status != Status.UNKNOWN) { - if (status == Status.PRESENT) { - stats.setPresent(stats.getPresent() - 1); - } else if (status == Status.UNEXCUSED_ABSENCE) { - stats.setUnexcused(stats.getUnexcused() - 1); - } else if (status == Status.EXCUSED_ABSENCE) { - stats.setExcused(stats.getExcused() - 1); - } else if (status == Status.LATE) { - stats.setLate(stats.getLate() - 1); - } else if (status == Status.LEFT_EARLY) { - stats.setLeftEarly(stats.getLeftEarly() - 1); - } - } - } - private void regradeForAttendanceRecord(AttendanceRecord attendanceRecord) { final AttendanceSite currentSite = getCurrentAttendanceSite(); // Auto grade if valid record, maximum points is set, and auto grade is enabled @@ -808,7 +636,7 @@ private Double grade(String userId, AttendanceSite attendanceSite) { final List rules = getGradingRulesForSite(attendanceSite); final AttendanceUserStats userStats = getStatsForUser(userId); - Double totalPoints = 0D; + double totalPoints = 0D; Double maximumGrade = attendanceSite.getMaximumGrade(); if (attendanceSite.getAutoGradeBySubtraction() && maximumGrade != null) { totalPoints = maximumGrade; @@ -841,16 +669,12 @@ private Double grade(String userId, AttendanceSite attendanceSite) { } // Don't allow negative total points - if (totalPoints < 0D) { - return 0D; - } else { - return totalPoints; - } + return Math.max(totalPoints, 0D); } @Override public Map transferCopyEntities(String fromContext, String toContext, List ids, List transferOptions) { - return transferCopyEntities(fromContext, toContext, ids, transferOptions); + return transferCopyEntities(fromContext, toContext, ids, transferOptions, false); } @Override @@ -877,15 +701,10 @@ public Map transferCopyEntities(String fromContext, String toCon AttendanceEvent toEvent = new AttendanceEvent(); toEvent.setAttendanceSite(toSite); toEvent.setName(fromEvent.getName()); - toEvent.setIsReoccurring(fromEvent.getIsReoccurring()); - toEvent.setIsRequired(fromEvent.getIsRequired()); if (fromEvent.getStartDateTime() != null) { toEvent.setStartDateTime(fromEvent.getStartDateTime()); } - if (fromEvent.getEndDateTime() != null) { - toEvent.setEndDateTime(fromEvent.getEndDateTime()); - } addAttendanceEventNow(toEvent); log.info("transferCopyEntities: new attendance event ({})", toEvent.getName()); @@ -903,16 +722,4 @@ public Map transferCopyEntities(String fromContext, String toCon public void updateEntityReferences(String toContext, Map transversalMap) { return; } - - @Setter - private AttendanceDao dao; - - @Setter - private SakaiProxy sakaiProxy; - - @Setter - private AttendanceGradebookProvider attendanceGradebookProvider; - - @Setter - private EntityManager entityManager; } diff --git a/impl/src/java/org/sakaiproject/attendance/logic/SakaiProxyImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/logic/SakaiProxyImpl.java similarity index 96% rename from impl/src/java/org/sakaiproject/attendance/logic/SakaiProxyImpl.java rename to impl/src/java/org/sakaiproject/attendance/impl/logic/SakaiProxyImpl.java index 934998a0..1ce762f1 100644 --- a/impl/src/java/org/sakaiproject/attendance/logic/SakaiProxyImpl.java +++ b/impl/src/java/org/sakaiproject/attendance/impl/logic/SakaiProxyImpl.java @@ -14,30 +14,25 @@ * limitations under the License. */ -package org.sakaiproject.attendance.logic; +package org.sakaiproject.attendance.impl.logic; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; +import org.sakaiproject.attendance.api.logic.SakaiProxy; import org.sakaiproject.authz.api.*; import org.sakaiproject.component.api.ServerConfigurationService; -import org.sakaiproject.entity.api.ResourceProperties; -import org.sakaiproject.entity.api.ResourcePropertiesEdit; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; -import org.sakaiproject.time.api.Time; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.user.api.*; -import org.sakaiproject.util.ResourceLoader; -import org.w3c.dom.Document; -import org.w3c.dom.Element; import java.util.*; diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceEventRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceEventRepositoryImpl.java new file mode 100644 index 00000000..7e1062f7 --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceEventRepositoryImpl.java @@ -0,0 +1,40 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.stats.AttendanceItemStats; +import org.sakaiproject.attendance.api.model.stats.StatusCount; +import org.sakaiproject.attendance.api.repository.AttendanceEventRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class AttendanceEventRepositoryImpl extends SpringCrudRepositoryImpl implements AttendanceEventRepository { + + @Transactional(readOnly = true) + public List findAllByAttendanceSite(AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceEvent.class); + Root event = query.from(AttendanceEvent.class); + query.where(cb.equal(event.get("attendanceSite"), attendanceSite)); + + return session.createQuery(query).list(); + } + + @Transactional(readOnly = true) + public AttendanceItemStats calculateStatsForEvent(AttendanceEvent event) { + Session session = sessionFactory.getCurrentSession(); + Query query = session.createQuery("SELECT new org.sakaiproject.attendance.api.model.stats.StatusCount(r.status, COUNT(r.status)) " + + "FROM AttendanceRecord AS r WHERE r.attendanceEvent = :attendanceEvent GROUP BY r.status"); + query.setParameter("attendanceEvent", event); + List statusCounts = query.getResultList(); + return new AttendanceItemStats(event, statusCounts); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceGradeRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceGradeRepositoryImpl.java new file mode 100644 index 00000000..652c078b --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceGradeRepositoryImpl.java @@ -0,0 +1,40 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceGrade; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.repository.AttendanceGradeRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; +import java.util.Optional; + +public class AttendanceGradeRepositoryImpl extends SpringCrudRepositoryImpl implements AttendanceGradeRepository { + + @Transactional(readOnly = true) + public List findAllByAttendanceSite(AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceGrade.class); + Root record = query.from(AttendanceGrade.class); + query.where(cb.equal(record.get("attendanceSite"), attendanceSite)); + + return session.createQuery(query).list(); + } + + @Transactional(readOnly = true) + public Optional findByAttendanceSiteAndUserId(AttendanceSite attendanceSite, String userId) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceGrade.class); + Root grade = query.from(AttendanceGrade.class); + query.where(cb.and(cb.equal(grade.get("attendanceSite"), attendanceSite), + cb.equal(grade.get("userID"), userId))); + + return session.createQuery(query).uniqueResultOptional(); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceRecordRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceRecordRepositoryImpl.java new file mode 100644 index 00000000..ae188d27 --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceRecordRepositoryImpl.java @@ -0,0 +1,27 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceRecord; +import org.sakaiproject.attendance.api.repository.AttendanceRecordRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class AttendanceRecordRepositoryImpl extends SpringCrudRepositoryImpl implements AttendanceRecordRepository { + + @Transactional(readOnly = true) + public List findAllByAttendanceEvent(AttendanceEvent attendanceEvent) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceRecord.class); + Root record = query.from(AttendanceRecord.class); + query.where(cb.equal(record.get("attendanceEvent"), attendanceEvent)); + + return session.createQuery(query).list(); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceSiteRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceSiteRepositoryImpl.java new file mode 100644 index 00000000..cf885bd8 --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceSiteRepositoryImpl.java @@ -0,0 +1,42 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.stats.AttendanceUserStats; +import org.sakaiproject.attendance.api.model.stats.StatusCount; +import org.sakaiproject.attendance.api.repository.AttendanceSiteRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class AttendanceSiteRepositoryImpl extends SpringCrudRepositoryImpl implements AttendanceSiteRepository { + + @Transactional(readOnly = true) + public AttendanceSite findBySiteId(String siteId) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceSite.class); + Root site = query.from(AttendanceSite.class); + query.where(cb.equal(site.get("siteID"), siteId)); + + return session.createQuery(query).uniqueResult(); + } + + @Transactional(readOnly = true) + public AttendanceUserStats calculateAttendanceUserStats(String userId, AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + Query query = session.createQuery("SELECT new org.sakaiproject.attendance.api.model.stats.StatusCount(r.status, COUNT(r.status)) " + + "FROM AttendanceRecord AS r JOIN AttendanceEvent AS e ON r.attendanceEvent = e " + + "WHERE e.attendanceSite = :attendanceSite AND r.userID = :userId GROUP BY r.status"); + query.setParameter("attendanceSite", attendanceSite); + query.setParameter("userId", userId); + List statusCounts = query.getResultList(); + + return new AttendanceUserStats(userId, attendanceSite, statusCounts); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceStatusRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceStatusRepositoryImpl.java new file mode 100644 index 00000000..29d2b573 --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/AttendanceStatusRepositoryImpl.java @@ -0,0 +1,39 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.AttendanceStatus; +import org.sakaiproject.attendance.api.repository.AttendanceStatusRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class AttendanceStatusRepositoryImpl extends SpringCrudRepositoryImpl implements AttendanceStatusRepository { + + @Transactional(readOnly = true) + public List findAllByAttendanceSite(AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceStatus.class); + Root status = query.from(AttendanceStatus.class); + query.where(cb.equal(status.get("attendanceSite"), attendanceSite)); + + return session.createQuery(query).list(); + } + + @Transactional(readOnly = true) + public List findAllActiveByAttendanceSite(AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(AttendanceStatus.class); + Root status = query.from(AttendanceStatus.class); + query.where(cb.and(cb.equal(status.get("attendanceSite"), attendanceSite), + cb.equal(status.get("isActive"), Boolean.TRUE))); + + return session.createQuery(query).list(); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/impl/repository/GradingRuleRepositoryImpl.java b/impl/src/java/org/sakaiproject/attendance/impl/repository/GradingRuleRepositoryImpl.java new file mode 100644 index 00000000..ddefa4c3 --- /dev/null +++ b/impl/src/java/org/sakaiproject/attendance/impl/repository/GradingRuleRepositoryImpl.java @@ -0,0 +1,27 @@ +package org.sakaiproject.attendance.impl.repository; + +import org.hibernate.Session; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.GradingRule; +import org.sakaiproject.attendance.api.repository.GradingRuleRepository; +import org.sakaiproject.springframework.data.SpringCrudRepositoryImpl; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class GradingRuleRepositoryImpl extends SpringCrudRepositoryImpl implements GradingRuleRepository { + + @Transactional(readOnly = true) + public List findAllByAttendanceSite(AttendanceSite attendanceSite) { + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(GradingRule.class); + Root rule = query.from(GradingRule.class); + query.where(cb.equal(rule.get("attendanceSite"), attendanceSite)); + + return session.createQuery(query).list(); + } +} diff --git a/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalc.java b/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalc.java deleted file mode 100644 index 021ffd79..00000000 --- a/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalc.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.services; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.sakaiproject.attendance.dao.AttendanceDao; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.logic.SakaiProxy; -import org.sakaiproject.attendance.model.*; - -import java.util.*; - -/** - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - */ -@Slf4j -public class AttendanceStatCalc { - private int sitesProcessed = 0; - private int sitesNotMarked = 0; - private int sitesInError = 0; - private int sitesWithNoUsers = 0; - - public void init() { - log.debug("AttendanceStatCalc init()"); - } - - public void destroy() { - log.debug("AttendanceStatCalc destroy()"); - } - - public void execute() { - log.debug("AttendanceStatCalc execute()"); - Date syncTime = new Date(); - Long lastId = 0L; - - List ids = dao.getAttendanceSiteBatch(syncTime, lastId); - if(ids.isEmpty()) { - String summary = getOverallSummary(); - if("".equals(summary)) { - log.info("AttendanceStatCalc no sites left to sync"); - } else { - log.info("AttendanceStatCalc done, but there are errors\n" + summary); - } - } else { - while(!ids.isEmpty()) { - dao.markAttendanceSiteForSync(ids, syncTime); - for (Long id : ids) { - calculateStats(id); - lastId = id > lastId ? id : lastId++; // never-ending loop protection - } - log.info("AttendanceStatCalc in progress " + getSummary()); - ids = dao.getAttendanceSiteBatch(syncTime, lastId); - } - log.info("AttendanceStatCalc finished " + getSummary()); - log.info(getOverallSummary()); - } - - resetCounters(); - } - - private void calculateStats(Long id) { - try { - AttendanceSite attendanceSite = dao.getAttendanceSite(id); - - if(attendanceSite.getIsSyncing()) { - List userIds = sakaiProxy.getSiteMembershipIds(attendanceSite.getSiteID()); - if(!userIds.isEmpty()) { // only calculate stats for sites still available - Map userStatsList = new HashMap<>(userIds.size()); - - userIds.forEach(userId -> { - int[] array = {0, 0, 0, 0, 0}; // present, unexcused, excused, late, leftEarly - userStatsList.put(userId, array); - }); - - List events = attendanceLogic.getAttendanceEventsForSite(attendanceSite); - if (!events.isEmpty()) { - events.forEach(attendanceEvent -> calculateEventStats(attendanceEvent, userStatsList)); - - for (String key : userStatsList.keySet()) { - AttendanceUserStats userStat = attendanceLogic.getStatsForUser(key, attendanceSite); - int[] userRecordStats = userStatsList.get(key); - userStat.setPresent(userRecordStats[0]); - userStat.setUnexcused(userRecordStats[1]); - userStat.setExcused(userRecordStats[2]); - userStat.setLate(userRecordStats[3]); - userStat.setLeftEarly(userRecordStats[4]); - - dao.updateAttendanceUserStats(userStat); - } - } - } else { - sitesWithNoUsers++; - log.debug("AttendanceSite, id: '" + id +"' has no users or Site, id: '" - + attendanceSite.getSiteID() +"' no longer exists."); - } - - attendanceSite.setIsSyncing(false); - attendanceLogic.updateAttendanceSite(attendanceSite); - - log.debug("AttendanceSite synced with id: " + id); - sitesProcessed++; - } else { - log.debug("AttendanceSite not marked as in progress" + id); - sitesNotMarked++; - } - } catch (Exception e) { - sitesInError++; - log.warn("Error syncing AttendanceSite id: " + id, e); - } - } - - private void calculateEventStats(AttendanceEvent event, Map userStats) { - Set records = event.getRecords(); - AttendanceItemStats itemStats = attendanceLogic.getStatsForEvent(event); - - int present = 0, unexcused = 0, excused = 0, late = 0, leftEarly = 0; - boolean recordsPresent = false; - for(AttendanceRecord record : records) { - recordsPresent = true; - Status recordStatus = record.getStatus(); - int[] array = userStats.get(record.getUserID()); - if(array != null) { - if (recordStatus == Status.PRESENT) { - present++; - array[0] = array[0] + 1; - } else if (recordStatus == Status.UNEXCUSED_ABSENCE) { - unexcused++; - array[1] = array[1] + 1; - } else if (recordStatus == Status.EXCUSED_ABSENCE) { - excused++; - array[2] = array[2] + 1; - } else if (recordStatus == Status.LATE) { - late++; - array[3] = array[3] + 1; - } else if (recordStatus == Status.LEFT_EARLY) { - leftEarly++; - array[4] = array[4] + 1; - } - - userStats.put(record.getUserID(), array); - } else { - log.debug("AttendanceRecord user no longer present in course, record id: '" + record.getId() - + "' and userID: " + record.getUserID()); - } - } - - if(recordsPresent) { - itemStats.setPresent(present); - itemStats.setUnexcused(unexcused); - itemStats.setExcused(excused); - itemStats.setLate(late); - itemStats.setLeftEarly(leftEarly); - - dao.updateAttendanceItemStats(itemStats); - } - } - - private String getSummary() { - return String.format("%d Attendance Sites synced, %d Attendance Sites with no users, %d Attendance Sites unsuccessfully synced", - sitesProcessed, sitesWithNoUsers, sitesInError + sitesNotMarked); - } - - private String getOverallSummary() { - List inProgress = dao.getAttendanceSitesInSync(); - if(inProgress.size() > 0) { - String message = "%d AttendanceSite(s) currently marked in sync. IDs marked in sync: %s"; - return String.format(message, inProgress.size(), inProgress); - } - return ""; - } - - private void resetCounters() { - this.sitesInError = 0; - this.sitesNotMarked = 0; - this.sitesProcessed = 0; - this.sitesWithNoUsers = 0; - } - - @Setter - private AttendanceDao dao; - - @Setter - private SakaiProxy sakaiProxy; - - @Setter - private AttendanceLogic attendanceLogic; -} diff --git a/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalcJob.java b/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalcJob.java deleted file mode 100644 index 6b42e3f0..00000000 --- a/impl/src/java/org/sakaiproject/attendance/services/AttendanceStatCalcJob.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2017, University of Dayton - * - * 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.attendance.services; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.quartz.DisallowConcurrentExecution; -import org.quartz.Job; -import org.quartz.JobExecutionContext; -import org.sakaiproject.authz.api.AuthzGroupService; -import org.sakaiproject.component.cover.ServerConfigurationService; -import org.sakaiproject.event.api.EventTrackingService; -import org.sakaiproject.event.api.UsageSession; -import org.sakaiproject.event.api.UsageSessionService; -import org.sakaiproject.tool.api.Session; -import org.sakaiproject.tool.api.SessionManager; - -import java.util.Date; - -/** - * The AttendanceStatCalc Job calculates all AttendanceUserStats and all AttendanceItemStats - * for each AttendanceSite in batches of 5 Attendance Sites. - * - * The job should be run once after upgrading past Attendance 1.0. Afterwards, it should be run - * only in cases where the statistics got out of sync (very very rare). - * - * @author Leonardo Canessa [lcanessa1 (at) udayton (dot) edu] - */ -@Slf4j -@DisallowConcurrentExecution -public class AttendanceStatCalcJob implements Job { - private String serverName = "N/A"; - final private String jobName = "AttendanceStatCalcJob"; - final private String jobError = "attend.calc.job.error"; - - public AttendanceStatCalcJob() { - super(); - } - - public void init() { - log.info(jobName + " init."); - serverName = ServerConfigurationService.getServerName(); - } - - public void destroy() { - log.info(jobName +" D E S T R O Y E D."); - } - - public void execute(JobExecutionContext context) { - log.debug(jobName + "execute()"); - loginToSakai("admin", jobName, jobError); - - String jobName = context.getJobDetail().getKey().getName(); - String triggerName = context.getTrigger().getKey().getName(); - Date requestedFire = context.getScheduledFireTime(); - Date actualFire = context.getFireTime(); - - StringBuffer whoAmI = new StringBuffer(jobName + " $"); - whoAmI.append(" Job: "); - whoAmI.append(jobName); - whoAmI.append(" Trigger: "); - whoAmI.append(triggerName); - - if (requestedFire != null) { - whoAmI.append(" Fire scheduled: "); - whoAmI.append(requestedFire.toString()); - } - - if (actualFire != null) { - whoAmI.append(" Fire actual: "); - whoAmI.append(actualFire.toString()); - } - - eventTrackingService.post(eventTrackingService.newEvent("attend.calc.job", safeEventLength(whoAmI.toString()), true)); - - log.info("Start Job: " + whoAmI.toString()); - attendanceStatCalc.execute(); - - logoutFromSakai(); - - } - - public void loginToSakai(String whoAs, String jobName, String jobError) { - log.debug(jobName + " loginToSakai()"); - - UsageSession session = usageSessionService.startSession(whoAs, serverName, jobName); - if (session == null) { - eventTrackingService.post(eventTrackingService.newEvent(jobError, whoAs + " unable to log into " + serverName, true)); - return; - } - - Session sakaiSession = sessionManager.getCurrentSession(); - sakaiSession.setUserId(whoAs); - sakaiSession.setUserEid(whoAs); - - // update the user's externally provided realm definitions - authzGroupService.refreshUser(whoAs); - - // post the login events - eventTrackingService.post(eventTrackingService.newEvent(UsageSessionService.EVENT_LOGIN, whoAs + " running " + serverName, true)); - } - - public void logoutFromSakai() { - log.debug(jobName + " Logging out of Sakai on " + serverName); - eventTrackingService.post(eventTrackingService.newEvent(UsageSessionService.EVENT_LOGOUT, null, true)); - usageSessionService.logout(); // safe to logout? what if other jobs are running? - } - - static public String safeEventLength(final String target) - { - return (target.length() > 255 ? target.substring(0, 255) : target); - } - - @Setter - private AttendanceStatCalc attendanceStatCalc; - - @Setter - private EventTrackingService eventTrackingService; - - @Setter - private UsageSessionService usageSessionService; - - @Setter - private AuthzGroupService authzGroupService; - - @Setter - private SessionManager sessionManager; -} diff --git a/impl/src/webapp/WEB-INF/components.xml b/impl/src/webapp/WEB-INF/components.xml index c537f042..f16234e8 100644 --- a/impl/src/webapp/WEB-INF/components.xml +++ b/impl/src/webapp/WEB-INF/components.xml @@ -14,13 +14,22 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + + + + @@ -36,31 +45,16 @@ - - - - - - - - - - - - PROPAGATION_REQUIRED - - - - - - + class="org.sakaiproject.attendance.impl.logic.AttendanceLogicImpl"> + + + + + + + @@ -68,11 +62,12 @@ + @@ -87,55 +82,49 @@ - - + - + + - org/sakaiproject/attendance/hbm/AttendanceEvent.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceGrade.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceItemStats.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceRecord.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceSite.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceStatus.hbm.xml - org/sakaiproject/attendance/hbm/AttendanceUserStats.hbm.xml - org/sakaiproject/attendance/hbm/GradingRule.hbm.xml + org.sakaiproject.attendance.api.model.AttendanceEvent + org.sakaiproject.attendance.api.model.AttendanceGrade + org.sakaiproject.attendance.api.model.AttendanceRecord + org.sakaiproject.attendance.api.model.AttendanceStatus + org.sakaiproject.attendance.api.model.AttendanceSite + org.sakaiproject.attendance.api.model.GradingRule + + + - - - + + - - - - - - - + + - - - - + + - - - - + + + + + + diff --git a/pom.xml b/pom.xml index 54c5cc4d..b82d5788 100644 --- a/pom.xml +++ b/pom.xml @@ -24,12 +24,13 @@ attendance pom - + - org.sakaiproject - master - 23-SNAPSHOT - + org.sakaiproject + master + 24-SNAPSHOT + ../master/pom.xml + @@ -67,12 +68,6 @@ ${project.version} provided - - org.sakaiproject.attendance - attendance-impl - ${project.version} - runtime - diff --git a/tool/pom.xml b/tool/pom.xml index d4f06826..b237af59 100644 --- a/tool/pom.xml +++ b/tool/pom.xml @@ -18,12 +18,13 @@ 4.0.0 - + - attendance - org.sakaiproject.attendance - 23-SNAPSHOT - + attendance + org.sakaiproject.attendance + 24-SNAPSHOT + ../pom.xml + attendance - Tool attendance-tool @@ -93,18 +94,18 @@ - org.sakaiproject.kernel + org.sakaiproject.kernel sakai-kernel-api org.sakaiproject.kernel sakai-component-manager - - org.sakaiproject.kernel - sakai-kernel-util - - + + org.sakaiproject.wicket + wicket-tool-6 + + diff --git a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceRecordProvider.java b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceRecordProvider.java index b61588f4..13738c9c 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceRecordProvider.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceRecordProvider.java @@ -18,8 +18,8 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.sakaiproject.attendance.model.AttendanceEvent; -import org.sakaiproject.attendance.model.AttendanceRecord; +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.AttendanceRecord; import java.util.ArrayList; import java.util.Comparator; diff --git a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceStatusProvider.java b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceStatusProvider.java index 4f5760c5..5c40d1f8 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceStatusProvider.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/AttendanceStatusProvider.java @@ -18,10 +18,9 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.sakaiproject.attendance.model.AttendanceSite; -import org.sakaiproject.attendance.model.AttendanceStatus; -import org.sakaiproject.attendance.model.Status; -import org.sakaiproject.attendance.tool.models.DetachableAttendanceStatusModel; +import org.sakaiproject.attendance.api.model.AttendanceSite; +import org.sakaiproject.attendance.api.model.AttendanceStatus; +import org.sakaiproject.attendance.api.model.Status; import java.util.ArrayList; import java.util.Collections; @@ -55,8 +54,10 @@ public AttendanceStatusProvider(String siteId, String filter) { AttendanceSite attendanceSite = attendanceLogic.getAttendanceSite(siteId); if(attendanceSite != null) { List attendanceStatuses = attendanceLogic.getAllStatusesForSite(attendanceSite); - this.list = new ArrayList(); + this.list = new ArrayList<>(); filterStatuses(attendanceStatuses, filter); + } else { + throw new IllegalArgumentException("Unable to get attendance site for site id " + siteId); } } diff --git a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/BaseProvider.java b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/BaseProvider.java index 89f0f6a8..2e3f1b8e 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/BaseProvider.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/BaseProvider.java @@ -19,8 +19,8 @@ import org.apache.wicket.injection.Injector; import org.apache.wicket.markup.repeater.data.IDataProvider; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.logic.SakaiProxy; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.logic.SakaiProxy; import java.util.Iterator; import java.util.List; diff --git a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/EventDataProvider.java b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/EventDataProvider.java index c53d6e48..a6e26d8a 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/EventDataProvider.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/dataproviders/EventDataProvider.java @@ -18,8 +18,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.sakaiproject.attendance.model.AttendanceEvent; -import org.sakaiproject.attendance.tool.models.DetachableEventModel; +import org.sakaiproject.attendance.api.model.AttendanceEvent; import java.util.Collections; import java.util.List; diff --git a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceRecordModel.java b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceRecordModel.java index 63b9b40b..474b6d4f 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceRecordModel.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceRecordModel.java @@ -19,8 +19,8 @@ import org.apache.wicket.injection.Injector; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.model.AttendanceRecord; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.model.AttendanceRecord; /** * DetachableAttendanceRecordModel @@ -85,6 +85,6 @@ else if (obj instanceof DetachableAttendanceRecordModel) { protected AttendanceRecord load(){ Injector.get().inject(this); // get the thing - return attendanceLogic.getAttendanceRecord(id); + return attendanceLogic.getAttendanceRecord(id).orElseThrow( () -> { throw new IllegalArgumentException("Unable to get attendance record for id " + id); }); } } diff --git a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceStatusModel.java b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceStatusModel.java index 6a9653ae..054ef9cb 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceStatusModel.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableAttendanceStatusModel.java @@ -19,8 +19,8 @@ import org.apache.wicket.injection.Injector; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.model.AttendanceStatus; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.model.AttendanceStatus; /** * DetachableAttendanceStatusModel @@ -85,6 +85,6 @@ else if (obj instanceof DetachableAttendanceStatusModel) { protected AttendanceStatus load(){ Injector.get().inject(this); // get the thing - return attendanceLogic.getAttendanceStatusById(id); + return attendanceLogic.getAttendanceStatusById(id).orElseThrow( () -> { throw new IllegalArgumentException("Unable to get attendance status by id " + id); }); } } diff --git a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableEventModel.java b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableEventModel.java index 769f2c81..4ddb8016 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableEventModel.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableEventModel.java @@ -19,8 +19,8 @@ import org.apache.wicket.injection.Injector; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.model.AttendanceEvent; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.model.AttendanceEvent; /** * DetachableAttendanceEventModel diff --git a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableUserModel.java b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableUserModel.java index ae2190c2..8f0e83ef 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableUserModel.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/models/DetachableUserModel.java @@ -19,7 +19,7 @@ import org.apache.wicket.injection.Injector; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.spring.injection.annot.SpringBean; -import org.sakaiproject.attendance.logic.SakaiProxy; +import org.sakaiproject.attendance.api.logic.SakaiProxy; import org.sakaiproject.user.api.User; /** diff --git a/tool/src/java/org/sakaiproject/attendance/tool/pages/BasePage.java b/tool/src/java/org/sakaiproject/attendance/tool/pages/BasePage.java index 9ed8f108..4dc81e02 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/pages/BasePage.java +++ b/tool/src/java/org/sakaiproject/attendance/tool/pages/BasePage.java @@ -20,13 +20,10 @@ import lombok.extern.slf4j.Slf4j; import org.apache.wicket.AttributeModifier; -import org.apache.wicket.Component; -import org.apache.wicket.Session; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; -import org.apache.wicket.feedback.FeedbackMessage; import org.apache.wicket.markup.head.*; import org.apache.wicket.markup.html.IHeaderContributor; import org.apache.wicket.markup.html.WebPage; @@ -38,13 +35,14 @@ import org.apache.wicket.model.ResourceModel; import org.apache.wicket.spring.injection.annot.SpringBean; import org.sakaiproject.attendance.api.AttendanceGradebookProvider; -import org.sakaiproject.attendance.logic.AttendanceLogic; -import org.sakaiproject.attendance.logic.SakaiProxy; -import org.sakaiproject.attendance.model.AttendanceEvent; -import org.sakaiproject.attendance.model.Status; +import org.sakaiproject.attendance.api.logic.AttendanceLogic; +import org.sakaiproject.attendance.api.logic.SakaiProxy; +import org.sakaiproject.attendance.api.model.AttendanceEvent; +import org.sakaiproject.attendance.api.model.Status; import org.sakaiproject.attendance.tool.panels.EventInputPanel; import org.sakaiproject.attendance.tool.util.AttendanceFeedbackPanel; -import org.sakaiproject.component.cover.ServerConfigurationService; +import org.sakaiproject.portal.util.PortalUtils; +import org.sakaiproject.time.api.UserTimeService; import org.sakaiproject.util.ResourceLoader; import javax.servlet.http.HttpServletRequest; @@ -72,6 +70,9 @@ public class BasePage extends WebPage implements IHeaderContributor { @SpringBean(name="org.sakaiproject.attendance.api.AttendanceGradebookProvider") protected AttendanceGradebookProvider attendanceGradebookProvider; + @SpringBean(name="org.sakaiproject.time.api.UserTimeService") + protected UserTimeService userTimeService; + protected String role; Link addLink; @@ -167,10 +168,6 @@ public void onClick() { feedbackPanel = new AttendanceFeedbackPanel("feedback"); add(feedbackPanel); - if(attendanceLogic.getCurrentAttendanceSite().getIsSyncing()) { - getSession().error((new ResourceModel("attendance.site.syncing.error")).getObject()); - } - this.addOrEditItemWindow = new ModalWindow("addOrEditItemWindow"); this.addOrEditItemWindow.showUnloadConfirmation(false); this.addOrEditItemWindow.setInitialHeight(400); @@ -183,20 +180,40 @@ public void onClick() { * Add to this any additional CSS or JS references that you need. * */ + @Override public void renderHead(IHeaderResponse response) { + super.renderHead(response); + + final String version = PortalUtils.getCDNQuery(); + //get the Sakai skin header fragment from the request attribute HttpServletRequest request = (HttpServletRequest)getRequest().getContainerRequest(); + + response.render(new PriorityHeaderItem(JavaScriptHeaderItem + .forReference(getApplication().getJavaScriptLibrarySettings().getJQueryReference()))); response.render(StringHeaderItem.forString((String)request.getAttribute("sakai.html.head"))); response.render(OnLoadHeaderItem.forScript("setMainFrameHeight( window.name )")); + //add Attendance.css as the css class response.render(CssHeaderItem.forUrl("css/attendance.css")); + //Tool additions (at end so we can override if isRequired) response.render(StringHeaderItem.forString("")); - //response.renderCSSReference("css/my_tool_styles.css"); - //response.renderJavascriptReference("js/my_tool_javascript.js"); + + // Shared JavaScript and stylesheets + // Force Wicket to use Sakai's version of jQuery + response.render( + new PriorityHeaderItem( + JavaScriptHeaderItem + .forUrl(String.format("/library/webjars/jquery/1.12.4/jquery.min.js%s", version)))); + // And pair this instance of jQuery with a Bootstrap version we've tested with + response.render( + new PriorityHeaderItem( + JavaScriptHeaderItem + .forUrl(String.format("/library/webjars/bootstrap/3.3.7/js/bootstrap.min.js%s", version)))); + // tablesorter - final String version = ServerConfigurationService.getString("portal.cdn.version", ""); response.render(JavaScriptHeaderItem.forUrl(String.format("javascript/jquery.tablesorter.min.js?version=%s", version))); response.render(JavaScriptHeaderItem.forUrl(String.format("javascript/jquery.tablesorter.widgets.min.js?version=%s", version))); } @@ -232,7 +249,7 @@ protected String getStatusString(Status s) { } } - protected AjaxLink getAddEditWindowAjaxLink(final AttendanceEvent obj, final String id) { + protected AjaxLink getAddEditWindowAjaxLink(Long attendanceEventId, final String id) { return new AjaxLink(id) { private static final long serialVersionUID = 1L; @@ -240,7 +257,7 @@ public void onClick(AjaxRequestTarget target) { final ModalWindow window = getAddOrEditItemWindow(); window.setTitle(new ResourceModel("attendance.add.edit.header")); window.setCssClassName(window.getCssClassName() + " editItemModal"); - window.setContent(new EventInputPanel(window.getContentId(), window, new CompoundPropertyModel<>(obj))); + window.setContent(new EventInputPanel(window.getContentId(), window, Model.of(attendanceEventId))); window.show(target); } }; diff --git a/tool/src/java/org/sakaiproject/attendance/tool/pages/EventInputPage.html b/tool/src/java/org/sakaiproject/attendance/tool/pages/EventInputPage.html index d5ce7e43..240c65ca 100644 --- a/tool/src/java/org/sakaiproject/attendance/tool/pages/EventInputPage.html +++ b/tool/src/java/org/sakaiproject/attendance/tool/pages/EventInputPage.html @@ -33,10 +33,12 @@

-