diff --git a/src/main/java/org/olat/modules/coach/model/CoachingSecurity.java b/src/main/java/org/olat/modules/coach/model/CoachingSecurity.java index 3a2d82fdf06d38c7a602173cb084c90a66599f51..bbe1a0143eaccea9ddf92529ddc647ca753c2dc7 100644 --- a/src/main/java/org/olat/modules/coach/model/CoachingSecurity.java +++ b/src/main/java/org/olat/modules/coach/model/CoachingSecurity.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.modules.coach.model; /** diff --git a/src/main/java/org/olat/modules/lecture/LectureService.java b/src/main/java/org/olat/modules/lecture/LectureService.java index caf6315e9e0ce4d5654efe4115c603e1ab470d76..615cf9792ad5e856577a802fdf4b6dd87dd1aafc 100644 --- a/src/main/java/org/olat/modules/lecture/LectureService.java +++ b/src/main/java/org/olat/modules/lecture/LectureService.java @@ -26,6 +26,8 @@ import java.util.List; import org.olat.basesecurity.Group; import org.olat.basesecurity.IdentityRef; import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; import org.olat.modules.lecture.model.AbsenceNoticeInfos; import org.olat.modules.lecture.model.AggregatedLectureBlocksStatistics; import org.olat.modules.lecture.model.IdentityRateWarning; @@ -299,6 +301,10 @@ public interface LectureService { public AbsenceNotice updateAbsenceNotice(AbsenceNotice absenceNotice, Identity authorizer, List<RepositoryEntry> entries, List<LectureBlock> lectureBlocks); + public AbsenceNotice updateAbsenceNoticeAttachments(AbsenceNotice absenceNotice, List<VFSItem> newFiles, List<VFSItem> filesToDelete); + + public VFSContainer getAbsenceNoticeAttachmentsContainer(AbsenceNotice absenceNotice); + /** * Reload the absence notice. * diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java index 3d9d503531830ed9e81b241c51a5d4cc165ac8c0..b8a3d8035758301469abde9a73e5f0668d517c07 100644 --- a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java +++ b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java @@ -19,6 +19,8 @@ */ package org.olat.modules.lecture.manager; +import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; @@ -60,6 +62,10 @@ import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.vfs.LocalFolderImpl; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSManager; import org.olat.group.BusinessGroup; import org.olat.group.DeletableGroupData; import org.olat.modules.coach.model.IdentityRepositoryEntryKey; @@ -626,6 +632,63 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable, De } } + @Override + public AbsenceNotice updateAbsenceNoticeAttachments(AbsenceNotice absenceNotice, List<VFSItem> newFiles, List<VFSItem> filesToDelete) { + if(!filesToDelete.isEmpty()) { + for(VFSItem file:filesToDelete) { + file.delete(); + } + } + + if(!newFiles.isEmpty()) { + LocalFolderImpl rootContainer = getAbsenceNoticesAttachmentsPath(); + File rootDir = rootContainer.getBasefile(); + String noticeStorage = ((AbsenceNoticeImpl)absenceNotice).getAttachmentsDirectory(); + if(noticeStorage == null) { + File userDir = new File(rootDir, absenceNotice.getIdentity().getKey().toString()); + File noticeDir = new File(userDir, absenceNotice.getKey().toString()); + noticeDir.mkdirs(); + + Path relativePath = rootDir.toPath().relativize(noticeDir.toPath()); + noticeStorage = relativePath.toString(); + ((AbsenceNoticeImpl)absenceNotice).setAttachmentsDirectory(noticeStorage); + absenceNotice = absenceNoticeDao.updateAbsenceNotice(absenceNotice); + dbInstance.commit(); + } + + VFSItem noticeItem = rootContainer.resolve(noticeStorage); + if(noticeItem instanceof VFSContainer) { + VFSContainer noticeContainer = (VFSContainer)noticeItem; + for(VFSItem file:newFiles) { + noticeContainer.copyFrom(file); + } + } + } + + return absenceNotice; + } + + + @Override + public VFSContainer getAbsenceNoticeAttachmentsContainer(AbsenceNotice absenceNotice) { + if(absenceNotice == null || absenceNotice.getKey() == null) return null; + + LocalFolderImpl rootContainer = getAbsenceNoticesAttachmentsPath(); + VFSItem userItem = rootContainer.resolve(absenceNotice.getIdentity().getKey().toString()); + if(userItem instanceof VFSContainer) { + VFSContainer userContainer = (VFSContainer)userItem; + VFSItem noticeItem = userContainer.resolve(absenceNotice.getKey().toString()); + if(noticeItem instanceof VFSContainer) { + return (VFSContainer)noticeItem; + } + } + return null; + } + + private LocalFolderImpl getAbsenceNoticesAttachmentsPath() { + return VFSManager.olatRootContainer("/lectures/notices/", null); + } + @Override public AbsenceNotice getAbsenceNotice(AbsenceNoticeRef notice) { return absenceNoticeDao.loadAbsenceNotice(notice.getKey()); diff --git a/src/main/java/org/olat/modules/lecture/model/EditAbsenceNoticeWrapper.java b/src/main/java/org/olat/modules/lecture/model/EditAbsenceNoticeWrapper.java index ee0326daf7cb73ec2d24df11500713079e0b945e..c5d60a7a1f981813e446abc409bd735c420b1102 100644 --- a/src/main/java/org/olat/modules/lecture/model/EditAbsenceNoticeWrapper.java +++ b/src/main/java/org/olat/modules/lecture/model/EditAbsenceNoticeWrapper.java @@ -24,6 +24,8 @@ import java.util.Date; import java.util.List; import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; import org.olat.modules.lecture.AbsenceCategory; import org.olat.modules.lecture.AbsenceNotice; import org.olat.modules.lecture.AbsenceNoticeTarget; @@ -59,6 +61,10 @@ public class EditAbsenceNoticeWrapper { private List<LectureBlock> lectureBlocks; private List<LectureBlock> predefinedLectureBlocks; + + private VFSContainer tempUploadFolder; + private VFSContainer documentContainer; + private List<VFSItem> attachmentsToDelete = new ArrayList<>(); private EditAbsenceNoticeWrapper(AbsenceNotice notice) { absenceNotice = notice; @@ -215,6 +221,26 @@ public class EditAbsenceNoticeWrapper { this.identitiesToContact = identitiesToContact; } + public VFSContainer getTempUploadFolder() { + return tempUploadFolder; + } + + public void setTempUploadFolder(VFSContainer tempUploadFolder) { + this.tempUploadFolder = tempUploadFolder; + } + + public VFSContainer getDocumentContainer() { + return documentContainer; + } + + public void setDocumentContainer(VFSContainer documentContainer) { + this.documentContainer = documentContainer; + } + + public List<VFSItem> getAttachmentsToDelete() { + return attachmentsToDelete; + } + public void commitChanges(AbsenceNotice notice) { notice.setStartDate(startDate); notice.setEndDate(endDate); diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties index 0cf06b99f58954919726b328f0b0cab69bb8a562..00becb55136e6c185ef4479a18688d15415d0ff2 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties @@ -1,4 +1,4 @@ -#Mon Aug 19 16:40:37 CEST 2019 +#Tue Aug 20 13:54:27 CEST 2019 absence.category=Absenzenbegr\u00FCndung absence.category.copied=Absenzenbegr\u00FCndung wurde erfolgreich kopiert. absence.category.copy={0} (Kopie) @@ -50,6 +50,7 @@ appeals.title=Rekursliste appeals.update.title=Edit {0} Rekurs archive.entry=Archivierung assessment.tool=Bewertungswerkzeug +attachment.upload=Artzzeugnis, Best\u00E4tigung etc. attendance.list=Absenzenliste attendance.list.title=Absenzenliste\: {0} attendance.list.to.sign=Pr\u00E4senzliste diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties index 508e35f073ef346abd250d2b382ac2ead3817998..2ee51ee8aa577f83ea9f546be1adf8f51e71e239 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties @@ -1,484 +1,485 @@ -#Mon Aug 19 18:54:56 CEST 2019 -edit.reason=Edit reason -table.legend.free=Free lecture -config.override.no=No -table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> -lecture.block.effective.reason=Reason -authorized.absence.reason=Reason -table.header.date=Date -lecture.mastercoach.can.authorize.appeal=Master coaches can authorize appeals -noticed.teachers=Teachers -participant.rate.edit=Personal rate -table.header.participants=Participants -empty.table.lectures.blocks=There are no lectures to display. -noticed.type.notified=Notice of absence -infos.participant.attendance.rate=Personal attendance rate\: {0}% -lecture.mastercoach.can.see.appeal=Master coaches can see appeals -table.header.attended.lectures=Attended -noticed.type.dispensation=Dispensation -coach.absence=Absences -add.reason=Add reason -search.form.string.hint=You can search title of lecture blocks and title or external reference of courses. External reference is an exact match. -lecture.calculate.attendance.rate.default.enabled=Calculate attendance rate (default) -lecture.course.admin.title=Configuration of lectures and absence management in course -appeal.approved=Approved -add.assessment.mode=Mark as exam +#Tue Aug 20 13:54:06 CEST 2019 +absence.category=Reason of absence absence.category.copied=Reason of absence was successfully copied. -user.overview.appeals=Appeals -profile=Profile -add.dispensation.title=Record dispensation +absence.category.copy={0} (copie) +absence.category.description=Description +absence.category.in.use=This reason of absence is still used by some notices and cannot be deleted. +absence.category.title=Reason of the absence +absences.batch.authorize=Authorize absence +absences.title=List of absences active=Active -pdf.table.header.signature=Signature -absence.category=Reason of absence +add.absence=Record new absence +add.absence.category=Add absences reason +add.absence.title=Record an absence +add.assessment.mode=Mark as exam +add.dispensation=Record new dispensation +add.dispensation.title=Record dispensation +add.lecture=New lecture block +add.notice.absence=Record new notice of absence +add.notice.absence.title=Record notice of absence +add.reason=Add reason +admin.menu.title=Lectures +admin.menu.title.alt=Lectures and absence management +afternoon=Afternoon +aggregated.list=Aggregated list +alert.appeal.pending=<strong>A</strong> pending appeal was found. +alert.appeals.pending=<strong>{0}</strong> pending appeals was found. +all=All +all.desc=Mark all lectures as absent +all.teachers.switch=All teachers all.teachers.switch.tooltip.off=Show all lecture blocks -sync.course.calendar.enabled=Synchronize courses calendars -no.teachers=No coaches yet -cockpit.pending.days=There is some lectures which are not already closed. Please record the absences for the following day\: -table.header.lecture.9=9 -lectures.with.curriculum=Absences within a curriculum -table.header.lecture.1=1 -noticed.targets=Absence for -partiallydone=Partially done -table.header.absent.lectures=Absent -table.header.lecture.2=2 -table.header.lecture.3=3 -pdf.table.header.all=All -table.header.lecture.4=4 -rate.error.title=The attendance rate is under the mandatory limit. -table.header.lecture.5=5 -export.header.location=Room\: {0} -table.header.lecture.6=6 -table.header.lecture.7=7 -multi.rollcall.callee.title=Daily overview -noticed.identity=Absent person -table.header.lecture.8=8 -config.sync.course.calendar=Synchronize course calendar -table.legend.authorized=Authorized absence -edit.absence.category=Edit reason of absence -log.remove.rate=Remove attendance rate -contact.teachers=Contact teachers -assessment.tool=Assessment tool -lecture.block.dateAndTime={2} from {3} to {4} -lecture.absence.default.authorized=Absence per default authorized -absence.category.in.use=This reason of absence is still used by some notices and cannot be deleted. -lecture.teacher.can.authorize.absence=Teachers can authorize absences -import.lectures=Import lecture blocks -date.end=$org.olat.repository\:cif.date.end -lecture.mastercoach.can.see.absence=Master coaches can see absences -lecture.groups=Course / groups / curriculum -search.form.login=Username +all.teachers.switch.tooltip.on=Show only my lecture blocks +appeal=Appeal +appeal.approved=Approved +appeal.batch.update=Change status +appeal.body=<p>Dear {1}</p> +appeal.body.title=<h4>Appeal of the following lecture block\:</h4><p><a href\="{3}">{3}</a></p> +appeal.closed=Closed +appeal.contact.list=Teacher +appeal.form.explain=The decision need to be motivated. +appeal.from=From {0} +appeal.pending=Pending +appeal.rejected=Rejected +appeal.sent=Send at {0} +appeal.sent.tooltip=Appeal was sent at {0} +appeal.status=Status +appeal.subject=Appeal lecture block "{0}" +appeal.title=Appeal for\: "{0}" +appeal.tooltip=Appeal possible from {0} until {1} +appeals.title=List of appeals appeals.update.title=Edit {0} appeal(s) +archive.entry=Archive +assessment.tool=Assessment tool +attachment.upload=Doctor's certificate, justification etc. attendance.list=Absence list +attendance.list.title=Absence list\: {0} +attendance.list.to.sign=Attendance list +attendance.list.to.sign.title=Attendance list\: {0} +authorized.absence=Authorized +authorized.absence.reason=Reason +autoclosed=Auto-closed +bulk=User names, $org.olat.user.propertyhandlers\:table.name.email oder $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier +bulk.example=test01<br>author02<br>test@openolat.org +bulk.hint=You can give a list of user names or email addresses separated by a return. +cancel.lecture.blocks=Cancel lectures +cancelled=Cancelled +close.lecture.blocks=Close lectures +close.lecture.blocks.confirmation={0} lectures at {1} will be closed. +close.lecture.blocks.day=Close lectures for {0} +closed=Closed +coach.absence=Absences +coach.appeals=Appeals +coach.cockpit=Cockpit +coach.dispensation=Notices of absence / dispensation coach.lectures=Lectures -detailled.list=Detailled list -lecture.admin.global.title=Global configuration -table.header.authorized.absence=Excused -user.overview.lectures=Lectures and absences -delete.assessment.mode=Delete exam -lecture.block.copied=The lectures block was successfully copied. -dates.public=$org.olat.repository\:cif.dates.public -start.desktop=Desktop -appeal.body=<p>Dear {1}</p> -lecture.teacher=Teacher -table.header.owners=Course owners -lecture.start=Begin -add.absence=Record new absence -noticed.type=Type +coach.lectures.search=User search +coach.report=Report +cockpit.absences=Absences +cockpit.date=for {0} +cockpit.day.overview=Daily overview +cockpit.lectures=Lectures cockpit.lectures.day.list=You don't have any lectures this day. -user.profil=User profil -save.next=Save and next -not.authorized.absence=Not authorized -managed.flags.lecture.block.preparation=Preparation -noticed.lectures=Lectures -table.header.num.lecture.block=Lectures -search.form.status.open=$\:open -table.header.log.user=User -tool.teacher=As teacher -rollcall.tooltip.absence=Absent +cockpit.pending.day={0} {1} ({2} lectures) cockpit.pending.day.plural={0} {1} ({2} lectures) -lecture.show.all.teachers.mine=Only my lectures block +cockpit.pending.days=There is some lectures which are not already closed. Please record the absences for the following day\: +cockpit.pending.days.plural=There is some lectures which are not already closed. Please record the absences for the following days\: +config.calculate.attendance.rate=Calculate attendance rate +config.override=Override default configuration +config.override.no=No +config.override.yes=Yes +config.rollcall.enabled=Roll call enabled +config.sync.course.calendar=Synchronize course calendar +config.sync.participant.calendar=Synchronize participants calendar +config.sync.teacher.calendar=Synchronize teacher calendar confirm.delete.absence.category=Do you really want to delete this reason of absence "{0}"? -lecture.can.override.standard.configuration=Allow override of configuration -close.lecture.blocks=Close lectures -mail.subject=Subject -num.warnings.notice.absence.explain={0} of unauthorized notice(s) of absence -pdf.table.header.comment=Comment -search.form.till=till -absences.batch.authorize=Authorize absence -first.admission=First admission -pdf.table.header.lectures=Lectures -attendance.list.to.sign=Attendance list -multi.rollcall.callee.title.for=for {0} -rollcall.absence.notice=Notice of absence -appeal.rejected=Rejected -notice.search=Search -save.temporary=Quick save -search.form.category=Reason -appeal.body.title=<h4>Appeal of the following lecture block\:</h4><p><a href\="{3}">{3}</a></p> -absences.title=List of absences -coach.lectures.search=User search -lecture.daily.batch.absence.start=No, first at start time of lecture blocks -lecture.teacher.reminder.body=Reminder lectures block "{0}" in course {3} -previous.participant=Back to previous participant -rollcall=Roll call -managed.flags.lecture.block.plannedLectures=Planned lectures -rollcall.coach.hint=Note\: absences are recorded per lesson. If more than the half a lesson is missed, the lesson is entered as an absence. -appeal.pending=Pending -table.header.num.absences=Number of absent participants -noticed.absence.unauthorized=Absent -repo.lectures.appeals=Appeals -cockpit.lectures=Lectures -close.lecture.blocks.day=Close lectures for {0} -info.no.lectures=You don't follow any lectures for the moment. -entry.rate=Course's rate -table.header.unauthorized.absence=Not excused -lecture.assessment.mode.enabled=Allow assessment mode for lectures -num.alert.absence.explain={0} of unauthorized absence(s) -pdf.table.dates={0} from {1} to {2} -lecture.participant.can.notice=Participants are allowed to notify an absence -public.dates=$org.olat.repository\:cif.public.dates -table.header.external.ref=Ext. ref. -lecture.assessment.mode.seb=Safe Exam Browser Keys -lecture.time.until=until -search.date=Date -lecture.teacher.reminder.subject=Reminder lectures block "{0}" -reason.id=ID -sync.participants.calendar.enabled=Synchronize participants calendars -warning.choose.at.least.one.appeal=You need to choose at least one appeal -lecture.time=Time -filter.showAll=Show all -table.header.planned.lectures=Lectures +confirm.delete.assessment.mode.text=Do you really want to delete the exam of this lecture block "{0}"? confirm.delete.assessment.mode.title=Delete exam -lecture.taxonomy=Taxonomy -lecture.status.enabled=Lectures status -noticed.type.absence=Without notification -in.progress=In process +confirm.delete.lectures=Do you really want to delete these lectures "{0}"? +confirm.delete.reason=Do you really want to delete this reason "{0}"? +contact.teachers=Contact teachers +contact.teachers.list.name=Teachers +copy=Copy +current.lecture=Current lectures +date.end=$org.olat.repository\:cif.date.end +date.start=$org.olat.repository\:cif.date.start +dates=$org.olat.repository\:cif.dates +dates.none=$org.olat.repository\:cif.dates.none +dates.private=$org.olat.repository\:cif.dates.private +dates.public=$org.olat.repository\:cif.dates.public +delete.assessment.mode=Delete exam +delete.lectures.title=Delete lectures +delete.title=Delete reason +detailled.list=Detailled list +details=Details +dispensations.title=Notices of absence / dispensations +done=Done +edit.absence.category=Edit reason of absence +edit.assessment.mode=Edit exam +edit.participant.rate=Edit participant's rate +edit.reason=Edit reason +edit.type.absence=Edit absence +edit.type.dispensation=Edit dispensation +edit.type.notice.absence=Edit notice of absence +effective.lectures=Effective lectures +empty.absences.list=There isn't any absences/dispensations with the wished criteria. +empty.appeals.list=There is no appeal which meets your criteria. +empty.lectures.list=The table is empty +empty.repository.entry.lectures=You haven't need to follow a lecture in the course. +empty.table.current.lectures.blocks=There are not lectures to start at the moment. +empty.table.lectures.blocks=There are no lectures to display. +empty.table.lectures.blocks.admin=No lecture blocks have been created for this course so far. empty.table.participant.list=No roll calls have been made for this course so far. -lecture.count.authorized.absence.attendant=Count authorized absence as attendant -lectures.table.pending=Pending lecture blocks -search.form.type=Type +entry.rate=Course's rate +error.atleastone.lecture=Please choose at least one lecture block. +error.collision=There is already an absence at these dates. +error.integer.between=The input must be a number between {0} and {1} +error.integer.positive=The number must be positive. +error.reason.mandatory=Reason is mandatory +error.search.form.notempty=Please fill in at least one field with two characters. error.unauthorized.absence.msg=<strong>A</strong> unauthorized absence was found. -notice.reason.title=Reason of absence -several.entries=Several -override.lecture=Override external management -export.header.lectures=Lectures -managed.flags.lecture.block.groups=Course / groups -lecture.descr=Description -bulk.example=test01<br>author02<br>test@openolat.org -noticed.target.all=All courses -cancelled=Cancelled -appeal.title=Appeal for\: "{0}" -bulk=User names, $org.olat.user.propertyhandlers\:table.name.email oder $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier -lectures.admin.reasons=Reasons lectures -absence.category.title=Reason of the absence -table.legend.attended=Attended -lecture.autoclose.notification.subject=Lecture block "{0}" autoerledigt -authorized.absence=Authorized -appeal.batch.update=Change status -lecture.admin.course.override.title=Configuration - can be overridden at course level -coach.report=Report -search.form.status.reopen=$\:reopen -lecture.assessment.mode.ips=Admissible IP addresses -table.header.absence=Absence -lecture.block.comment=Comment -lectures.table.current=Current lecture block -repo.lectures=Lectures -admin.menu.title.alt=Lectures and absence management -managed.flags.lecture.block.settings=Configuration -menu.my.lectures.alt=Lectures and absences -search.curriculums=Search by curriculums -edit.participant.rate=Edit participant's rate -notice.dates.lectures.title=Context -form.managedflags.intro.short=This lecture block has been created by an external tool. Therefore some settings can not be modified and used within OpenOlat. -appeal.closed=Closed -lecture.status.partially.done.enabled=Allow holding partial lectures -delete.lectures.title=Delete lectures +error.unauthorized.absences.msg=<strong>{0}</strong> unauthorised absences was found. evening=Evening -lectures.repository.print.title=Lectures and absences of {1} in course {0} -rollcall.status=Roll call status -unauthorized.filter=Unauthorized -table.header.preparation=Preparation -confirm.delete.assessment.mode.text=Do you really want to delete the exam of this lecture block "{0}"? -tool.participant=As participant -noticed.duration=Duration -reason.copied=Reason was successfully copied. -table.header.progress=Grafik -open.course=Open course -error.atleastone.lecture=Please choose at least one lecture block. -mail.body=Message -lecture.appeal.absence.enabled=Appeal absence enabled -all=All -cancel.lecture.blocks=Cancel lectures -rollcall.dispensation=Dispensation -dispensations.title=Notices of absence / dispensations -unauthorized.filter.label=Display -table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> -table.legend.absent=Absent +export.footer.lectures.hint=x \= lecture absent export.header.entry=Course\: {0} -table.header.id=ID -site.title.alt=Lectures management -search.form.string=Search -start.mobile=Mobile -log.add.admission.date=Add admission date {0} -table.header.rate=Presence -lecture.time.from=from -managed.flags.lecture.block.compulsory=Compulsory -reason.deleted=Reason was successfully deleted. -search.participants=Search by participants -empty.table.current.lectures.blocks=There are not lectures to start at the moment. -lecture.show.all.teachers.all=Lectures block of all teachers -attendance.list.to.sign.title=Attendance list\: {0} -total=Total -table.header.log.effective.lectures=Effective lectures -lecture.auto.close.period=Auto close period in days -rollcall.tooltip.authorized.absence=Authorized absence -today=Today -lecture.reminder.period=Reminder period in days -noticed.notice.absence=Notice of absence -search.form.status=Status -table.header.absences.alert=Number of unauthorized absences -table.header.log.planned.lectures=Planned lectures -noticed.duration.days=Day choice -unoverride.lecture=Stop override -appeal.subject=Appeal lecture block "{0}" -coach.cockpit=Cockpit -table.header.import.status=Status -noticed.till=till +export.header.lectureblocks=Lectures block\: {0} the {1} at {2} until {3} +export.header.lectures=Lectures +export.header.location=Room\: {0} +export.header.teachers=Teachers\: {0} +filter.mandatory=Compulsory +filter.showAll=Show all +filter.warning=Warnings +first.admission=First admission +form.managedflags.intro=This lecture block has been created by an external tool. Therefore some settings and modules can not be modified and used within OpenOlat. The following elements are blocked within OpenOlat\: {0} +form.managedflags.intro.short=This lecture block has been created by an external tool. Therefore some settings can not be modified and used within OpenOlat. +from=from {0} +import.lectures=Import lecture blocks +in.progress=In process +info.lecture.block.optional=This lecture block is optional. +info.no.lectures=You don't follow any lectures for the moment. +infos.participant.attendance.rate=Personal attendance rate\: {0}% +interceptor.start=You have now a roll call for the course "{0}" {1} from {4} until {5}. +lecture.absence.default.authorized=Absence per default authorized +lecture.admin.course.override.title=Configuration - can be overridden at course level +lecture.admin.enabled=Enable lectures and absence management +lecture.admin.global.title=Global configuration +lecture.appeal.absence.enabled=Appeal absence enabled +lecture.appeal.absence.period=Appeal absence period in days +lecture.assessment.mode.enabled=Allow assessment mode for lectures +lecture.assessment.mode.followup.time=Follow-up +lecture.assessment.mode.ips=Admissible IP addresses +lecture.assessment.mode.leading.time=Prep time +lecture.assessment.mode.seb=Safe Exam Browser Keys lecture.attendance.rate.default=Attendance quota global in % -reason.copy={0} (Copy) -reason=Reason -error.search.form.notempty=Please fill in at least one field with two characters. -pdf.table.header.participants=First name / last name -table.header.num.participants=\# -noticed.dispensation=Dispensation -tools.import.table=Import lecture blocks from Excel +lecture.authorized.absence.enabled=Authorized absences +lecture.auto.close.period=Auto close period in days +lecture.autoclose.notification.body=<p>Dear course administrator</p><p>We want inform you that the lecture block was closed automatically. With the following link, you can access the lecture block\:<br><a href\='{3}'>{3}</a></p> +lecture.autoclose.notification.subject=Lecture block "{0}" autoerledigt +lecture.block=Lectures block +lecture.block.comment=Comment +lecture.block.copied=The lectures block was successfully copied. +lecture.block.copy={0} (Copy) +lecture.block.dateAndTime={2} from {3} to {4} +lecture.block.effective.end=Effective end +lecture.block.effective.reason=Reason +lecture.block.status=Status +lecture.calculate.attendance.rate.default.enabled=Calculate attendance rate (default) +lecture.can.override.standard.configuration=Allow override of configuration +lecture.compulsory=Compulsory +lecture.count.authorized.absence.attendant=Count authorized absence as attendant +lecture.course.admin.title=Configuration of lectures and absence management in course +lecture.daily.batch.absence=Daily recording absences +lecture.daily.batch.absence.day=Yes, recording of the absences of all lectures blocks of the day +lecture.daily.batch.absence.start=No, first at start time of lecture blocks lecture.date=Date -search.entries=Search by courses -table.legend.unauthorized=Not authorized absence -table.header.appeal.status=Appeal -wizard.entries.label.blocks=<strong>{0}</strong> <small>{1}</small> ({2} lectures blocks) -noticed.duration.today=Today -current.lecture=Current lectures -edit.assessment.mode=Edit exam -reason.in.use=This reason is still used by some lectures and cannot be deleted. -error.reason.mandatory=Reason is mandatory -filter.mandatory=Compulsory -table.header.compulsory.long=Compulsory presence +lecture.deleted=Lectures was successfully deleted. +lecture.descr=Description +lecture.end=End +lecture.from.to=Time from\: +lecture.from.to.format={0} until {1} +lecture.groups=Course / groups / curriculum +lecture.location=Location lecture.mastercoach.can.authorize.absence=Master coaches can authorize absences -morning=Morning -appeal.sent.tooltip=Appeal was sent at {0} -rollcall.tooltip.ok=Present -form.managedflags.intro=This lecture block has been created by an external tool. Therefore some settings and modules can not be modified and used within OpenOlat. The following elements are blocked within OpenOlat\: {0} -repo.settings=Configuration -empty.repository.entry.lectures=You haven't need to follow a lecture in the course. -rollcall.absence=Absence -cockpit.absences=Absences -absence.category.copy={0} (copie) -appeal.sent=Send at {0} -lectures.admin.permissions=Permissions -aggregated.list=Aggregated list -multi.rollcall.title.for=for {0} ({1} lecture blocks) -warning.repositoryentry.deleted=$org.olat.repository\:repositoryentry.deleted -coach.dispensation=Notices of absence / dispensation -appeal.status=Status -multi.rollcall.title=Multi-lectures recording +lecture.mastercoach.can.authorize.appeal=Master coaches can authorize appeals +lecture.mastercoach.can.record.notice=Master coaches can record notice of absences +lecture.mastercoach.can.see.absence=Master coaches can see absences +lecture.mastercoach.can.see.appeal=Master coaches can see appeals lecture.owner.can.view.all.curriculum.elements=Course owner can see all courses in curriculum elements -table.header.lecture.block=Lecture block -error.integer.between=The input must be a number between {0} and {1} +lecture.participant.can.notice=Participants are allowed to notify an absence lecture.preparation=Preparation -upto=till {0} -lecture.title=Title +lecture.reminder.enabled=Reminder enabled +lecture.reminder.period=Reminder period in days +lecture.rollcall.default.enabled=Roll call enabled (default) +lecture.show.all.teachers=Default display in course +lecture.show.all.teachers.all=Lectures block of all teachers +lecture.show.all.teachers.mine=Only my lectures block +lecture.start=Begin +lecture.status.enabled=Lectures status +lecture.status.partially.done.enabled=Allow holding partial lectures +lecture.taxonomy=Taxonomy +lecture.teacher=Teacher +lecture.teacher.can.authorize.absence=Teachers can authorize absences +lecture.teacher.can.authorize.appeal=Teachers can authorize appeals lecture.teacher.can.see.appeal=Teachers can see appeals -appeal=Appeal -info.lecture.block.optional=This lecture block is optional. -notice.start.date=Start date -table.header.presence=Present +lecture.teacher.reminder.body=Reminder lectures block "{0}" in course {3} +lecture.teacher.reminder.subject=Reminder lectures block "{0}" +lecture.time=Time +lecture.time.from=from +lecture.time.until=until +lecture.title=Title +lectures.admin.absences.categories=Reasons absences +lectures.admin.permissions=Permissions +lectures.admin.permissions.title=Teachers / master coaches permissions +lectures.admin.reasons=Reasons lectures +lectures.admin.report=Lectures report +lectures.admin.settings=Settings lectures and absence management +lectures.print.title=Lectures and absences of {0} +lectures.repository.print.title=Lectures and absences of {1} in course {0} +lectures.table.closed=Closed lecture blocks +lectures.table.current=Current lecture block +lectures.table.next=Next lecture blocks +lectures.table.pending=Pending lecture blocks +lectures.with.curriculum=Absences within a curriculum +lectures.without.curriculum=Absences outside of a curriculum +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 +mail.body=Message +mail.subject=Subject +managed.flags.lecture.block.all=Fully externally managed +managed.flags.lecture.block.compulsory=Compulsory +managed.flags.lecture.block.dates=Dates +managed.flags.lecture.block.delete=Delete lectures block +managed.flags.lecture.block.description=Description managed.flags.lecture.block.details=Title, description... -table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> -num.warnings.dispensation.explain={0} of unauthorized dispensation -closed=Closed -appeal.from=From {0} -appeal.form.explain=The decision need to be motivated. -repo.participants=Participants -managed.flags.lecture.block.title=Title -open=Open -table.header.comment=Comment -add.notice.absence.title=Record notice of absence -noticed.duration.exact=Exact (with daytime) -rollcall.comment=Comment -cockpit.date=for {0} -error.collision=There is already an absence at these dates. -noticed.reason=Comment -table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> -lecture.block=Lectures block -table.header.start.time=From -lecture.block.copy={0} (Copy) -edit.type.notice.absence=Edit notice of absence -details=Details -add.lecture=New lecture block -table.header.notice.type=Type -results=Results -table.header.identifier=Identifier -reason.title=Reason -date.start=$org.olat.repository\:cif.date.start -lecture.assessment.mode.leading.time=Prep time -table.header.num.presences=Number of present participants -reopen=Reopen +managed.flags.lecture.block.groups=Course / groups managed.flags.lecture.block.location=Location -remove.custom.rate=Remove custom rate -interceptor.start=You have now a roll call for the course "{0}" {1} from {4} until {5}. -filter.warning=Warnings -export.header.lectureblocks=Lectures block\: {0} the {1} at {2} until {3} -alert.appeal.pending=<strong>A</strong> pending appeal was found. -sync.teachers.calendar.enabled=Synchronize teachers calendars -contact.teachers.list.name=Teachers -lecture.rollcall.default.enabled=Roll call enabled (default) -lectures.admin.settings=Settings lectures and absence management -table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> -all.desc=Mark all lectures as absent -add.dispensation=Record new dispensation +managed.flags.lecture.block.plannedLectures=Planned lectures +managed.flags.lecture.block.preparation=Preparation +managed.flags.lecture.block.settings=Configuration +managed.flags.lecture.block.teachers=Teacher +managed.flags.lecture.block.title=Title +menu.my.lectures=Absences +menu.my.lectures.alt=Lectures and absences +morning=Morning +multi.rollcall.callee.title=Daily overview +multi.rollcall.callee.title.for=for {0} +multi.rollcall.title=Multi-lectures recording +multi.rollcall.title.for=for {0} ({1} lecture blocks) +new.appeal.title=New appeal +next.participant=To the next participant +no.teachers=No coaches yet +not.authorized.absence=Not authorized +notice.dates.lectures.title=Context +notice.end.date=End date +notice.reason.title=Reason of absence +notice.search=Search +notice.start.date=Start date noticed.absence.authorized=Authorized -wizard.lectureblock.label=<strong>{0}</strong> <small>{1}</small><br>{2} {3} - {4} {5} lessons\: "{6}" with {7} -cockpit.pending.days.plural=There is some lectures which are not already closed. Please record the absences for the following days\: -table.header.description=Description +noticed.absence.unauthorized=Absent +noticed.autorized.yes=Authorized noticed.category=Justification -lecture.block.effective.end=Effective end -edit.type.absence=Edit absence -participant.rate=Rate -log.add.rate=Add attendance rate {0} -empty.appeals.list=There is no appeal which meets your criteria. -export.header.teachers=Teachers\: {0} -log.remove.admission.date=Remove admission date -table.header.log.effective.end.date=Effective end date -lectures.admin.absences.categories=Reasons absences -table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> -admin.menu.title=Lectures -confirm.delete.lectures=Do you really want to delete these lectures "{0}"? -export.footer.lectures.hint=x \= lecture absent -lecture.deleted=Lectures was successfully deleted. -table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> +noticed.dispensation=Dispensation +noticed.duration=Duration +noticed.duration.days=Day choice +noticed.duration.exact=Exact (with daytime) +noticed.duration.today=Today +noticed.entries=Courses +noticed.identity=Absent person +noticed.lectures=Lectures +noticed.notice.absence=Notice of absence +noticed.reason=Comment +noticed.target.all=All courses +noticed.target.courses=Selected courses +noticed.target.lectureblocks=Selected lecture blocks +noticed.targets=Absence for +noticed.teachers=Teachers +noticed.till=till +noticed.type=Type +noticed.type.absence=Without notification +noticed.type.dispensation=Dispensation +noticed.type.notified=Notice of absence +num.alert.absence.explain={0} of unauthorized absence(s) +num.warnings.dispensation.explain={0} of unauthorized dispensation +num.warnings.notice.absence.explain={0} of unauthorized notice(s) of absence +open=Open +open.course=Open course open.specific.course=Open "{0}" +override.lecture=Override external management +partiallydone=Partially done +participant.rate=Rate +participant.rate.edit=Personal rate +pdf.table.dates={0} from {1} to {2} +pdf.table.header.all=All +pdf.table.header.authorised=Auth. +pdf.table.header.comment=Comment +pdf.table.header.lectures=Lectures +pdf.table.header.participants=First name / last name +pdf.table.header.signature=Signature +planned.lectures=Planned lectures +previous.participant=Back to previous participant +private.dates=$org.olat.repository\:cif.private.dates +profile=Profile +public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=The attendance rate is under the mandatory limit. rate.warning.title=The attendance rate is close to the mandatory limit. -table.header.effective.lectures=Lectures -lectures.table.closed=Closed lecture blocks +reason=Reason +reason.copied=Reason was successfully copied. +reason.copy={0} (Copy) +reason.deleted=Reason was successfully deleted. +reason.description=Description +reason.id=ID +reason.in.use=This reason is still used by some lectures and cannot be deleted. +reason.title=Reason +remove.custom.rate=Remove custom rate +reopen=Reopen reopen.lecture.blocks=Reopen lectures -table.header.attended.current.rate=% Attended -noticed.target.lectureblocks=Selected lecture blocks -table.header.location=Location -config.override.yes=Yes -lectures.without.curriculum=Absences outside of a curriculum -close.lecture.blocks.confirmation={0} lectures at {1} will be closed. -search.form.status.closed=$\:closed -new.appeal.title=New appeal -empty.absences.list=There isn't any absences/dispensations with the wished criteria. -appeal.tooltip=Appeal possible from {0} until {1} -managed.flags.lecture.block.all=Fully externally managed -pdf.table.header.authorised=Auth. -dates=$org.olat.repository\:cif.dates -managed.flags.lecture.block.delete=Delete lectures block -error.integer.positive=The number must be positive. -menu.my.lectures=Absences +repo.lectures=Lectures +repo.lectures.appeals=Appeals +repo.lectures.block=Lecture blocks +repo.participants=Participants +repo.settings=Configuration +results=Results +rollcall=Roll call +rollcall.absence=Absence +rollcall.absence.notice=Notice of absence +rollcall.coach.hint=Note\: absences are recorded per lesson. If more than the half a lesson is missed, the lesson is entered as an absence. +rollcall.comment=Comment +rollcall.dispensation=Dispensation +rollcall.status=Roll call status +rollcall.tooltip.absence=Absent +rollcall.tooltip.authorized.absence=Authorized absence rollcall.tooltip.free=Free -lecture.end=End -add.absence.category=Add absences reason -managed.flags.lecture.block.dates=Dates -log.change.admission.date=Update admission date {0} -table.header.log.author=Changed by +rollcall.tooltip.ok=Present +rollcall.tooltip.unauthorized.absence=Not authorized absence +save.next=Save and next +save.temporary=Quick save +search.curriculums=Search by curriculums +search.date=Date +search.entries=Search by courses +search.form.category=Reason +search.form.end=Until +search.form.login=Username +search.form.start=Start +search.form.status=Status +search.form.status.autoclosed=$\:autoclosed +search.form.status.closed=$\:closed +search.form.status.open=$\:open +search.form.status.reopen=$\:reopen +search.form.string=Search +search.form.string.hint=You can search title of lecture blocks and title or external reference of courses. External reference is an exact match. +search.form.till=till +search.form.type=Type +search.participants=Search by participants search.teachers=Search by teachers -lecture.teacher.can.authorize.appeal=Teachers can authorize appeals -reason.description=Description -lecture.compulsory=Compulsory -planned.lectures=Planned lectures +send=Send +several.entries=Several +site.title=Lectures management +site.title.alt=Lectures management +start.desktop=Desktop start.label=Roll call -error.unauthorized.absences.msg=<strong>{0}</strong> unauthorised absences was found. -noticed.entries=Courses +start.mobile=Mobile start.wizard=Start wizard -log=Log -table.header.username=Username -search.form.start=Start -config.calculate.attendance.rate=Calculate attendance rate -tools=Action -lectures.admin.report=Lectures report -table.header.lecture.11=11 +sync.course.calendar.enabled=Synchronize courses calendars +sync.participants.calendar.enabled=Synchronize participants calendars +sync.teachers.calendar.enabled=Synchronize teachers calendars +table.header.absence=Absence +table.header.absences.alert=Number of unauthorized absences +table.header.absences.warning=Number of unauthorized dispensation and notices +table.header.absent.lectures=Absent +table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.appeal.status=Appeal +table.header.assessment.mode=Exam +table.header.attended.current.rate=% Attended +table.header.attended.lectures=Attended +table.header.authorized.absence=Excused +table.header.auto.close.date=Auto closed at +table.header.comment=Comment +table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> +table.header.compulsory.long=Compulsory presence +table.header.date=Date +table.header.description=Description +table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> +table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> +table.header.effective.lectures=Lectures +table.header.end.time=To +table.header.entry=Course +table.header.export=Export +table.header.external.ref=Ext. ref. +table.header.id=ID +table.header.identifier=Identifier +table.header.import.status=Status +table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> +table.header.lecture.1=1 table.header.lecture.10=10 -table.header.lecture.13=13 +table.header.lecture.11=11 table.header.lecture.12=12 -lecture.daily.batch.absence=Daily recording absences -private.dates=$org.olat.repository\:cif.private.dates +table.header.lecture.13=13 table.header.lecture.14=14 -copy=Copy -managed.flags.lecture.block.teachers=Teacher -noticed.target.courses=Selected courses -add.notice.absence=Record new notice of absence -appeal.contact.list=Teacher -table.header.teachers=Coaches -warning.edit.lecture=Roll call ist deactivated. -table.header.absences.warning=Number of unauthorized dispensation and notices -bulk.hint=You can give a list of user names or email addresses separated by a return. +table.header.lecture.2=2 +table.header.lecture.3=3 +table.header.lecture.4=4 +table.header.lecture.5=5 +table.header.lecture.6=6 +table.header.lecture.7=7 +table.header.lecture.8=8 +table.header.lecture.9=9 +table.header.lecture.block=Lecture block +table.header.location=Location table.header.log.action=Action -add.absence.title=Record an absence -dates.none=$org.olat.repository\:cif.dates.none -repo.lectures.block=Lecture blocks -rollcall.tooltip.unauthorized.absence=Not authorized absence -lecture.from.to.format={0} until {1} -appeals.title=List of appeals -lecture.block.status=Status -user.overview.dispensation=Dispensation -warning.teachers.at.least.one.contact=There isn't any teacher to contact -lecture.appeal.absence.period=Appeal absence period in days -next.participant=To the next participant -lectures.admin.permissions.title=Teachers / master coaches permissions -table.header.assessment.mode=Exam -lecture.autoclose.notification.body=<p>Dear course administrator</p><p>We want inform you that the lecture block was closed automatically. With the following link, you can access the lecture block\:<br><a href\='{3}'>{3}</a></p> -alert.appeals.pending=<strong>{0}</strong> pending appeals was found. -table.header.entry=Course -table.header.end.time=To -lectures.table.next=Next lecture blocks -table.header.times=Time -dates.private=$org.olat.repository\:cif.dates.private -from=from {0} -lectures.print.title=Lectures and absences of {0} -lecture.mastercoach.can.record.notice=Master coaches can record notice of absences -config.sync.participant.calendar=Synchronize participants calendar -table.header.auto.close.date=Auto closed at -config.sync.teacher.calendar=Synchronize teacher calendar +table.header.log.author=Changed by +table.header.log.effective.end.date=Effective end date +table.header.log.effective.lectures=Effective lectures +table.header.log.planned.lectures=Planned lectures +table.header.log.user=User +table.header.notice.type=Type +table.header.num.absences=Number of absent participants +table.header.num.lecture.block=Lectures +table.header.num.participants=\# +table.header.num.presences=Number of present participants +table.header.owners=Course owners +table.header.participants=Participants +table.header.planned.lectures=Lectures +table.header.preparation=Preparation +table.header.presence=Present +table.header.progress=Grafik +table.header.rate=Presence +table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> table.header.reason=Reason -done=Done -config.override=Override default configuration -cockpit.day.overview=Daily overview -lecture.from.to=Time from\: -notice.end.date=End date -lecture.reminder.enabled=Reminder enabled -all.teachers.switch=All teachers -search.form.end=Until -log.change.rate=Update attendance rate {0} -archive.entry=Archive -send=Send -noticed.autorized.yes=Authorized -lecture.show.all.teachers=Default display in course +table.header.start.time=From table.header.status=Status -lecture.authorized.absence.enabled=Authorized absences -attendance.list.title=Absence list\: {0} -managed.flags.lecture.block.description=Description -cockpit.pending.day={0} {1} ({2} lectures) -coach.appeals=Appeals -empty.table.lectures.blocks.admin=No lecture blocks have been created for this course so far. -edit.type.dispensation=Edit dispensation -autoclosed=Auto-closed -wizard.entries.label.block=<strong>{0}</strong> <small>{1}</small> ({2} lectures block) -lecture.assessment.mode.followup.time=Follow-up -lecture.daily.batch.absence.day=Yes, recording of the absences of all lectures blocks of the day -delete.title=Delete reason -effective.lectures=Effective lectures -empty.lectures.list=The table is empty -lecture.admin.enabled=Enable lectures and absence management +table.header.teachers=Coaches +table.header.times=Time +table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.unauthorized.absence=Not excused +table.header.username=Username +table.legend.absent=Absent +table.legend.attended=Attended +table.legend.authorized=Authorized absence +table.legend.free=Free lecture +table.legend.unauthorized=Not authorized absence +today=Today +tool.participant=As participant +tool.teacher=As teacher +tools=Action +tools.import.table=Import lecture blocks from Excel +total=Total +unauthorized.filter=Unauthorized +unauthorized.filter.label=Display +unoverride.lecture=Stop override +upto=till {0} +user.overview.appeals=Appeals +user.overview.dispensation=Dispensation +user.overview.lectures=Lectures and absences +user.profil=User profil +warning.choose.at.least.one.appeal=You need to choose at least one appeal +warning.edit.lecture=Roll call ist deactivated. +warning.repositoryentry.deleted=$org.olat.repository\:repositoryentry.deleted +warning.teachers.at.least.one.contact=There isn't any teacher to contact whole.day=Whole day -search.form.status.autoclosed=$\:autoclosed -all.teachers.switch.tooltip.on=Show only my lecture blocks -afternoon=Afternoon -absence.category.description=Description -site.title=Lectures management -table.header.export=Export -config.rollcall.enabled=Roll call enabled -confirm.delete.reason=Do you really want to delete this reason "{0}"? -lecture.location=Location +wizard.entries.label.block=<strong>{0}</strong> <small>{1}</small> ({2} lectures block) +wizard.entries.label.blocks=<strong>{0}</strong> <small>{1}</small> ({2} lectures blocks) +wizard.lectureblock.label=<strong>{0}</strong> <small>{1}</small><br>{2} {3} - {4} {5} lessons\: "{6}" with {7} diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties index 4485066225edd2dc36ad92306548ff986c6c0cee..c562a6d29bfa320e12c5dce7a5cd88b5506e974c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties @@ -1,405 +1,405 @@ -#Mon Aug 19 18:49:44 CEST 2019 -edit.reason=Editer la justification -table.legend.free=Le\u00E7on facultative -config.override.no=Non -table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> -lecture.block.effective.reason=Justification -authorized.absence.reason=Justification -table.header.date=Date -noticed.teachers=Charg\u00E9s de cours -table.header.participants=Participants -participant.rate.edit=Valeur seuil personelle -empty.table.lectures.blocks=Aucun cours bloc n'a \u00E9t\u00E9 trouv\u00E9. -infos.participant.attendance.rate=Valeur seuil personelle\: {0}% -table.header.attended.lectures=Pr\u00E9sent -coach.absence=Absences -add.reason=Cr\u00E9er une justification -search.form.string.hint=Vous pouvez chercher les titres d'un bloc de cours ou sa r\u00E9f\u00E9rence externe. Lors de la recherche avec la r\u00E9f\u00E9rence externe, seuls les r\u00E9sultats exacts sont affich\u00E9s. -lecture.calculate.attendance.rate.default.enabled=Calcul du taux de pr\u00E9sence -lecture.course.admin.title=Configuration des cours blocs et absences du cours -appeal.approved=Approuv\u00E9 -add.assessment.mode=Marqu\u00E9 comme \u00E9valuation +#Tue Aug 20 13:54:17 CEST 2019 +absence.category=Raison de l'absence absence.category.copied=La raison de l'absence a \u00E9t\u00E9 copi\u00E9 avec succ\u00E8s. -user.overview.appeals=Recours -profile=Profil +absence.category.copy={0} (copie) +absence.category.description=Description +absence.category.in.use=Cette raison d'absence est encore utilis\u00E9 par certaines notices d'absences et ne peut pas \u00EAtre effac\u00E9e. +absence.category.title=Raison de l'absence +absences.title=Liste d'absences active=Actif -pdf.table.header.signature=Signature -absence.category=Raison de l'absence +add.assessment.mode=Marqu\u00E9 comme \u00E9valuation +add.lecture=Cr\u00E9er un nouveau cours bloc +add.reason=Cr\u00E9er une justification +admin.menu.title=Cours blocs +admin.menu.title.alt=Administration des cours blocs et absences +afternoon=Apr\u00E8s-midi +aggregated.list=Liste consolid\u00E9e +alert.appeal.pending=<strong>Un</strong> recours en attente a \u00E9t\u00E9 trouv\u00E9. +alert.appeals.pending=<strong>{0}</strong> recours en attente ont \u00E9t\u00E9 trouv\u00E9s. +all=Tous +all.desc=Marqu\u00E9 toutes les le\u00E7ons comme absence +all.teachers.switch=Tous les charg\u00E9s de cours all.teachers.switch.tooltip.off=Montrer tous les cours blocs -sync.course.calendar.enabled=Synchroniser le calendrier du cours -no.teachers=Pas encore de charg\u00E9 de cours disponible -table.header.lecture.9=9 -lectures.with.curriculum=Absences du curriculum -table.header.lecture.1=1 -partiallydone=En partie termin\u00E9 -table.header.absent.lectures=Absences -table.header.lecture.2=2 -table.header.lecture.3=3 -pdf.table.header.all=Tous -table.header.lecture.4=4 -table.header.lecture.5=5 -rate.error.title=Le taux de pr\u00E9sence se situe sous la limite obligatoire. -export.header.location=Salle\: {0} -table.header.lecture.6=6 -table.header.lecture.7=7 -table.header.lecture.8=8 -noticed.identity=Personne absente -config.sync.course.calendar=Synchroniser le calendrier du cours -table.legend.authorized=Absence autoris\u00E9e -log.remove.rate=Valeur seuil enlev\u00E9e -assessment.tool=Outil d'\u00E9valuation -lecture.absence.default.authorized=Compter les absences par d\u00E9faut comme excus\u00E9es -lecture.block.dateAndTime={2} de {3} jusqu'\u00E0 {4} heure -absence.category.in.use=Cette raison d'absence est encore utilis\u00E9 par certaines notices d'absences et ne peut pas \u00EAtre effac\u00E9e. -lecture.teacher.can.authorize.absence=Les charg\u00E9s de cours peuvent excuser les absences -import.lectures=Importer des cours blocs -date.end=$org.olat.repository\:cif.date.end -lecture.groups=Cours / groupes / curriculum -search.form.login=Nom d'utilisateur -appeals.update.title=Edit {0} recours -attendance.list=Liste d'absences -coach.lectures=Cours -detailled.list=Liste d\u00E9taill\u00E9e -lecture.admin.global.title=Configuration globale -table.header.authorized.absence=Excus\u00E9 -delete.assessment.mode=Effacer l'\u00E9valuation -lecture.block.copied=Le cours bloc a \u00E9t\u00E9 copi\u00E9 avec succ\u00E8s. -dates.public=$org.olat.repository\:cif.dates.public -start.desktop=Bureau +all.teachers.switch.tooltip.on=Montrer seulement mes cours blocs +appeal=Recours +appeal.approved=Approuv\u00E9 +appeal.batch.update=Changer le status appeal.body=<p>Ch\u00E8re / Cher {1}</p><p>J'aimerais signaler que les absences de {2} ont \u00E9t\u00E9 \u00E0 mon avis saisies de mani\u00E8re incorrecte.</p><p>Raisons\:</p><p><span style\="color\: \#ff0000;">(entrez les raisons ici)</span></p><p>Merci d'avance de les v\u00E9rifier et pour les \u00E9ventuelles corrections.</p><p>Avec mes salutations distingu\u00E9es</p> -lecture.teacher=Charg\u00E9s de cours -table.header.owners=Propri\u00E9taire de cours -lecture.start=D\u00E9but -noticed.type=Type -cockpit.lectures.day.list=Vous n'avez pas de cours ce jour-l\u00E0. -user.profil=Profil de l'utilisateur -save.next=Sauver et continuer -managed.flags.lecture.block.preparation=Pr\u00E9paration/suivi -noticed.lectures=Cours-blocs -table.header.num.lecture.block=Cours -search.form.status.open=$\:open -table.header.log.user=Utilisateur -tool.teacher=Comme charg\u00E9 de cours -rollcall.tooltip.absence=Absence -lecture.show.all.teachers.mine=Seulement mes cours blocs -lecture.can.override.standard.configuration=Permettre de modifier la configuration standard -close.lecture.blocks=Termin\u00E9 le cours bloc -pdf.table.header.comment=Commentaire -search.form.till=jusqu'\u00E0 -first.admission=Premi\u00E8re admission -pdf.table.header.lectures=Cours bloc -attendance.list.to.sign=Liste de pr\u00E9sence -multi.rollcall.callee.title.for=pour {0} -appeal.rejected=Rejet\u00E9 -save.temporary=Sauver temporairement -search.form.category=Raisons appeal.body.title=<h4>Demande de recours pour le cours bloc suivant\:</h4><p><a href\="{3}">{3}</a></p> -absences.title=Liste d'absences -lecture.teacher.reminder.body=<p>Ch\u00E8re charg\u00E9e de cours<br>Cher charg\u00E9 de cours</p><p>Nous aimerions vous rappeler que vous devez encore noter les absences pour un cours bloc. Avec le lien ci-dessous vous m\u00E8nera directement au cours bloc en question\:<br><a href\='{3}'>{3}</a></p><p>Merci beaucoup\!</p><p>Votre administrateur de cours</p> -previous.participant=Participant pr\u00E9c\u00E9dent -rollcall=Contr\u00F4le de pr\u00E9sence -managed.flags.lecture.block.plannedLectures=Cours blocs pr\u00E9vus -rollcall.coach.hint=Note\: les absences sont enregistr\u00E9es pour chaque le\u00E7on. Si plus de la moiti\u00E9 d'une le\u00E7on est manqu\u00E9e, elle sera consid\u00E9r\u00E9e comme une absence. +appeal.closed=Termin\u00E9 +appeal.contact.list=Charg\u00E9 de cours +appeal.form.explain=La d\u00E9cision doit \u00EAtre motiv\u00E9e. +appeal.from=Depuis le {0} appeal.pending=Pendant -noticed.absence.unauthorized=Absent -repo.lectures.appeals=Appels -cockpit.lectures=Cours -info.no.lectures=Vous ne suivez pour l'instant aucun cours bloc. -entry.rate=Valeur seuil pour le cours -table.header.unauthorized.absence=Non excus\u00E9es -lecture.assessment.mode.enabled=Activer les \u00E9valuations pour cours blocs -pdf.table.dates={0} de {1} jusqu'\u00E0 {2} -public.dates=$org.olat.repository\:cif.public.dates -table.header.external.ref=R\u00E9f. ext. -lecture.assessment.mode.seb=Cl\u00E9s Safe Exam Browser -lecture.time.until=jusqu'\u00E0 -search.date=Date -lecture.teacher.reminder.subject=Rappel cours bloc "{0}" -reason.id=ID -sync.participants.calendar.enabled=Synchroniser le calendrier des participants -warning.choose.at.least.one.appeal=S'il-vous-pla\u00EEt, s\u00E9lectionnez au moins un recours. -lecture.time=Temps -filter.showAll=Tout montrer -table.header.planned.lectures=Le\u00E7ons -confirm.delete.assessment.mode.title=Effacer l'examen -lecture.taxonomy=Taxonomie -lecture.status.enabled=Status -in.progress=En cours -empty.table.participant.list=Aucun contr\u00F4le de pr\u00E9sence n'a \u00E9t\u00E9 effectu\u00E9 pour ce cours jusqu'\u00E0 maintenant. -lecture.count.authorized.absence.attendant=Compter les absences excus\u00E9es comme pr\u00E9sent -lectures.table.pending=Cours blocs en attente -search.form.type=Type -notice.reason.title=Raison de l'absence -several.entries=Plusieurs -override.lecture=Passer outre la gestion ext\u00E9rieure du cours -export.header.lectures=Cours blocs -managed.flags.lecture.block.groups=Cours / groupes -lecture.descr=Description -bulk.example=test01<br>author02<br>test@openolat.org -noticed.target.all=Tous les cours -cancelled=Annul\u00E9 +appeal.rejected=Rejet\u00E9 +appeal.sent=Envoy\u00E9 le {0} +appeal.sent.tooltip=Recours envoy\u00E9 le {0} +appeal.status=Statut +appeal.subject=Recours cours bloc "{0}" appeal.title=Recours pour\: "{0}" -bulk=Nom d'utilisateur, $org.olat.user.propertyhandlers\:table.name.email ou $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier -lectures.admin.reasons=Justifications absences -absence.category.title=Raison de l'absence -table.legend.attended=Pr\u00E9sent -lecture.autoclose.notification.subject=Cours bloc "{0}" boucl\u00E9 automatiquement +appeal.tooltip=Recours possible du {0} au {1} +appeals.title=Liste de recours +appeals.update.title=Edit {0} recours +archive.entry=Archivage +assessment.tool=Outil d'\u00E9valuation +attendance.list=Liste d'absences +attendance.list.title=Liste d'absence\: {0} +attendance.list.to.sign=Liste de pr\u00E9sence +attendance.list.to.sign.title=Liste de pr\u00E9sence\: {0} authorized.absence=Excus\u00E9 -lecture.admin.course.override.title=Configuration - modifiable au niveau du cours -appeal.batch.update=Changer le status -search.form.status.reopen=$\:reopen -lecture.assessment.mode.ips=Adresses IP autoris\u00E9es -table.header.absence=Pr\u00E9sences -lecture.block.comment=Remarques -lectures.table.current=Cours blocs en cours -repo.lectures=Cours blocs -admin.menu.title.alt=Administration des cours blocs et absences -managed.flags.lecture.block.settings=Configuration -menu.my.lectures.alt=Cours blocs et absences -search.curriculums=Recherche par curriculums -edit.participant.rate=Editer la valeur seuil personalis\u00E9e -form.managedflags.intro.short=Ce cours bloc a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Ses param\u00E8tres ne peuvent donc pas \u00EAtre chang\u00E9s dans OpenOlat. -appeal.closed=Termin\u00E9 -lecture.status.partially.done.enabled=Activer la possibilit\u00E9 de le\u00E7ons partielles -delete.lectures.title=Effacer un cours bloc -evening=Soir\u00E9e -lectures.repository.print.title=Cours blocs et absences de {1} pour le cours\: {0} -rollcall.status=Status du cours bloc -table.header.preparation=En pr\u00E9paration -confirm.delete.assessment.mode.text=Voulez-vous vraiment effacer l'examen de ce cours bloc "{0}"? -tool.participant=Comme participant -noticed.duration=Dur\u00E9e -reason.copied=La justification a \u00E9t\u00E9 copi\u00E9e avec succ\u00E8s. -table.header.progress=Graphe -open.course=Cours ouvert -error.atleastone.lecture=Choisissez au moins un cours bloc s'il vous pla\u00EEt. -lecture.appeal.absence.enabled=Activer la possibilit\u00E9 de recours -all=Tous +authorized.absence.reason=Justification +autoclosed=Termin\u00E9 automatiquement +bulk=Nom d'utilisateur, $org.olat.user.propertyhandlers\:table.name.email ou $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier +bulk.example=test01<br>author02<br>test@openolat.org +bulk.hint=Vous pouvez entrer une liste de noms d'utilisateurs ou d'adresses courriels dans ce champ de recherche. cancel.lecture.blocks=Annuler le cours bloc -table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> -table.legend.absent=Absent -export.header.entry=Cours\: {0} -table.header.id=ID -search.form.string=Recherche -start.mobile=Mobile -log.add.admission.date=Date d'inscription ajout\u00E9e\: {0} -table.header.rate=Pr\u00E9sence -lecture.time.from=de -managed.flags.lecture.block.compulsory=Obligatoire -reason.deleted=La justification a \u00E9t\u00E9 effac\u00E9e avec succ\u00E8s. -search.participants=Recherche par participants -empty.table.current.lectures.blocks=Vous n'avez aucun cours bloc actuellement. -lecture.show.all.teachers.all=Cours blocs de tous les charg\u00E9s de cours -attendance.list.to.sign.title=Liste de pr\u00E9sence\: {0} -total=Total -table.header.log.effective.lectures=Le\u00E7ons effectives -lecture.auto.close.period=D\u00E9lai pour bloquer le cours bloc -rollcall.tooltip.authorized.absence=Absence excus\u00E9e -today=Aujourd'hui -lecture.reminder.period=D\u00E9lai de rappel -search.form.status=Status -table.header.log.planned.lectures=Le\u00E7ons pr\u00E9vues -unoverride.lecture=Retour en gestion ext\u00E9rieur -appeal.subject=Recours cours bloc "{0}" -table.header.import.status=Status +cancelled=Annul\u00E9 +close.lecture.blocks=Termin\u00E9 le cours bloc +closed=Termin\u00E9 +coach.absence=Absences +coach.appeals=Recours coach.cockpit=Cockpit -noticed.till=jusqu'\u00E0 -lecture.attendance.rate.default=Taux de pr\u00E9sence global en % -reason.copy={0} (copie) -reason=Justification -error.search.form.notempty=Veuillez remplir au minimum un champ du formulaire avec deux caract\u00E8res s'il vous pla\u00EEt. -pdf.table.header.participants=Pr\u00E9nom / nom de famille -table.header.num.participants=Nombre de participants -tools.import.table=Importer des cours blocs depuis Excel -lecture.date=Date -search.entries=Recherche par cours -table.legend.unauthorized=Absence non excus\u00E9e -table.header.appeal.status=Recours -wizard.entries.label.blocks=<strong>{0}</strong> <small>{1}</small> ({2} cours blocs) -noticed.duration.today=Aujourd'hui +coach.lectures=Cours +cockpit.absences=Absences +cockpit.date=pour {0} +cockpit.lectures=Cours +cockpit.lectures.day.list=Vous n'avez pas de cours ce jour-l\u00E0. +cockpit.pending.day={0} {1} ({2} cours) +config.calculate.attendance.rate=Calculer le taux de pr\u00E9sence +config.override=Permettre de modifier la configuration standard +config.override.no=Non +config.override.yes=Oui +config.rollcall.enabled=Activer le contr\u00F4le du taux de pr\u00E9sence +config.sync.course.calendar=Synchroniser le calendrier du cours +config.sync.participant.calendar=Synchroniser le calendrier des participants +config.sync.teacher.calendar=Synchroniser le calendrier des charg\u00E9s de cours +confirm.delete.assessment.mode.text=Voulez-vous vraiment effacer l'examen de ce cours bloc "{0}"? +confirm.delete.assessment.mode.title=Effacer l'examen +confirm.delete.lectures=Voulez-vous vraiment effacer ce cours block "{0}"? +confirm.delete.reason=Voulez-vous vraiment effacer cette justification "{0}"? +copy=Copier current.lecture=Cours bloc actuel +date.end=$org.olat.repository\:cif.date.end +date.start=$org.olat.repository\:cif.date.start +dates=$org.olat.repository\:cif.dates +dates.none=$org.olat.repository\:cif.dates.none +dates.private=$org.olat.repository\:cif.dates.private +dates.public=$org.olat.repository\:cif.dates.public +delete.assessment.mode=Effacer l'\u00E9valuation +delete.lectures.title=Effacer un cours bloc +delete.title=Effacer une justification +detailled.list=Liste d\u00E9taill\u00E9e +details=D\u00E9tails +done=Termin\u00E9 edit.assessment.mode=Editer la configuration d'\u00E9valuation -reason.in.use=Cette justification est encore utilis\u00E9e par un ou plusieurs cours blocs et ne peut pas \u00EAtre effac\u00E9e. +edit.participant.rate=Editer la valeur seuil personalis\u00E9e +edit.reason=Editer la justification +effective.lectures=Le\u00E7ons effectives +empty.lectures.list=La liste est vide +empty.repository.entry.lectures=Vous n'avez pas encore de le\u00E7ons dans ce cours. +empty.table.current.lectures.blocks=Vous n'avez aucun cours bloc actuellement. +empty.table.lectures.blocks=Aucun cours bloc n'a \u00E9t\u00E9 trouv\u00E9. +empty.table.lectures.blocks.admin=Aucun cours bloc n'a \u00E9t\u00E9 cr\u00E9\u00E9 pour ce cours. +empty.table.participant.list=Aucun contr\u00F4le de pr\u00E9sence n'a \u00E9t\u00E9 effectu\u00E9 pour ce cours jusqu'\u00E0 maintenant. +entry.rate=Valeur seuil pour le cours +error.atleastone.lecture=Choisissez au moins un cours bloc s'il vous pla\u00EEt. +error.integer.between=La valeur doit \u00EAtre un nombre entre {0} et {1} +error.integer.positive=La valeur doit \u00EAtre un nombre positif. error.reason.mandatory=La justification est requis. +error.search.form.notempty=Veuillez remplir au minimum un champ du formulaire avec deux caract\u00E8res s'il vous pla\u00EEt. +evening=Soir\u00E9e +export.footer.lectures.hint=x \= Absence +export.header.entry=Cours\: {0} +export.header.lectureblocks=Cours bloc\: {0} de {1} de {2} \u00E0 {3} +export.header.lectures=Cours blocs +export.header.location=Salle\: {0} +export.header.teachers=Charg\u00E9s de cours\: {0} filter.mandatory=Pr\u00E9sence obligatoire -table.header.compulsory.long=Pr\u00E9sence obligatoire -morning=Matin\u00E9e -appeal.sent.tooltip=Recours envoy\u00E9 le {0} -rollcall.tooltip.ok=Pr\u00E9sent +filter.showAll=Tout montrer +filter.warning=Avertissements +first.admission=Premi\u00E8re admission form.managedflags.intro=Ce bloc de le\u00E7ons a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Certains r\u00E9glages et modules ne peuvent pas \u00EAtre modifi\u00E9s et utilis\u00E9s dans OpenOlat. Les \u00E9l\u00E9ments suivants sont bloqu\u00E9s dans OpenOlat\: {0} -repo.settings=Configuration -empty.repository.entry.lectures=Vous n'avez pas encore de le\u00E7ons dans ce cours. -rollcall.absence=Absence -cockpit.absences=Absences -absence.category.copy={0} (copie) -appeal.sent=Envoy\u00E9 le {0} -aggregated.list=Liste consolid\u00E9e -warning.repositoryentry.deleted=$org.olat.repository\:repositoryentry.deleted -appeal.status=Statut +form.managedflags.intro.short=Ce cours bloc a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Ses param\u00E8tres ne peuvent donc pas \u00EAtre chang\u00E9s dans OpenOlat. +from=de {0} +import.lectures=Importer des cours blocs +in.progress=En cours +info.lecture.block.optional=Ce cours bloc n'est <strong>pas</strong> obligatoire. +info.no.lectures=Vous ne suivez pour l'instant aucun cours bloc. +infos.participant.attendance.rate=Valeur seuil personelle\: {0}% +interceptor.start=Vous avez un cours bloc pour le cours "{0}" {1} de {4} \u00E0 {5}. +lecture.absence.default.authorized=Compter les absences par d\u00E9faut comme excus\u00E9es +lecture.admin.course.override.title=Configuration - modifiable au niveau du cours +lecture.admin.enabled=Activer l'administration des cours blocs et des absences +lecture.admin.global.title=Configuration globale +lecture.appeal.absence.enabled=Activer la possibilit\u00E9 de recours +lecture.appeal.absence.period=D\u00E9lai de recours +lecture.assessment.mode.enabled=Activer les \u00E9valuations pour cours blocs +lecture.assessment.mode.followup.time=P\u00E9riode de temporisation +lecture.assessment.mode.ips=Adresses IP autoris\u00E9es +lecture.assessment.mode.leading.time=Pr\u00E9paration +lecture.assessment.mode.seb=Cl\u00E9s Safe Exam Browser +lecture.attendance.rate.default=Taux de pr\u00E9sence global en % +lecture.authorized.absence.enabled=Absences excus\u00E9es +lecture.auto.close.period=D\u00E9lai pour bloquer le cours bloc +lecture.autoclose.notification.body=<p>Ch\u00E8re administratrice de cours<br>Cher administrateur de cours</p><p>Nous vous informons que le cours bloc a \u00E9t\u00E9 ferm\u00E9 automatiquement sans intervention du charg\u00E9 de cours. Avec le lien ci-dessous, vous pouvez acc\u00E9der \u00E0 ce cours bloc\:<br><a href\='{3}'>{3}</a></p> +lecture.autoclose.notification.subject=Cours bloc "{0}" boucl\u00E9 automatiquement +lecture.block=Cours blocs +lecture.block.comment=Remarques +lecture.block.copied=Le cours bloc a \u00E9t\u00E9 copi\u00E9 avec succ\u00E8s. +lecture.block.copy={0} (copie) +lecture.block.dateAndTime={2} de {3} jusqu'\u00E0 {4} heure +lecture.block.effective.end=Fin effective +lecture.block.effective.reason=Justification +lecture.block.status=Status +lecture.calculate.attendance.rate.default.enabled=Calcul du taux de pr\u00E9sence +lecture.can.override.standard.configuration=Permettre de modifier la configuration standard +lecture.compulsory=Pr\u00E9sence obligatoire +lecture.count.authorized.absence.attendant=Compter les absences excus\u00E9es comme pr\u00E9sent +lecture.course.admin.title=Configuration des cours blocs et absences du cours +lecture.date=Date +lecture.deleted=Cours bloc a \u00E9t\u00E9 effac\u00E9 avec succ\u00E8s. +lecture.descr=Description +lecture.end=Fin +lecture.from.to=Depuis +lecture.from.to.format={0} jusqu'\u00E0 {1} +lecture.groups=Cours / groupes / curriculum +lecture.location=Lieu lecture.owner.can.view.all.curriculum.elements=Les propri\u00E9taires peuvent voir tous les cours de l'\u00E9l\u00E9ment de curriculum -table.header.lecture.block=Cours bloc -error.integer.between=La valeur doit \u00EAtre un nombre entre {0} et {1} lecture.preparation=Pr\u00E9paration/suivi -upto=jusqu'\u00E0 {0} +lecture.reminder.enabled=Activ\u00E9 la fonction de rappel +lecture.reminder.period=D\u00E9lai de rappel +lecture.rollcall.default.enabled=Activer le contr\u00F4le de pr\u00E9sence +lecture.show.all.teachers=Affichage par d\u00E9faut dans le cours +lecture.show.all.teachers.all=Cours blocs de tous les charg\u00E9s de cours +lecture.show.all.teachers.mine=Seulement mes cours blocs +lecture.start=D\u00E9but +lecture.status.enabled=Status +lecture.status.partially.done.enabled=Activer la possibilit\u00E9 de le\u00E7ons partielles +lecture.taxonomy=Taxonomie +lecture.teacher=Charg\u00E9s de cours +lecture.teacher.can.authorize.absence=Les charg\u00E9s de cours peuvent excuser les absences +lecture.teacher.reminder.body=<p>Ch\u00E8re charg\u00E9e de cours<br>Cher charg\u00E9 de cours</p><p>Nous aimerions vous rappeler que vous devez encore noter les absences pour un cours bloc. Avec le lien ci-dessous vous m\u00E8nera directement au cours bloc en question\:<br><a href\='{3}'>{3}</a></p><p>Merci beaucoup\!</p><p>Votre administrateur de cours</p> +lecture.teacher.reminder.subject=Rappel cours bloc "{0}" +lecture.time=Temps +lecture.time.from=de +lecture.time.until=jusqu'\u00E0 lecture.title=Titre -appeal=Recours -info.lecture.block.optional=Ce cours bloc n'est <strong>pas</strong> obligatoire. -table.header.presence=Pr\u00E9sence +lectures.admin.reasons=Justifications absences +lectures.admin.report=Rapport cours blocs +lectures.admin.settings=Configuration de l'administration des cours blocs et des absences +lectures.print.title=Cours blocs et absences de {0} +lectures.repository.print.title=Cours blocs et absences de {1} pour le cours\: {0} +lectures.table.closed=Cours blocs termin\u00E9s +lectures.table.current=Cours blocs en cours +lectures.table.next=Prochains cours blocs +lectures.table.pending=Cours blocs en attente +lectures.with.curriculum=Absences du curriculum +lectures.without.curriculum=Absences hors curriculum +log=Log +log.add.admission.date=Date d'inscription ajout\u00E9e\: {0} +log.add.rate=Valeur seuil ajout\u00E9e\: {0} +log.change.admission.date=Date d'inscription modifi\u00E9e\: {0} +log.change.rate=Valeur seuil modifi\u00E9e\: {0} +log.remove.admission.date=Date d'inscription enlev\u00E9e +log.remove.rate=Valeur seuil enlev\u00E9e +managed.flags.lecture.block.all=Gestion externe compl\u00E8te +managed.flags.lecture.block.compulsory=Obligatoire +managed.flags.lecture.block.dates=Date +managed.flags.lecture.block.delete=Effacer le cours bloc +managed.flags.lecture.block.description=Description managed.flags.lecture.block.details=Titre, description... -table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> -closed=Termin\u00E9 -appeal.form.explain=La d\u00E9cision doit \u00EAtre motiv\u00E9e. -appeal.from=Depuis le {0} -repo.participants=Participants +managed.flags.lecture.block.groups=Cours / groupes +managed.flags.lecture.block.location=Lieu +managed.flags.lecture.block.plannedLectures=Cours blocs pr\u00E9vus +managed.flags.lecture.block.preparation=Pr\u00E9paration/suivi +managed.flags.lecture.block.settings=Configuration +managed.flags.lecture.block.teachers=Charg\u00E9s de cours managed.flags.lecture.block.title=Titre -open=Ouvert -table.header.comment=Commentaire -rollcall.comment=Remarque -cockpit.date=pour {0} +menu.my.lectures=Absences +menu.my.lectures.alt=Cours blocs et absences +morning=Matin\u00E9e +multi.rollcall.callee.title.for=pour {0} +new.appeal.title=Nouvelle notification de recours +next.participant=Participant suivant +no.teachers=Pas encore de charg\u00E9 de cours disponible +notice.reason.title=Raison de l'absence +noticed.absence.unauthorized=Absent +noticed.duration=Dur\u00E9e +noticed.duration.today=Aujourd'hui +noticed.entries=Cours +noticed.identity=Personne absente +noticed.lectures=Cours-blocs noticed.reason=Commentaire -table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> -lecture.block=Cours blocs -table.header.start.time=De -lecture.block.copy={0} (copie) -details=D\u00E9tails -add.lecture=Cr\u00E9er un nouveau cours bloc -table.header.notice.type=Type -results=R\u00E9sultats -table.header.identifier=Identifiant -reason.title=Justification -date.start=$org.olat.repository\:cif.date.start -lecture.assessment.mode.leading.time=Pr\u00E9paration -table.header.num.presences=Nombre de participants pr\u00E9sents -reopen=R\u00E9ouvert -managed.flags.lecture.block.location=Lieu -remove.custom.rate=Enlever la valeur seuil personnelle -filter.warning=Avertissements -interceptor.start=Vous avez un cours bloc pour le cours "{0}" {1} de {4} \u00E0 {5}. -export.header.lectureblocks=Cours bloc\: {0} de {1} de {2} \u00E0 {3} -sync.teachers.calendar.enabled=Synchroniser le calendrier des charg\u00E9s de cours -alert.appeal.pending=<strong>Un</strong> recours en attente a \u00E9t\u00E9 trouv\u00E9. -lecture.rollcall.default.enabled=Activer le contr\u00F4le de pr\u00E9sence -lectures.admin.settings=Configuration de l'administration des cours blocs et des absences -table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> -all.desc=Marqu\u00E9 toutes les le\u00E7ons comme absence -wizard.lectureblock.label=<strong>{0}</strong> <small>{1}</small><br>{2} {3} - {4} {5} cours\: "{6}" avec {7} -table.header.description=Description -lecture.block.effective.end=Fin effective +noticed.target.all=Tous les cours +noticed.target.courses=Cours choisis +noticed.target.lectureblocks=Cours-blocs choisis +noticed.teachers=Charg\u00E9s de cours +noticed.till=jusqu'\u00E0 +noticed.type=Type +open=Ouvert +open.course=Cours ouvert +override.lecture=Passer outre la gestion ext\u00E9rieure du cours +partiallydone=En partie termin\u00E9 participant.rate=Valeur seuil -log.add.rate=Valeur seuil ajout\u00E9e\: {0} -export.header.teachers=Charg\u00E9s de cours\: {0} -log.remove.admission.date=Date d'inscription enlev\u00E9e -table.header.log.effective.end.date=Date effective de fin -table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> -admin.menu.title=Cours blocs -confirm.delete.lectures=Voulez-vous vraiment effacer ce cours block "{0}"? -export.footer.lectures.hint=x \= Absence -lecture.deleted=Cours bloc a \u00E9t\u00E9 effac\u00E9 avec succ\u00E8s. -table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> +participant.rate.edit=Valeur seuil personelle +pdf.table.dates={0} de {1} jusqu'\u00E0 {2} +pdf.table.header.all=Tous +pdf.table.header.authorised=Exc. +pdf.table.header.comment=Commentaire +pdf.table.header.lectures=Cours bloc +pdf.table.header.participants=Pr\u00E9nom / nom de famille +pdf.table.header.signature=Signature +planned.lectures=Cours blocs pr\u00E9vus +previous.participant=Participant pr\u00E9c\u00E9dent +private.dates=$org.olat.repository\:cif.private.dates +profile=Profil +public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=Le taux de pr\u00E9sence se situe sous la limite obligatoire. rate.warning.title=Le taux de pr\u00E9sence est proche de la limite obligatoire. -table.header.effective.lectures=Le\u00E7ons -lectures.table.closed=Cours blocs termin\u00E9s +reason=Justification +reason.copied=La justification a \u00E9t\u00E9 copi\u00E9e avec succ\u00E8s. +reason.copy={0} (copie) +reason.deleted=La justification a \u00E9t\u00E9 effac\u00E9e avec succ\u00E8s. +reason.description=Description +reason.id=ID +reason.in.use=Cette justification est encore utilis\u00E9e par un ou plusieurs cours blocs et ne peut pas \u00EAtre effac\u00E9e. +reason.title=Justification +remove.custom.rate=Enlever la valeur seuil personnelle +reopen=R\u00E9ouvert reopen.lecture.blocks=R\u00E9ouvrir un cours bloc -table.header.attended.current.rate=% pr\u00E9sent -noticed.target.lectureblocks=Cours-blocs choisis -table.header.location=Lieu -config.override.yes=Oui -lectures.without.curriculum=Absences hors curriculum -search.form.status.closed=$\:closed -new.appeal.title=Nouvelle notification de recours -appeal.tooltip=Recours possible du {0} au {1} -managed.flags.lecture.block.all=Gestion externe compl\u00E8te -pdf.table.header.authorised=Exc. -dates=$org.olat.repository\:cif.dates -managed.flags.lecture.block.delete=Effacer le cours bloc -error.integer.positive=La valeur doit \u00EAtre un nombre positif. -menu.my.lectures=Absences +repo.lectures=Cours blocs +repo.lectures.appeals=Appels +repo.lectures.block=Cours blocs +repo.participants=Participants +repo.settings=Configuration +results=R\u00E9sultats +rollcall=Contr\u00F4le de pr\u00E9sence +rollcall.absence=Absence +rollcall.coach.hint=Note\: les absences sont enregistr\u00E9es pour chaque le\u00E7on. Si plus de la moiti\u00E9 d'une le\u00E7on est manqu\u00E9e, elle sera consid\u00E9r\u00E9e comme une absence. +rollcall.comment=Remarque +rollcall.status=Status du cours bloc +rollcall.tooltip.absence=Absence +rollcall.tooltip.authorized.absence=Absence excus\u00E9e rollcall.tooltip.free=Facultatif -lecture.end=Fin -managed.flags.lecture.block.dates=Date -log.change.admission.date=Date d'inscription modifi\u00E9e\: {0} -table.header.log.author=Changements +rollcall.tooltip.ok=Pr\u00E9sent +rollcall.tooltip.unauthorized.absence=Absence non excus\u00E9e +save.next=Sauver et continuer +save.temporary=Sauver temporairement +search.curriculums=Recherche par curriculums +search.date=Date +search.entries=Recherche par cours +search.form.category=Raisons +search.form.end=Jusqu'\u00E0 +search.form.login=Nom d'utilisateur +search.form.start=De +search.form.status=Status +search.form.status.autoclosed=$\:autoclosed +search.form.status.closed=$\:closed +search.form.status.open=$\:open +search.form.status.reopen=$\:reopen +search.form.string=Recherche +search.form.string.hint=Vous pouvez chercher les titres d'un bloc de cours ou sa r\u00E9f\u00E9rence externe. Lors de la recherche avec la r\u00E9f\u00E9rence externe, seuls les r\u00E9sultats exacts sont affich\u00E9s. +search.form.till=jusqu'\u00E0 +search.form.type=Type +search.participants=Recherche par participants search.teachers=Recherche par charg\u00E9s de cours -reason.description=Description -lecture.compulsory=Pr\u00E9sence obligatoire -planned.lectures=Cours blocs pr\u00E9vus +send=Envoyer +several.entries=Plusieurs +site.title=Gestion des cours blocs +start.desktop=Bureau start.label=Noter les absences -noticed.entries=Cours +start.mobile=Mobile start.wizard=D\u00E9marrer l'assistant -log=Log -table.header.username=Nom d'utilisateur -search.form.start=De -config.calculate.attendance.rate=Calculer le taux de pr\u00E9sence -tools=Action -lectures.admin.report=Rapport cours blocs -table.header.lecture.11=11 +sync.course.calendar.enabled=Synchroniser le calendrier du cours +sync.participants.calendar.enabled=Synchroniser le calendrier des participants +sync.teachers.calendar.enabled=Synchroniser le calendrier des charg\u00E9s de cours +table.header.absence=Pr\u00E9sences +table.header.absent.lectures=Absences +table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.appeal.status=Recours +table.header.assessment.mode=Evaluations +table.header.attended.current.rate=% pr\u00E9sent +table.header.attended.lectures=Pr\u00E9sent +table.header.authorized.absence=Excus\u00E9 +table.header.auto.close.date=Termin\u00E9 automatiquement le +table.header.comment=Commentaire +table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> +table.header.compulsory.long=Pr\u00E9sence obligatoire +table.header.date=Date +table.header.description=Description +table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> +table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> +table.header.effective.lectures=Le\u00E7ons +table.header.end.time=Jusqu'\u00E0 +table.header.entry=Cours +table.header.export=Exporter +table.header.external.ref=R\u00E9f. ext. +table.header.id=ID +table.header.identifier=Identifiant +table.header.import.status=Status +table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> +table.header.lecture.1=1 table.header.lecture.10=10 -table.header.lecture.13=13 +table.header.lecture.11=11 table.header.lecture.12=12 -private.dates=$org.olat.repository\:cif.private.dates +table.header.lecture.13=13 table.header.lecture.14=14 -copy=Copier -managed.flags.lecture.block.teachers=Charg\u00E9s de cours -noticed.target.courses=Cours choisis -appeal.contact.list=Charg\u00E9 de cours -table.header.teachers=Charg\u00E9s de cours -warning.edit.lecture=Le contr\u00F4le d'absence est d\u00E9sactiv\u00E9. -bulk.hint=Vous pouvez entrer une liste de noms d'utilisateurs ou d'adresses courriels dans ce champ de recherche. +table.header.lecture.2=2 +table.header.lecture.3=3 +table.header.lecture.4=4 +table.header.lecture.5=5 +table.header.lecture.6=6 +table.header.lecture.7=7 +table.header.lecture.8=8 +table.header.lecture.9=9 +table.header.lecture.block=Cours bloc +table.header.location=Lieu table.header.log.action=Action -dates.none=$org.olat.repository\:cif.dates.none -repo.lectures.block=Cours blocs -rollcall.tooltip.unauthorized.absence=Absence non excus\u00E9e -lecture.from.to.format={0} jusqu'\u00E0 {1} -appeals.title=Liste de recours -lecture.block.status=Status -warning.teachers.at.least.one.contact=Il n'y a pas de charg\u00E9s de cours \u00E0 contacter. -lecture.appeal.absence.period=D\u00E9lai de recours -next.participant=Participant suivant -table.header.assessment.mode=Evaluations -lecture.autoclose.notification.body=<p>Ch\u00E8re administratrice de cours<br>Cher administrateur de cours</p><p>Nous vous informons que le cours bloc a \u00E9t\u00E9 ferm\u00E9 automatiquement sans intervention du charg\u00E9 de cours. Avec le lien ci-dessous, vous pouvez acc\u00E9der \u00E0 ce cours bloc\:<br><a href\='{3}'>{3}</a></p> -table.header.entry=Cours -alert.appeals.pending=<strong>{0}</strong> recours en attente ont \u00E9t\u00E9 trouv\u00E9s. -table.header.end.time=Jusqu'\u00E0 -lectures.table.next=Prochains cours blocs -table.header.times=P\u00E9riode -dates.private=$org.olat.repository\:cif.dates.private -from=de {0} -lectures.print.title=Cours blocs et absences de {0} -config.sync.participant.calendar=Synchroniser le calendrier des participants -table.header.auto.close.date=Termin\u00E9 automatiquement le -config.sync.teacher.calendar=Synchroniser le calendrier des charg\u00E9s de cours +table.header.log.author=Changements +table.header.log.effective.end.date=Date effective de fin +table.header.log.effective.lectures=Le\u00E7ons effectives +table.header.log.planned.lectures=Le\u00E7ons pr\u00E9vues +table.header.log.user=Utilisateur +table.header.notice.type=Type +table.header.num.lecture.block=Cours +table.header.num.participants=Nombre de participants +table.header.num.presences=Nombre de participants pr\u00E9sents +table.header.owners=Propri\u00E9taire de cours +table.header.participants=Participants +table.header.planned.lectures=Le\u00E7ons +table.header.preparation=En pr\u00E9paration +table.header.presence=Pr\u00E9sence +table.header.progress=Graphe +table.header.rate=Pr\u00E9sence +table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> table.header.reason=Justification -done=Termin\u00E9 -config.override=Permettre de modifier la configuration standard -lecture.from.to=Depuis -lecture.reminder.enabled=Activ\u00E9 la fonction de rappel -all.teachers.switch=Tous les charg\u00E9s de cours -search.form.end=Jusqu'\u00E0 -log.change.rate=Valeur seuil modifi\u00E9e\: {0} -archive.entry=Archivage -send=Envoyer -lecture.show.all.teachers=Affichage par d\u00E9faut dans le cours +table.header.start.time=De table.header.status=Status -lecture.authorized.absence.enabled=Absences excus\u00E9es -attendance.list.title=Liste d'absence\: {0} -managed.flags.lecture.block.description=Description -cockpit.pending.day={0} {1} ({2} cours) -coach.appeals=Recours -empty.table.lectures.blocks.admin=Aucun cours bloc n'a \u00E9t\u00E9 cr\u00E9\u00E9 pour ce cours. -autoclosed=Termin\u00E9 automatiquement -wizard.entries.label.block=<strong>{0}</strong> <small>{1}</small> ({2} cours bloc) -lecture.assessment.mode.followup.time=P\u00E9riode de temporisation -delete.title=Effacer une justification -effective.lectures=Le\u00E7ons effectives -empty.lectures.list=La liste est vide -lecture.admin.enabled=Activer l'administration des cours blocs et des absences +table.header.teachers=Charg\u00E9s de cours +table.header.times=P\u00E9riode +table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.unauthorized.absence=Non excus\u00E9es +table.header.username=Nom d'utilisateur +table.legend.absent=Absent +table.legend.attended=Pr\u00E9sent +table.legend.authorized=Absence autoris\u00E9e +table.legend.free=Le\u00E7on facultative +table.legend.unauthorized=Absence non excus\u00E9e +today=Aujourd'hui +tool.participant=Comme participant +tool.teacher=Comme charg\u00E9 de cours +tools=Action +tools.import.table=Importer des cours blocs depuis Excel +total=Total +unoverride.lecture=Retour en gestion ext\u00E9rieur +upto=jusqu'\u00E0 {0} +user.overview.appeals=Recours +user.profil=Profil de l'utilisateur +warning.choose.at.least.one.appeal=S'il-vous-pla\u00EEt, s\u00E9lectionnez au moins un recours. +warning.edit.lecture=Le contr\u00F4le d'absence est d\u00E9sactiv\u00E9. +warning.repositoryentry.deleted=$org.olat.repository\:repositoryentry.deleted +warning.teachers.at.least.one.contact=Il n'y a pas de charg\u00E9s de cours \u00E0 contacter. whole.day=Journ\u00E9e enti\u00E8re -search.form.status.autoclosed=$\:autoclosed -all.teachers.switch.tooltip.on=Montrer seulement mes cours blocs -absence.category.description=Description -afternoon=Apr\u00E8s-midi -site.title=Gestion des cours blocs -table.header.export=Exporter -config.rollcall.enabled=Activer le contr\u00F4le du taux de pr\u00E9sence -confirm.delete.reason=Voulez-vous vraiment effacer cette justification "{0}"? -lecture.location=Lieu +wizard.entries.label.block=<strong>{0}</strong> <small>{1}</small> ({2} cours bloc) +wizard.entries.label.blocks=<strong>{0}</strong> <small>{1}</small> ({2} cours blocs) +wizard.lectureblock.label=<strong>{0}</strong> <small>{1}</small><br>{2} {3} - {4} {5} cours\: "{6}" avec {7} diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/AbsencesController.java b/src/main/java/org/olat/modules/lecture/ui/coach/AbsencesController.java index 7a5c17c2259bcc38c96b2de17ba6d7178847f41a..9744dbd22f3750abc5cbefd1717bdb09aa3d754f 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/AbsencesController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/AbsencesController.java @@ -19,7 +19,6 @@ */ package org.olat.modules.lecture.ui.coach; -import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -35,18 +34,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; -import org.olat.core.id.Identity; import org.olat.core.id.Roles; -import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; -import org.olat.core.util.mail.ContactList; -import org.olat.core.util.mail.MailBundle; -import org.olat.core.util.mail.MailContext; -import org.olat.core.util.mail.MailContextImpl; -import org.olat.core.util.mail.MailHelper; -import org.olat.core.util.mail.MailLoggingAction; -import org.olat.core.util.mail.MailManager; -import org.olat.core.util.mail.MailerResult; import org.olat.modules.lecture.AbsenceNoticeSearchParameters; import org.olat.modules.lecture.AbsenceNoticeType; import org.olat.modules.lecture.LectureService; @@ -56,6 +45,8 @@ import org.olat.modules.lecture.ui.LectureRepositoryAdminController; import org.olat.modules.lecture.ui.LecturesSecurityCallback; import org.olat.modules.lecture.ui.event.SearchAbsenceNoticeEvent; import org.olat.modules.lecture.ui.wizard.AbsenceNotice1UserSearchStep; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeCancelStepCallback; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeFinishStepCallback; import org.springframework.beans.factory.annotation.Autowired; /** @@ -76,8 +67,6 @@ public class AbsencesController extends BasicController { private AbsenceNoticeSearchController searchCtrl; private AbsenceNoticesListController noticesListCtlr; - @Autowired - private MailManager mailService; @Autowired private LectureService lectureService; @@ -176,56 +165,14 @@ public class AbsencesController extends BasicController { private void doAddNotice(UserRequest ureq) { final EditAbsenceNoticeWrapper noticeWrapper = new EditAbsenceNoticeWrapper(AbsenceNoticeType.absence); AbsenceNotice1UserSearchStep step = new AbsenceNotice1UserSearchStep(ureq, noticeWrapper, secCallback); - StepRunnerCallback stop = (uureq, swControl, runContext) -> { - if(noticeWrapper.getAbsenceNotice() == null) { - Identity absentIdentity = noticeWrapper.getIdentity(); - lectureService.createAbsenceNotice(absentIdentity, noticeWrapper.getAbsenceNoticeType(), noticeWrapper.getAbsenceNoticeTarget(), - noticeWrapper.getStartDate(), noticeWrapper.getEndDate(), - noticeWrapper.getAbsenceCategory(), noticeWrapper.getAbsenceReason(), noticeWrapper.getAuthorized(), - noticeWrapper.getEntries(), noticeWrapper.getLectureBlocks(), getIdentity()); - } - - if(noticeWrapper.getIdentitiesToContact() != null && !noticeWrapper.getIdentitiesToContact().isEmpty()) { - inform(ureq, noticeWrapper); - } - return StepsMainRunController.DONE_MODIFIED; - }; - + StepRunnerCallback stop = new AbsenceNoticeFinishStepCallback(noticeWrapper, getTranslator()); + StepRunnerCallback cancel = new AbsenceNoticeCancelStepCallback(noticeWrapper); + removeAsListenerAndDispose(addNoticeCtrl); String title = translate("add.absence.title"); - addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, null, title, ""); + addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, cancel, title, ""); listenTo(addNoticeCtrl); getWindowControl().pushAsModalDialog(addNoticeCtrl.getInitialComponent()); } - - private void inform(UserRequest ureq, EditAbsenceNoticeWrapper noticeWrapper) { - boolean success = false; - try { - List<ContactList> contactList = new ArrayList<>(); - ContactList memberList = new ContactList(translate("contact.teachers.list.name")); - memberList.addAllIdentites(noticeWrapper.getIdentitiesToContact()); - MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); - MailBundle bundle = new MailBundle(); - bundle.setContext(context); - bundle.setFromId(getIdentity()); - bundle.setContactLists(contactList); - bundle.setContent(noticeWrapper.getContactSubject(), noticeWrapper.getContactSubject()); - MailerResult result = mailService.sendMessage(bundle); - success = result.isSuccessful(); - if (success) { - showInfo("msg.send.ok"); - // do logging - ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass()); - fireEvent(ureq, Event.DONE_EVENT); - } else { - Roles roles = ureq.getUserSession().getRoles(); - boolean admin = roles.isAdministrator() || roles.isSystemAdmin(); - MailHelper.printErrorsAndWarnings(result, getWindowControl(), admin, getLocale()); - fireEvent(ureq, Event.FAILED_EVENT); - } - } catch (Exception e) { - logError("", e); - showWarning("error.msg.send.nok"); - } - } + } diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/DispensationsController.java b/src/main/java/org/olat/modules/lecture/ui/coach/DispensationsController.java index 216dd591c797032e24374ee976cf35f432961150..bece847b09feb9e03de5f5b8e7a5833401179369 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/DispensationsController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/DispensationsController.java @@ -19,9 +19,7 @@ */ package org.olat.modules.lecture.ui.coach; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import org.olat.commons.calendar.CalendarUtils; import org.olat.core.gui.UserRequest; @@ -35,27 +33,16 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; -import org.olat.core.id.Identity; -import org.olat.core.id.Roles; -import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; -import org.olat.core.util.mail.ContactList; -import org.olat.core.util.mail.MailBundle; -import org.olat.core.util.mail.MailContext; -import org.olat.core.util.mail.MailContextImpl; -import org.olat.core.util.mail.MailHelper; -import org.olat.core.util.mail.MailLoggingAction; -import org.olat.core.util.mail.MailManager; -import org.olat.core.util.mail.MailerResult; import org.olat.modules.lecture.AbsenceNoticeSearchParameters; import org.olat.modules.lecture.AbsenceNoticeType; -import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.model.EditAbsenceNoticeWrapper; import org.olat.modules.lecture.ui.LectureRepositoryAdminController; import org.olat.modules.lecture.ui.LecturesSecurityCallback; import org.olat.modules.lecture.ui.event.SearchAbsenceNoticeEvent; import org.olat.modules.lecture.ui.wizard.AbsenceNotice1UserSearchStep; -import org.springframework.beans.factory.annotation.Autowired; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeCancelStepCallback; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeFinishStepCallback; /** * @@ -76,11 +63,6 @@ public class DispensationsController extends BasicController { private StepsMainRunController addNoticeCtrl; private AbsenceNoticeSearchController searchCtrl; private AbsenceNoticesListController noticesListCtlr; - - @Autowired - private MailManager mailService; - @Autowired - private LectureService lectureService; public DispensationsController(UserRequest ureq, WindowControl wControl, Date currentDate, LecturesSecurityCallback secCallback, boolean withSearch, boolean withAddAbsence) { @@ -174,20 +156,8 @@ public class DispensationsController extends BasicController { final EditAbsenceNoticeWrapper noticeWrapper = new EditAbsenceNoticeWrapper(type); AbsenceNotice1UserSearchStep step = new AbsenceNotice1UserSearchStep(ureq, noticeWrapper, secCallback); - StepRunnerCallback stop = (uureq, swControl, runContext) -> { - if(noticeWrapper.getAbsenceNotice() == null) { - Identity absentIdentity = noticeWrapper.getIdentity(); - lectureService.createAbsenceNotice(absentIdentity, noticeWrapper.getAbsenceNoticeType(), noticeWrapper.getAbsenceNoticeTarget(), - noticeWrapper.getStartDate(), noticeWrapper.getEndDate(), - noticeWrapper.getAbsenceCategory(), noticeWrapper.getAbsenceReason(), noticeWrapper.getAuthorized(), - noticeWrapper.getEntries(), noticeWrapper.getLectureBlocks(), getIdentity()); - } - - if(noticeWrapper.getIdentitiesToContact() != null && !noticeWrapper.getIdentitiesToContact().isEmpty()) { - inform(ureq, noticeWrapper); - } - return StepsMainRunController.DONE_MODIFIED; - }; + StepRunnerCallback stop = new AbsenceNoticeFinishStepCallback(noticeWrapper, getTranslator()); + StepRunnerCallback cancel = new AbsenceNoticeCancelStepCallback(noticeWrapper); String title = translate("add.dispensation.title"); if(type == AbsenceNoticeType.notified) { @@ -195,39 +165,8 @@ public class DispensationsController extends BasicController { } removeAsListenerAndDispose(addNoticeCtrl); - addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, null, title, ""); + addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, cancel, title, ""); listenTo(addNoticeCtrl); getWindowControl().pushAsModalDialog(addNoticeCtrl.getInitialComponent()); } - - private void inform(UserRequest ureq, EditAbsenceNoticeWrapper noticeWrapper) { - boolean success = false; - try { - List<ContactList> contactList = new ArrayList<>(); - ContactList memberList = new ContactList(translate("contact.teachers.list.name")); - memberList.addAllIdentites(noticeWrapper.getIdentitiesToContact()); - MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); - MailBundle bundle = new MailBundle(); - bundle.setContext(context); - bundle.setFromId(getIdentity()); - bundle.setContactLists(contactList); - bundle.setContent(noticeWrapper.getContactSubject(), noticeWrapper.getContactSubject()); - MailerResult result = mailService.sendMessage(bundle); - success = result.isSuccessful(); - if (success) { - showInfo("msg.send.ok"); - // do logging - ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass()); - fireEvent(ureq, Event.DONE_EVENT); - } else { - Roles roles = ureq.getUserSession().getRoles(); - boolean admin = roles.isAdministrator() || roles.isSystemAdmin(); - MailHelper.printErrorsAndWarnings(result, getWindowControl(), admin, getLocale()); - fireEvent(ureq, Event.FAILED_EVENT); - } - } catch (Exception e) { - logError("", e); - showWarning("error.msg.send.nok"); - } - } } diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/EditNoticeController.java b/src/main/java/org/olat/modules/lecture/ui/coach/EditNoticeController.java index ad38d9a9c9d6561393d50c5478cc926af6cff41d..40f394e8cc9310f1b642e5e8f938d3689335e954 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/EditNoticeController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/EditNoticeController.java @@ -19,6 +19,7 @@ */ package org.olat.modules.lecture.ui.coach; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -29,6 +30,8 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.modules.lecture.AbsenceNotice; import org.olat.modules.lecture.AbsenceNoticeTarget; import org.olat.modules.lecture.AbsenceNoticeToLectureBlock; @@ -95,7 +98,7 @@ public class EditNoticeController extends FormBasicController { @Override protected void doDispose() { - // + editReasonCtrl.deleteTempStorage(); } @Override @@ -128,6 +131,11 @@ public class EditNoticeController extends FormBasicController { } absenceNotice = lectureService.updateAbsenceNotice(absenceNotice, authorizer, entries, lectureBlocks); + List<VFSItem> newFiles = new ArrayList<>(); + if(noticeWrapper.getTempUploadFolder() != null) { + newFiles.addAll(noticeWrapper.getTempUploadFolder().getItems(new VFSSystemItemFilter())); + } + lectureService.updateAbsenceNoticeAttachments(absenceNotice, newFiles, noticeWrapper.getAttachmentsToDelete()); fireEvent(ureq, Event.CHANGED_EVENT); } diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/EditReasonController.java b/src/main/java/org/olat/modules/lecture/ui/coach/EditReasonController.java index f7c094b0dcf0c1a1ba4e3ac504d9c5094c89da80..333f069391203c9693acccdf02b0a3e0bc3d1112 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/EditReasonController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/EditReasonController.java @@ -19,23 +19,45 @@ */ package org.olat.modules.lecture.ui.coach; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FileElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.util.KeyValues; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; +import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSManager; +import org.olat.core.util.vfs.VFSMediaResource; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.modules.lecture.AbsenceCategory; import org.olat.modules.lecture.AbsenceNoticeType; import org.olat.modules.lecture.LectureService; @@ -61,11 +83,16 @@ public class EditReasonController extends FormBasicController { private TextElement reasonEl; private SingleSelection typeEl; + private FileElement documentUploadEl; + private FormLayoutContainer filesLayout; private SingleSelection absenceCategoriesEl; private MultipleSelectionElement authorizedEl; - + + private String mapperUri; private final boolean wizard; private final Identity noticedIdentity; + private VFSContainer tempUploadFolder; + private final VFSContainer documentContainer; private final EditAbsenceNoticeWrapper noticeWrapper; private final LecturesSecurityCallback secCallback; private List<AbsenceCategory> absenceCategories; @@ -83,12 +110,16 @@ public class EditReasonController extends FormBasicController { this.secCallback = secCallback; this.noticeWrapper = noticeWrapper; this.noticedIdentity = noticeWrapper.getIdentity(); + documentContainer = lectureService.getAbsenceNoticeAttachmentsContainer(noticeWrapper.getAbsenceNotice()); absenceCategories = lectureService.getAllAbsencesCategories(); initForm(ureq); + updateAttachments(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + mainForm.setMultipartEnabled(true); + if(wizard) { formLayout.setElementCssClass("o_sel_absence_edit_reason"); setFormTitle("notice.reason.title"); @@ -133,6 +164,14 @@ public class EditReasonController extends FormBasicController { String currentReason = noticeWrapper.getAbsenceReason(); reasonEl = uifactory.addTextAreaElement("reason", "noticed.reason", 2048, 4, 36, false, false, currentReason, formLayout); + + String editPage = Util.getPackageVelocityRoot(getClass()) + "/notice_files.html"; + filesLayout = FormLayoutContainer.createCustomFormLayout("filesLayout", getTranslator(), editPage); + filesLayout.setLabel("attachment.upload", null); + formLayout.add(filesLayout); + + documentUploadEl = uifactory.addFileElement(getWindowControl(), "attachment.upload", formLayout); + documentUploadEl.addActionListener(FormEvent.ONCHANGE); } @Override @@ -140,6 +179,12 @@ public class EditReasonController extends FormBasicController { // } + protected void deleteTempStorage() { + if(tempUploadFolder != null) { + tempUploadFolder.delete(); + } + } + public AbsenceCategory getAbsenceCategory() { if(!absenceCategoriesEl.isVisible() || !absenceCategoriesEl.isOneSelected()) return null; @@ -155,6 +200,59 @@ public class EditReasonController extends FormBasicController { return null; } + private void updateAttachments(UserRequest ureq) { + if(mapperUri == null) { + mapperUri = registerCacheableMapper(ureq, "assigment-" + CodeHelper.getRAMUniqueID(), new DocumentMapper()); + filesLayout.contextPut("mapperUri", mapperUri); + } + + List<VFSItem> files = new ArrayList<>(); + if(documentContainer != null) { + List<VFSItem> currentItems = documentContainer.getItems(new VFSSystemItemFilter()); + List<VFSItem> deletedItems = noticeWrapper.getAttachmentsToDelete(); + for(VFSItem currentItem:currentItems) { + boolean deleted = false; + for(VFSItem deletedItem:deletedItems) { + if(deletedItem.isSame(currentItem)) { + deleted = true; + } + } + if(!deleted) { + files.add(currentItem); + } + } + + } + // add files from TempFolder + if(tempUploadFolder != null) { + files.addAll(tempUploadFolder.getItems(new VFSSystemItemFilter())); + } + + Collections.sort(files, new Comparator<VFSItem>(){ + final Collator c = Collator.getInstance(getLocale()); + @Override + public int compare(final VFSItem o1, final VFSItem o2) { + return c.compare((o1).getName(), (o2).getName()); + } + }); + + filesLayout.contextPut("files", files); + + // add delete links for each attachment if user is allowed to see them + int count = 0; + for (VFSItem file : files) { + FormLink deleteLink = uifactory.addFormLink("delete_" + (++count), filesLayout, Link.BUTTON_XSMALL); + deleteLink.setUserObject(file); + deleteLink.setI18nKey("delete"); + } + + boolean hasFile = !files.isEmpty(); + filesLayout.setVisible(hasFile); + filesLayout.showLabel(hasFile); + documentUploadEl.showLabel(!hasFile); + documentUploadEl.getComponent().setDirty(true); + } + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = super.validateFormLogic(ureq); @@ -183,6 +281,22 @@ public class EditReasonController extends FormBasicController { authorizedEl.select(authorizedKeys[0], true); } authorizedEl.setEnabled(!forceAuthorized); + } else if (source == documentUploadEl) { + if (documentUploadEl.isUploadSuccess()) { + doUploadDocument(ureq); + } + } else if (source instanceof FormLink) { + FormLink activeLink = (FormLink) source; + Object uobject = activeLink.getUserObject(); + if (uobject instanceof VFSLeaf) { + VFSLeaf file = (VFSLeaf)uobject; + if(tempUploadFolder != null && tempUploadFolder.resolve(file.getName()) != null) { + file.delete(); + } else { + noticeWrapper.getAttachmentsToDelete().add(file); + } + } + updateAttachments(ureq); } super.formInnerEvent(ureq, source, event); } @@ -202,4 +316,56 @@ public class EditReasonController extends FormBasicController { noticeWrapper.setAbsenceNoticeType(noticeWrapper.getAbsenceNoticeType()); } } + + private void doUploadDocument(UserRequest ureq) { + String fileName = documentUploadEl.getUploadFileName(); + // checking tmp-folder and msg-container for filename + boolean fileExists = false; + if ((tempUploadFolder != null && tempUploadFolder.resolve(fileName) != null) + || (documentContainer != null && documentContainer.resolve(fileName) != null)) { + fileExists = true; + } + + if (fileExists) { + try { + Files.delete(documentUploadEl.getUploadFile().toPath()); + documentUploadEl.setErrorKey("attachments.error.file.exists", null); + documentUploadEl.showError(true); + } catch (IOException e) { + logError("Cannot delete uploaded file", e); + } + } else { + // files got stored in an extra tempFolder, to use the same + // fileUploader multiple times + if(tempUploadFolder == null) { + tempUploadFolder = VFSManager.olatRootContainer(File.separator + "tmp/" + CodeHelper.getGlobalForeverUniqueID() + "/", null); + noticeWrapper.setTempUploadFolder(tempUploadFolder); + } + documentUploadEl.moveUploadFileTo(tempUploadFolder); + documentUploadEl.showError(false); + documentUploadEl.reset(); + updateAttachments(ureq); + showInfo("attachments.upload.successful", fileName); + } + } + + public class DocumentMapper implements Mapper { + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + if(relPath.startsWith("/")) { + relPath = relPath.substring(1, relPath.length()); + } + + @SuppressWarnings("unchecked") + List<VFSItem> files = (List<VFSItem>)filesLayout.contextGet("files"); + if(files != null) { + for(VFSItem file:files) { + if(relPath.equalsIgnoreCase(file.getName()) && file instanceof VFSLeaf) { + return new VFSMediaResource((VFSLeaf)file); + } + } + } + return null; + } + } } diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/IdentitiesLecturesRollCallController.java b/src/main/java/org/olat/modules/lecture/ui/coach/IdentitiesLecturesRollCallController.java index 52bed771106ae6c76d1f887361a86f2764bc8443..1a1a66d0a411daa681fc0a2f99efeba2b747336f 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/IdentitiesLecturesRollCallController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/IdentitiesLecturesRollCallController.java @@ -75,6 +75,8 @@ import org.olat.modules.lecture.ui.coach.IdentitiesLecturesRollCallTableModel.Id import org.olat.modules.lecture.ui.component.LectureBlockRollCallStatusItem; import org.olat.modules.lecture.ui.profile.IdentityProfileController; import org.olat.modules.lecture.ui.wizard.AbsenceNotice3LecturesEntriesStep; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeCancelStepCallback; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeFinishStepCallback; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; import org.springframework.beans.factory.annotation.Autowired; @@ -444,16 +446,8 @@ public class IdentitiesLecturesRollCallController extends FormBasicController { noticeWrapper.setCurrentDate(currentDate); AbsenceNotice3LecturesEntriesStep step = new AbsenceNotice3LecturesEntriesStep(ureq, noticeWrapper, secCallback, true); - StepRunnerCallback stop = (uureq, swControl, runContext) -> { - if(noticeWrapper.getAbsenceNotice() == null) { - Identity absentIdentity = noticeWrapper.getIdentity(); - lectureService.createAbsenceNotice(absentIdentity, noticeWrapper.getAbsenceNoticeType(), - noticeWrapper.getAbsenceNoticeTarget(), noticeWrapper.getStartDate(), noticeWrapper.getEndDate(), - noticeWrapper.getAbsenceCategory(), noticeWrapper.getAbsenceReason(), noticeWrapper.getAuthorized(), - noticeWrapper.getEntries(), noticeWrapper.getLectureBlocks(), getIdentity()); - } - return StepsMainRunController.DONE_MODIFIED; - }; + StepRunnerCallback stop = new AbsenceNoticeFinishStepCallback(noticeWrapper, getTranslator()); + StepRunnerCallback cancel = new AbsenceNoticeCancelStepCallback(noticeWrapper); String title = translate("add.dispensation.title"); if(type == AbsenceNoticeType.notified) { @@ -463,7 +457,7 @@ public class IdentitiesLecturesRollCallController extends FormBasicController { } removeAsListenerAndDispose(addNoticeCtrl); - addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, null, title, ""); + addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, cancel, title, ""); listenTo(addNoticeCtrl); getWindowControl().pushAsModalDialog(addNoticeCtrl.getInitialComponent()); } diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/LecturesCoachingController.java b/src/main/java/org/olat/modules/lecture/ui/coach/LecturesCoachingController.java index ba544d2ccec741dd8785ded1e438fd921620ac70..b1c3c330a60f5b4abc2cce9e5ae230605f642231 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/LecturesCoachingController.java +++ b/src/main/java/org/olat/modules/lecture/ui/coach/LecturesCoachingController.java @@ -135,6 +135,7 @@ public class LecturesCoachingController extends BasicController implements Activ doOpenLectures(ureq); segmentView.select(lecturesLink); } else if("Absences".equalsIgnoreCase(type)) { + doAbsences(ureq); segmentView.select(absenceLink); } else if("Dispenses".equalsIgnoreCase(type)) { doDispenses(ureq); diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/_content/edit_notice.html b/src/main/java/org/olat/modules/lecture/ui/coach/_content/edit_notice.html index e24ff1f21319ad7cce16897d2d09d5ef6e8f472b..b3814056fc578bf3aa15dcd49a3ea0f4d91d8f8f 100644 --- a/src/main/java/org/olat/modules/lecture/ui/coach/_content/edit_notice.html +++ b/src/main/java/org/olat/modules/lecture/ui/coach/_content/edit_notice.html @@ -1,6 +1,9 @@ $r.render("reason") $r.render("datesAndLectures") -<div class="o_button_group"> - $r.render("cancel") - $r.render("save") -</div> \ No newline at end of file +<div class="o_form form-horizontal"><div class="form-group clearfix"> + <div class="col-sm-9 col-sm-offset-3 "> + $r.render("cancel") + $r.render("save") + </div> +</div></div> + diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/_content/notice_files.html b/src/main/java/org/olat/modules/lecture/ui/coach/_content/notice_files.html new file mode 100644 index 0000000000000000000000000000000000000000..bfa8c511d7e3d580128b9c01b3544447030362b6 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/coach/_content/notice_files.html @@ -0,0 +1,13 @@ +#if($files && $files.size() > 0) +<table class="table table-condensed table-striped"><tbody> + #foreach ($file in $files) + #set( $fname = $file.getName() ) + <tr> + <td style="width:1%"><i class="o_icon o_icon-fw $r.getFiletypeIconCss($fname)"> </i></td> + <td><a href="$mapperUri/$fname" target="_blank">$r.escapeHtml($fname)</a></td> + <td>$r.formatBytes($file.getSize())</td> + <td style="width:1%">$r.render("delete_$foreach.count")</td> + </tr> + #end +</tbody></table> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/profile/IdentityProfileController.java b/src/main/java/org/olat/modules/lecture/ui/profile/IdentityProfileController.java index fded61848a9be53a36c5d845c42437738823b689..70c231a1519d23000a76c8fe0247896eabac3397 100644 --- a/src/main/java/org/olat/modules/lecture/ui/profile/IdentityProfileController.java +++ b/src/main/java/org/olat/modules/lecture/ui/profile/IdentityProfileController.java @@ -19,7 +19,6 @@ */ package org.olat.modules.lecture.ui.profile; -import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -39,21 +38,10 @@ import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.id.Identity; -import org.olat.core.id.Roles; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; -import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; -import org.olat.core.util.mail.ContactList; -import org.olat.core.util.mail.MailBundle; -import org.olat.core.util.mail.MailContext; -import org.olat.core.util.mail.MailContextImpl; -import org.olat.core.util.mail.MailHelper; -import org.olat.core.util.mail.MailLoggingAction; -import org.olat.core.util.mail.MailManager; -import org.olat.core.util.mail.MailerResult; import org.olat.modules.lecture.AbsenceNoticeType; -import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.model.EditAbsenceNoticeWrapper; import org.olat.modules.lecture.ui.AppealListRepositoryController; import org.olat.modules.lecture.ui.LectureRepositoryAdminController; @@ -61,8 +49,9 @@ import org.olat.modules.lecture.ui.LecturesSecurityCallback; import org.olat.modules.lecture.ui.ParticipantLecturesOverviewController; import org.olat.modules.lecture.ui.coach.DispensationsController; import org.olat.modules.lecture.ui.wizard.AbsenceNotice3LecturesEntriesStep; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeCancelStepCallback; +import org.olat.modules.lecture.ui.wizard.AbsenceNoticeFinishStepCallback; import org.olat.user.DisplayPortraitController; -import org.springframework.beans.factory.annotation.Autowired; /** * @@ -89,11 +78,6 @@ public class IdentityProfileController extends BasicController implements Activa private DailyOverviewProfilController dailyOverviewCtrl; private ParticipantLecturesOverviewController lecturesCtrl; - @Autowired - private MailManager mailService; - @Autowired - private LectureService lectureService; - public IdentityProfileController(UserRequest ureq, WindowControl wControl, Identity profiledIdentity, LecturesSecurityCallback secCallback, boolean withBack) { super(ureq, wControl, Util.createPackageTranslator(LectureRepositoryAdminController.class, ureq.getLocale())); @@ -222,21 +206,9 @@ public class IdentityProfileController extends BasicController implements Activa noticeWrapper.setCurrentDate(new Date()); AbsenceNotice3LecturesEntriesStep step = new AbsenceNotice3LecturesEntriesStep(ureq, noticeWrapper, secCallback, true); - StepRunnerCallback stop = (uureq, swControl, runContext) -> { - if(noticeWrapper.getAbsenceNotice() == null) { - Identity absentIdentity = noticeWrapper.getIdentity(); - lectureService.createAbsenceNotice(absentIdentity, noticeWrapper.getAbsenceNoticeType(), noticeWrapper.getAbsenceNoticeTarget(), - noticeWrapper.getStartDate(), noticeWrapper.getEndDate(), - noticeWrapper.getAbsenceCategory(), noticeWrapper.getAbsenceReason(), noticeWrapper.getAuthorized(), - noticeWrapper.getEntries(), noticeWrapper.getLectureBlocks(), getIdentity()); - } - - if(noticeWrapper.getIdentitiesToContact() != null && !noticeWrapper.getIdentitiesToContact().isEmpty()) { - inform(ureq, noticeWrapper); - } - return StepsMainRunController.DONE_MODIFIED; - }; - + StepRunnerCallback stop = new AbsenceNoticeFinishStepCallback(noticeWrapper, getTranslator()); + StepRunnerCallback cancel = new AbsenceNoticeCancelStepCallback(noticeWrapper); + String title = translate("add.dispensation.title"); if(type == AbsenceNoticeType.notified) { title = translate("add.notice.absence.title"); @@ -245,40 +217,8 @@ public class IdentityProfileController extends BasicController implements Activa } removeAsListenerAndDispose(addNoticeCtrl); - addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, null, title, ""); + addNoticeCtrl = new StepsMainRunController(ureq, getWindowControl(), step, stop, cancel, title, ""); listenTo(addNoticeCtrl); getWindowControl().pushAsModalDialog(addNoticeCtrl.getInitialComponent()); } - - - private void inform(UserRequest ureq, EditAbsenceNoticeWrapper noticeWrapper) { - boolean success = false; - try { - List<ContactList> contactList = new ArrayList<>(); - ContactList memberList = new ContactList(translate("contact.teachers.list.name")); - memberList.addAllIdentites(noticeWrapper.getIdentitiesToContact()); - MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); - MailBundle bundle = new MailBundle(); - bundle.setContext(context); - bundle.setFromId(getIdentity()); - bundle.setContactLists(contactList); - bundle.setContent(noticeWrapper.getContactSubject(), noticeWrapper.getContactSubject()); - MailerResult result = mailService.sendMessage(bundle); - success = result.isSuccessful(); - if (success) { - showInfo("msg.send.ok"); - // do logging - ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass()); - fireEvent(ureq, Event.DONE_EVENT); - } else { - Roles roles = ureq.getUserSession().getRoles(); - boolean admin = roles.isAdministrator() || roles.isSystemAdmin(); - MailHelper.printErrorsAndWarnings(result, getWindowControl(), admin, getLocale()); - fireEvent(ureq, Event.FAILED_EVENT); - } - } catch (Exception e) { - logError("", e); - showWarning("error.msg.send.nok"); - } - } } diff --git a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice1UserSearchStep.java b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice1UserSearchStep.java index fcdcc184452519b6cc0d9777e058b6a9859b363b..7d91fb0e89b566d27a4e3cc166092fa07fa4b30d 100644 --- a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice1UserSearchStep.java +++ b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice1UserSearchStep.java @@ -54,6 +54,7 @@ public class AbsenceNotice1UserSearchStep extends BasicStep { @Override public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) { runContext.put("absence", noticeWrapper); + form.setMultipartEnabled(true); return new UserSearchController(ureq, wControl, form, runContext); } } diff --git a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice3LecturesEntriesStep.java b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice3LecturesEntriesStep.java index a643267199eb4a3c7d36143ee02bdc373177f919..592c8879b21c3c11d488508bc0e9bd7ad55d3934 100644 --- a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice3LecturesEntriesStep.java +++ b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice3LecturesEntriesStep.java @@ -69,6 +69,7 @@ public class AbsenceNotice3LecturesEntriesStep extends BasicStep { if(noticeWrapper != null) { runContext.put("absence", noticeWrapper); } + form.setMultipartEnabled(true); return new DatesLecturesEntriesStepController(ureq, wControl, form, runContext, secCallback); } } diff --git a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice4ReasonStep.java b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice4ReasonStep.java index 12bd855f418e98a2551888742806aabb33b424ca..842b5d04df640bf6e8387e645b2026a1c6a105b2 100644 --- a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice4ReasonStep.java +++ b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNotice4ReasonStep.java @@ -52,6 +52,7 @@ public class AbsenceNotice4ReasonStep extends BasicStep { @Override public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) { + form.setMultipartEnabled(true); return new ReasonStepController(ureq, wControl, form, runContext, secCallback); } } diff --git a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeCancelStepCallback.java b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeCancelStepCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..119de09380362dfc24f53c9ef903665252c7d31b --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeCancelStepCallback.java @@ -0,0 +1,51 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.wizard; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.Step; +import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; +import org.olat.core.gui.control.generic.wizard.StepsMainRunController; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.modules.lecture.model.EditAbsenceNoticeWrapper; + +/** + * + * Initial date: 20 août 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AbsenceNoticeCancelStepCallback implements StepRunnerCallback { + + private final EditAbsenceNoticeWrapper noticeWrapper; + + public AbsenceNoticeCancelStepCallback(EditAbsenceNoticeWrapper noticeWrapper) { + this.noticeWrapper = noticeWrapper; + } + + @Override + public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) { + if(noticeWrapper.getTempUploadFolder() != null) { + noticeWrapper.getTempUploadFolder().deleteSilently(); + } + return StepsMainRunController.DONE_UNCHANGED; + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeFinishStepCallback.java b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeFinishStepCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..9fc274c0dfa94d8229bf9334980fa32f0d6b8ebe --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/wizard/AbsenceNoticeFinishStepCallback.java @@ -0,0 +1,132 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.wizard; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.logging.log4j.Logger; +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.Step; +import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; +import org.olat.core.gui.control.generic.wizard.StepsMainRunController; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.logging.Tracing; +import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; +import org.olat.core.util.mail.ContactList; +import org.olat.core.util.mail.MailBundle; +import org.olat.core.util.mail.MailContext; +import org.olat.core.util.mail.MailContextImpl; +import org.olat.core.util.mail.MailHelper; +import org.olat.core.util.mail.MailLoggingAction; +import org.olat.core.util.mail.MailManager; +import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; +import org.olat.modules.lecture.AbsenceNotice; +import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.model.EditAbsenceNoticeWrapper; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 20 août 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AbsenceNoticeFinishStepCallback implements StepRunnerCallback { + + private static final Logger log = Tracing.createLoggerFor(AbsenceNoticeFinishStepCallback.class); + + private final Translator translator; + private final EditAbsenceNoticeWrapper noticeWrapper; + + @Autowired + private MailManager mailService; + @Autowired + private LectureService lectureService; + + public AbsenceNoticeFinishStepCallback(EditAbsenceNoticeWrapper noticeWrapper, Translator translator) { + CoreSpringFactory.autowireObject(this); + this.translator = translator; + this.noticeWrapper = noticeWrapper; + } + + @Override + public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) { + if(noticeWrapper.getAbsenceNotice() == null) { + Identity absentIdentity = noticeWrapper.getIdentity(); + AbsenceNotice notice = lectureService.createAbsenceNotice(absentIdentity, noticeWrapper.getAbsenceNoticeType(), + noticeWrapper.getAbsenceNoticeTarget(), noticeWrapper.getStartDate(), noticeWrapper.getEndDate(), + noticeWrapper.getAbsenceCategory(), noticeWrapper.getAbsenceReason(), noticeWrapper.getAuthorized(), + noticeWrapper.getEntries(), noticeWrapper.getLectureBlocks(), ureq.getIdentity()); + + List<VFSItem> newFiles = new ArrayList<>(); + if(noticeWrapper.getTempUploadFolder() != null) { + newFiles.addAll(noticeWrapper.getTempUploadFolder().getItems(new VFSSystemItemFilter())); + } + lectureService.updateAbsenceNoticeAttachments(notice, newFiles, noticeWrapper.getAttachmentsToDelete()); + + } + + if(noticeWrapper.getTempUploadFolder() != null) { + noticeWrapper.getTempUploadFolder().deleteSilently(); + } + + if(noticeWrapper.getIdentitiesToContact() != null && !noticeWrapper.getIdentitiesToContact().isEmpty()) { + inform(ureq, wControl); + } + return StepsMainRunController.DONE_MODIFIED; + } + + private void inform(UserRequest ureq, WindowControl wControl) { + boolean success = false; + try { + List<ContactList> contactList = new ArrayList<>(); + ContactList memberList = new ContactList(translator.translate("contact.teachers.list.name")); + memberList.addAllIdentites(noticeWrapper.getIdentitiesToContact()); + MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString()); + MailBundle bundle = new MailBundle(); + bundle.setContext(context); + bundle.setFromId(ureq.getIdentity()); + bundle.setContactLists(contactList); + bundle.setContent(noticeWrapper.getContactSubject(), noticeWrapper.getContactSubject()); + MailerResult result = mailService.sendMessage(bundle); + success = result.isSuccessful(); + if (success) { + wControl.setInfo(translator.translate("msg.send.ok")); + // do logging + ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass()); + } else { + Roles roles = ureq.getUserSession().getRoles(); + boolean admin = roles.isAdministrator() || roles.isSystemAdmin(); + MailHelper.printErrorsAndWarnings(result, wControl, admin, ureq.getLocale()); + } + } catch (Exception e) { + log.error("", e); + wControl.setWarning(translator.translate("error.msg.send.nok")); + } + } +}