Skip to content
Snippets Groups Projects
Commit af93d5c7 authored by srosse's avatar srosse
Browse files

OO-3397: add audit log for author who change summary data of a participant

parent dfeaace8
No related branches found
No related tags found
No related merge requests found
...@@ -65,6 +65,9 @@ public interface LectureBlockAuditLog { ...@@ -65,6 +65,9 @@ public interface LectureBlockAuditLog {
updateRollCall, updateRollCall,
adaptRollCall, adaptRollCall,
updateSummary,
removeCustomRate,
sendAppeal sendAppeal
} }
......
...@@ -122,6 +122,10 @@ public interface LectureService { ...@@ -122,6 +122,10 @@ public interface LectureService {
public LectureBlockRollCall toAuditLectureBlockRollCall(String xml); public LectureBlockRollCall toAuditLectureBlockRollCall(String xml);
public String toAuditXml(LectureParticipantSummary summary);
public LectureParticipantSummary toAuditLectureParticipantSummary(String xml);
/** /**
* Append content to the log saved on the lecture block. * Append content to the log saved on the lecture block.
......
...@@ -32,9 +32,11 @@ import org.olat.modules.lecture.LectureBlock; ...@@ -32,9 +32,11 @@ import org.olat.modules.lecture.LectureBlock;
import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockAuditLog;
import org.olat.modules.lecture.LectureBlockRef; import org.olat.modules.lecture.LectureBlockRef;
import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureBlockRollCall;
import org.olat.modules.lecture.LectureParticipantSummary;
import org.olat.modules.lecture.model.LectureBlockAuditLogImpl; import org.olat.modules.lecture.model.LectureBlockAuditLogImpl;
import org.olat.modules.lecture.model.LectureBlockImpl; import org.olat.modules.lecture.model.LectureBlockImpl;
import org.olat.modules.lecture.model.LectureBlockRollCallImpl; import org.olat.modules.lecture.model.LectureBlockRollCallImpl;
import org.olat.modules.lecture.model.LectureParticipantSummaryImpl;
import org.olat.modules.lecture.model.ReasonImpl; import org.olat.modules.lecture.model.ReasonImpl;
import org.olat.repository.RepositoryEntryRef; import org.olat.repository.RepositoryEntryRef;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -80,6 +82,14 @@ public class LectureBlockAuditLogDAO { ...@@ -80,6 +82,14 @@ public class LectureBlockAuditLogDAO {
rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lectureBlock"); rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lectureBlock");
rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lastModified"); rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lastModified");
} }
private static final XStream summaryXStream = XStreamHelper.createXStreamInstanceForDBObjects();
static {
summaryXStream.alias("summary", LectureParticipantSummaryImpl.class);
summaryXStream.ignoreUnknownElements();
summaryXStream.omitField(LectureParticipantSummaryImpl.class, "identity");
summaryXStream.omitField(LectureParticipantSummaryImpl.class, "entry");
}
public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message, public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message,
LectureBlockRef lectureBlock, LectureBlockRollCall rollCall, LectureBlockRef lectureBlock, LectureBlockRollCall rollCall,
...@@ -185,4 +195,24 @@ public class LectureBlockAuditLogDAO { ...@@ -185,4 +195,24 @@ public class LectureBlockAuditLogDAO {
} }
return null; return null;
} }
public String toXml(LectureParticipantSummary summary) {
if(summary == null) return null;
return summaryXStream.toXML(summary);
}
public LectureParticipantSummary summaryFromXml(String xml) {
if(StringHelper.containsNonWhitespace(xml)) {
try {
Object obj = summaryXStream.fromXML(xml);
if(obj instanceof LectureParticipantSummary) {
return (LectureParticipantSummary)obj;
}
} catch (Exception e) {
log.error("", e);
return null;
}
}
return null;
}
} }
...@@ -265,6 +265,16 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable, De ...@@ -265,6 +265,16 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable, De
return auditLogDao.rollCallFromXml(xml); return auditLogDao.rollCallFromXml(xml);
} }
@Override
public String toAuditXml(LectureParticipantSummary summary) {
return auditLogDao.toXml(summary);
}
@Override
public LectureParticipantSummary toAuditLectureParticipantSummary(String xml) {
return auditLogDao.summaryFromXml(xml);
}
@Override @Override
public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message, public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message,
LectureBlockRef lectureBlock, LectureBlockRollCall rollCall, LectureBlockRef lectureBlock, LectureBlockRollCall rollCall,
......
...@@ -36,6 +36,7 @@ import org.olat.core.gui.control.Event; ...@@ -36,6 +36,7 @@ import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControl;
import org.olat.core.id.Identity; import org.olat.core.id.Identity;
import org.olat.core.util.StringHelper; import org.olat.core.util.StringHelper;
import org.olat.modules.lecture.LectureBlockAuditLog;
import org.olat.modules.lecture.LectureParticipantSummary; import org.olat.modules.lecture.LectureParticipantSummary;
import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.LectureService;
import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntry;
...@@ -137,6 +138,7 @@ public class EditParticipantSummaryController extends FormBasicController { ...@@ -137,6 +138,7 @@ public class EditParticipantSummaryController extends FormBasicController {
@Override @Override
protected void formOK(UserRequest ureq) { protected void formOK(UserRequest ureq) {
String before = lectureService.toAuditXml(participantSummary);
String customRate = rateEl.getValue(); String customRate = rateEl.getValue();
if(StringHelper.containsNonWhitespace(customRate)) { if(StringHelper.containsNonWhitespace(customRate)) {
double val = Long.parseLong(customRate) / 100.0d; double val = Long.parseLong(customRate) / 100.0d;
...@@ -147,6 +149,9 @@ public class EditParticipantSummaryController extends FormBasicController { ...@@ -147,6 +149,9 @@ public class EditParticipantSummaryController extends FormBasicController {
participantSummary.setFirstAdmissionDate(firstAdmissionEl.getDate()); participantSummary.setFirstAdmissionDate(firstAdmissionEl.getDate());
participantSummary = lectureService.saveParticipantSummary(participantSummary); participantSummary = lectureService.saveParticipantSummary(participantSummary);
lectureService.recalculateSummary(entry, assessedIdentity); lectureService.recalculateSummary(entry, assessedIdentity);
lectureService.auditLog(LectureBlockAuditLog.Action.updateSummary, before, lectureService.toAuditXml(participantSummary),
"", null, null, entry, assessedIdentity, getIdentity());
fireEvent(ureq, Event.DONE_EVENT); fireEvent(ureq, Event.DONE_EVENT);
} }
...@@ -156,8 +161,11 @@ public class EditParticipantSummaryController extends FormBasicController { ...@@ -156,8 +161,11 @@ public class EditParticipantSummaryController extends FormBasicController {
} }
private void doRemoveCustomRate(UserRequest ureq) { private void doRemoveCustomRate(UserRequest ureq) {
String before = lectureService.toAuditXml(participantSummary);
participantSummary.setRequiredAttendanceRate(null); participantSummary.setRequiredAttendanceRate(null);
participantSummary = lectureService.saveParticipantSummary(participantSummary); participantSummary = lectureService.saveParticipantSummary(participantSummary);
lectureService.auditLog(LectureBlockAuditLog.Action.removeCustomRate, before, lectureService.toAuditXml(participantSummary),
"", null, null, entry, assessedIdentity, getIdentity());
fireEvent(ureq, Event.DONE_EVENT); fireEvent(ureq, Event.DONE_EVENT);
} }
} }
...@@ -143,6 +143,12 @@ lectures.table.current=Aktueller Lektionenblock ...@@ -143,6 +143,12 @@ lectures.table.current=Aktueller Lektionenblock
lectures.table.next=N\u00E4chste Lektionenbl\u00F6cke lectures.table.next=N\u00E4chste Lektionenbl\u00F6cke
lectures.table.pending=Pendente Lektionenbl\u00F6cke lectures.table.pending=Pendente Lektionenbl\u00F6cke
log=Log log=Log
log.add.admission.date=Erstzulassungdatum hinzugef\u00FCgt: {0}
log.add.rate=Schwellwert hinzugef\u00FCgt: {0}
log.change.admission.date=Erstzulassungdatum angepasst: {0}
log.change.rate=Schwellwert angepasst: {0}
log.remove.admission.date=Erstzulassungdatum entfernt
log.remove.rate=Schwellwert entfernt
managed.flags.lecture.block.all=Vollst\u00E4ndige externe Verwaltung managed.flags.lecture.block.all=Vollst\u00E4ndige externe Verwaltung
managed.flags.lecture.block.compulsory=Zwingend managed.flags.lecture.block.compulsory=Zwingend
managed.flags.lecture.block.dates=Datum managed.flags.lecture.block.dates=Datum
......
...@@ -143,6 +143,12 @@ lectures.table.current=Current lecture block ...@@ -143,6 +143,12 @@ lectures.table.current=Current lecture block
lectures.table.next=Next lecture blocks lectures.table.next=Next lecture blocks
lectures.table.pending=Pending lecture blocks lectures.table.pending=Pending lecture blocks
log=Log log=Log
log.add.admission.date=Add admission date {0}
log.add.rate=Add attendance rate {0}
log.change.admission.date=Update admission date {0}
log.change.rate=Update attendance rate {0}
log.remove.admission.date=Remove admission date
log.remove.rate=Remove attendance rate
managed.flags.lecture.block.all=Fully externally managed managed.flags.lecture.block.all=Fully externally managed
managed.flags.lecture.block.compulsory=Compulsory managed.flags.lecture.block.compulsory=Compulsory
managed.flags.lecture.block.dates=Dates managed.flags.lecture.block.dates=Dates
......
...@@ -31,6 +31,7 @@ import org.olat.core.CoreSpringFactory; ...@@ -31,6 +31,7 @@ import org.olat.core.CoreSpringFactory;
import org.olat.core.gui.translator.Translator; import org.olat.core.gui.translator.Translator;
import org.olat.core.logging.OLog; import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing; import org.olat.core.logging.Tracing;
import org.olat.core.util.Formatter;
import org.olat.core.util.StringHelper; import org.olat.core.util.StringHelper;
import org.olat.core.util.openxml.OpenXMLWorkbook; import org.olat.core.util.openxml.OpenXMLWorkbook;
import org.olat.core.util.openxml.OpenXMLWorkbookResource; import org.olat.core.util.openxml.OpenXMLWorkbookResource;
...@@ -40,6 +41,7 @@ import org.olat.modules.lecture.LectureBlock; ...@@ -40,6 +41,7 @@ import org.olat.modules.lecture.LectureBlock;
import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockAuditLog;
import org.olat.modules.lecture.LectureBlockRef; import org.olat.modules.lecture.LectureBlockRef;
import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureBlockRollCall;
import org.olat.modules.lecture.LectureParticipantSummary;
import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.LectureService;
import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryManager;
...@@ -58,6 +60,7 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -58,6 +60,7 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
private static final OLog log = Tracing.createLoggerFor(LectureBlockAuditLogExport.class); private static final OLog log = Tracing.createLoggerFor(LectureBlockAuditLogExport.class);
protected final Translator translator; protected final Translator translator;
protected final Formatter formatter;
private final boolean authorizedAbsenceEnabled; private final boolean authorizedAbsenceEnabled;
private final List<LectureBlockAuditLog> auditLog; private final List<LectureBlockAuditLog> auditLog;
...@@ -74,6 +77,7 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -74,6 +77,7 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
this.auditLog = auditLog; this.auditLog = auditLog;
this.translator = translator; this.translator = translator;
this.authorizedAbsenceEnabled = authorizedAbsenceEnabled; this.authorizedAbsenceEnabled = authorizedAbsenceEnabled;
formatter = Formatter.getInstance(translator.getLocale());
userManager = CoreSpringFactory.getImpl(UserManager.class); userManager = CoreSpringFactory.getImpl(UserManager.class);
lectureService = CoreSpringFactory.getImpl(LectureService.class); lectureService = CoreSpringFactory.getImpl(LectureService.class);
repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class); repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
...@@ -152,11 +156,16 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -152,11 +156,16 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
//planned / effective //planned / effective
LectureBlock auditBlock = null; LectureBlock auditBlock = null;
LectureBlockRollCall auditRollCall = null; LectureBlockRollCall auditRollCall = null;
LectureParticipantSummary auditSummary = null;
if(logEntry.getRollCallKey() != null) { if(logEntry.getRollCallKey() != null) {
auditRollCall = getAuditRollCall(logEntry.getAfter()); auditRollCall = getAuditRollCall(logEntry.getAfter());
} }
if(auditRollCall == null) { if(auditRollCall == null) {
auditBlock = getAuditLectureBlock(logEntry.getAfter()); if(logEntry.getLectureBlockKey() != null) {
auditBlock = getAuditLectureBlock(logEntry.getAfter());
} else {
auditSummary = getAuditLectureParticipantSummary(logEntry.getAfter());
}
} }
if(auditBlock != null) { if(auditBlock != null) {
...@@ -187,6 +196,16 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -187,6 +196,16 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
row.addCell(pos++, auditRollCall.getAbsenceReason(), null); row.addCell(pos++, auditRollCall.getAbsenceReason(), null);
} }
row.addCell(pos++, auditRollCall.getComment(), null); row.addCell(pos++, auditRollCall.getComment(), null);
} else if(auditSummary != null) {
Long assessedIdentityKey = logEntry.getIdentityKey();
String fullname = userManager.getUserDisplayName(assessedIdentityKey);
row.addCell(pos++, fullname);
pos += 2;
if(authorizedAbsenceEnabled) {
pos += 2;
}
String summaryComment = getSummaryComment(getAuditLectureParticipantSummary(logEntry.getBefore()), auditSummary);
row.addCell(pos++, summaryComment, null);
} else { } else {
pos += 4; pos += 4;
if(authorizedAbsenceEnabled) { if(authorizedAbsenceEnabled) {
...@@ -202,6 +221,40 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -202,6 +221,40 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
} }
} }
private String getSummaryComment(LectureParticipantSummary beforeSummary, LectureParticipantSummary afterSummary) {
StringBuilder sb = new StringBuilder();
Date beforeDate = beforeSummary == null ? null : beforeSummary.getFirstAdmissionDate();
Date afterDate = afterSummary.getFirstAdmissionDate();
if(beforeDate == null && afterDate != null) {
sb.append(translator.translate("log.add.admission.date", new String[]{ formatter.formatDate(afterDate) }));
} else if(beforeDate != null && afterDate == null) {
sb.append(translator.translate("log.remove.admission.date"));
} else if(beforeDate != null && afterDate != null && !beforeDate.equals(afterDate) ) {
sb.append(translator.translate("log.change.admission.date", new String[]{ formatter.formatDate(afterDate) }));
}
Double beforeRate = beforeSummary == null ? null : beforeSummary.getAttendanceRate();
Double afterRate = afterSummary.getAttendanceRate();
if(beforeRate == null && afterRate != null) {
sb.append(translator.translate("log.add.rate", new String[]{ toPercent(afterRate) }));
} else if(beforeRate != null && afterRate == null) {
sb.append(translator.translate("log.remove.rate"));
} else if(beforeRate != null && afterRate != null && !beforeRate.equals(afterRate)) {
sb.append(translator.translate("log.change.rate", new String[]{ toPercent(afterRate) }));
}
return sb.toString();
}
private String toPercent(Double value) {
if(value == null) return "";
double percent = value.doubleValue() * 100.0d;
long rounded = Math.round(percent);
return Long.toString(rounded).concat("%");
}
private LectureBlockRollCall getAuditRollCall(String xml) { private LectureBlockRollCall getAuditRollCall(String xml) {
return lectureService.toAuditLectureBlockRollCall(xml); return lectureService.toAuditLectureBlockRollCall(xml);
} }
...@@ -210,6 +263,10 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -210,6 +263,10 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
return lectureService.toAuditLectureBlock(xml); return lectureService.toAuditLectureBlock(xml);
} }
private LectureParticipantSummary getAuditLectureParticipantSummary(String xml) {
return lectureService.toAuditLectureParticipantSummary(xml);
}
protected void cacheRepositoryEntry(RepositoryEntry entry) { protected void cacheRepositoryEntry(RepositoryEntry entry) {
if(entry != null) { if(entry != null) {
displayNames.put(entry.getKey(), entry.getDisplayname()); displayNames.put(entry.getKey(), entry.getDisplayname());
...@@ -236,6 +293,8 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook ...@@ -236,6 +293,8 @@ public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbook
} }
private String getLectureBlockTitle(Long lectureBlockKey) { private String getLectureBlockTitle(Long lectureBlockKey) {
if(lectureBlockKey == null) return null;
String title = lectureBlockTitles.get(lectureBlockKey); String title = lectureBlockTitles.get(lectureBlockKey);
if(title == null) { if(title == null) {
LectureBlock block = lectureService.getLectureBlock(new LectureBlockRefForLog(lectureBlockKey)); LectureBlock block = lectureService.getLectureBlock(new LectureBlockRefForLog(lectureBlockKey));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment