Merge branch 'master' of gitlab.cip.ifi.lmu.de:jost/UniWorX

This commit is contained in:
Gregor Kleen 2019-08-22 17:08:50 +02:00
commit f067f65ee5
12 changed files with 190 additions and 46 deletions

View File

@ -30,6 +30,7 @@ Aborted: Abgebrochen
Remarks: Hinweise
Registered: Angemeldet
RegisteredSince: Angemeldet seit
Registration: Anmeldung
RegisterFrom: Anmeldungen von
RegisterTo: Anmeldungen bis
DeRegUntil: Abmeldungen bis
@ -1023,6 +1024,7 @@ MenuExamEdit: Bearbeiten
MenuExamUsers: Teilnehmer
MenuExamAddMembers: Prüfungsteilnehmer hinzufügen
MenuLecturerInvite: Dozenten hinzufügen
MenuAllocationInfo: Hinweise zum Ablauf einer Zentralanmeldung
AuthPredsInfo: Um eigene Veranstaltungen aus Sicht der Teilnehmer anzusehen, können Veranstalter und Korrektoren hier die Prüfung ihrer erweiterten Berechtigungen temporär deaktivieren. Abgewählte Prädikate schlagen immer fehl. Abgewählte Prädikate werden also nicht geprüft um Zugriffe zu gewähren, welche andernfalls nicht erlaubt wären. Diese Einstellungen gelten nur temporär bis Ihre Sitzung abgelaufen ist, d.h. bis ihr Browser-Cookie abgelaufen ist. Durch Abwahl von Prädikaten kann man sich höchstens temporär aussperren.
AuthPredsActive: Aktive Authorisierungsprädikate
@ -1481,8 +1483,11 @@ AllocationStaffRegisterFrom: Eintragung der Kurse ab
AllocationStaffRegister: Eintragung der Kurse
AllocationRegisterFrom: Bewerbung ab
AllocationRegister: Bewerbung
AllocationRegisterClosed: Die Zentralanmeldung ist aktuell geschlossen.
AllocationRegisterOpensIn opens@Text: Die Zentralanmeldung öffnet voraussichtlich in #{opens}
AllocationStaffAllocationFrom: Bewertung der Bewerbungen ab
AllocationStaffAllocation: Bewertung der Bewerbungen
AllocationStaffAllocation: Bewerbungsbewertung
AllocationProcess: Platzvergabe
AllocationNoApplication: Keine Bewerbung
AllocationPriority: Priorität
AllocationPriorityTip: Kurse, denen Sie eine höhere Priorität zuteilen, werden bei der Platzvergabe präferiert.
@ -1496,7 +1501,7 @@ BtnAllocationRegister: Teilnahme registrieren
BtnAllocationRegistrationEdit: Teilnahme anpassen
AllocationParticipation: Teilnahme an der Zentralanmeldung
AllocationParticipationLoginFirst: Um an der Zentralanmeldung teilzunehmen, loggen Sie sich bitte zunächst ein.
AllocationCourses: Kurse
AllocationCourses: Kurse dieser Zentralanmeldung
AllocationData: Organisatorisches
AllocationCoursePriority i@Natural: #{i}. Wahl
AllocationCourseNoApplication: Keine Bewerbung

1
routes
View File

@ -61,6 +61,7 @@
/info InfoR GET !free
/info/lecturer InfoLecturerR GET !lecturer
/info/data DataProtR GET !free
/info/allocation InfoAllocationR GET !free
/impressum ImpressumR GET !free
/version VersionR GET !free

View File

@ -1728,6 +1728,7 @@ instance YesodBreadcrumbs UniWorX where
breadcrumb InfoR = return ("Information" , Nothing)
breadcrumb InfoLecturerR = return ("Veranstalter" , Just InfoR)
breadcrumb DataProtR = return ("Datenschutz" , Just InfoR)
breadcrumb InfoAllocationR = return ("Zentralanmeldungen", Just InfoR)
breadcrumb ImpressumR = return ("Impressum" , Just InfoR)
breadcrumb VersionR = return ("Versionsgeschichte", Just InfoR)
@ -2156,7 +2157,7 @@ pageActions (TermCourseListR tid) =
]
pageActions (TermSchoolCourseListR _tid _ssh) =
[ MenuItem
{ menuItemType = PageActionPrime
{ menuItemType = PageActionPrime
, menuItemLabel = MsgMenuCourseNew
, menuItemIcon = Just "book"
, menuItemRoute = SomeRoute CourseNewR
@ -2164,6 +2165,16 @@ pageActions (TermSchoolCourseListR _tid _ssh) =
, menuItemAccessCallback' = return True
}
]
pageActions (AllocationR _tid _ssh _ash AShowR) =
[ MenuItem
{ menuItemType = PageActionPrime
, menuItemLabel = MsgMenuAllocationInfo
, menuItemIcon = Nothing
, menuItemRoute = SomeRoute InfoAllocationR
, menuItemModal = True
, menuItemAccessCallback' = return True
}
]
pageActions (CourseListR) =
[ MenuItem
{ menuItemType = PageActionPrime

View File

@ -2,6 +2,7 @@ module Handler.Allocation
( module Handler.Allocation
) where
import Handler.Allocation.Info as Handler.Allocation
import Handler.Allocation.Show as Handler.Allocation
import Handler.Allocation.Application as Handler.Allocation
import Handler.Allocation.Register as Handler.Allocation

View File

@ -0,0 +1,13 @@
module Handler.Allocation.Info
( getInfoAllocationR
) where
import Import
import Handler.Utils
getInfoAllocationR :: Handler Html
getInfoAllocationR = do
siteLayoutMsg MsgMenuAllocationInfo $ do
setTitleI MsgMenuAllocationInfo
$(i18nWidgetFile "allocation-info")

View File

@ -9,18 +9,19 @@ import Handler.Allocation.Register
import Handler.Allocation.Application
import qualified Database.Esqueleto as E
getAShowR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
getAShowR tid ssh ash = do
muid <- maybeAuthId
now <- liftIO getCurrentTime
let
resultCourse :: Simple Field1 a (Entity Course) => Lens' a (Entity Course)
resultCourse = _1
resultCourseApplication :: Simple Field2 a (Maybe (Entity CourseApplication)) => Traversal' a (Entity CourseApplication)
resultCourseApplication = _2 . _Just
resultHasTemplate :: Simple Field3 a (E.Value Bool) => Lens' a Bool
resultHasTemplate :: Simple Field3 a (E.Value Bool) => Lens' a Bool
resultHasTemplate = _3 . _Value
(Entity aId Allocation{..}, courses, registration) <- runDB $ do
@ -91,5 +92,6 @@ getAShowR tid ssh ash = do
<div .allocation-course ##{toPathPiece cID}>
^{wdgt}
|]
let daysToRegistrationStart = assertM (>0) $ (`diffUTCTime` now) <$> allocationRegisterFrom
allocationInfoModal = modal [whamlet|_{MsgMenuAllocationInfo}|] $ Left $ SomeRoute InfoAllocationR
$(widgetFile "allocation/show")

View File

@ -25,39 +25,39 @@ import qualified Database.Esqueleto.Utils as E
-- NOTE: Outdated way to use dbTable; see ProfileDataR Handler for a more recent method.
type CourseTableData = DBRow (Entity Course, Int, Bool, Entity School, [Entity User])
type CourseTableData = DBRow (Entity Course, Int, Bool, Entity School, [Entity User], Maybe (Entity Allocation))
colCourse :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colCourse = sortable (Just "course") (i18nCell MsgCourse)
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _) } ->
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _, _) } ->
anchorCell (CourseR courseTerm courseSchool courseShorthand CShowR)
[whamlet|_{courseName}|]
colDescription :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colDescription = sortable Nothing mempty
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _) } ->
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _, _) } ->
case courseDescription of
Nothing -> mempty
(Just descr) -> cell $ modal (toWidget $ hasComment True) (Right $ toWidget descr)
colCShort :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colCShort = sortable (Just "cshort") (i18nCell MsgCourseShort)
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _) } ->
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _, _) } ->
anchorCell (CourseR courseTerm courseSchool courseShorthand CShowR) [whamlet|_{courseShorthand}|]
colTerm :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colTerm = sortable (Just "term") (i18nCell MsgTerm)
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _) } ->
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, _, _, _) } ->
anchorCell (TermCourseListR courseTerm) [whamlet|#{courseTerm}|]
colSchoolShort :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colSchoolShort = sortable (Just "schoolshort") (i18nCell MsgCourseSchoolShort)
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, Entity _ School{..}, _) } ->
$ \DBRow{ dbrOutput=(Entity _ Course{..}, _, _, Entity _ School{..}, _, _) } ->
anchorCell (TermSchoolCourseListR courseTerm courseSchool) [whamlet|_{schoolShorthand}|]
colRegistered :: IsDBTable m a => Colonnade Sortable CourseTableData (DBCell m a)
colRegistered = sortable (Just "registered") (i18nCell MsgRegistered)
$ \DBRow{ dbrOutput=(_, _, registered, _, _) } -> tickmarkCell registered
$ \DBRow{ dbrOutput=(_, _, registered, _, _, _) } -> tickmarkCell registered
type CourseTableExpr = E.SqlExpr (Entity Course) `E.InnerJoin` E.SqlExpr (Entity School)
@ -90,7 +90,9 @@ makeCourseTable whereClause colChoices psValidator = do
dbtProj :: DBRow _ -> MaybeT (ReaderT SqlBackend (HandlerT UniWorX IO)) CourseTableData
dbtProj = traverse $ \(course, E.Value participants, E.Value registered, school) -> do
lecturerList <- lift $ E.select $ E.from $ lecturerQuery $ E.val $ entityKey course
return (course, participants, registered, school, lecturerList)
courseAlloc <- lift $ getBy (UniqueAllocationCourse $ entityKey course)
>>= traverse (getJustEntity . allocationCourseAllocation . entityVal)
return (course, participants, registered, school, lecturerList, courseAlloc)
snd <$> dbTable psValidator DBTable
{ dbtSQLQuery
, dbtRowKey = \(course `E.InnerJoin` _) -> course E.^. CourseId
@ -179,8 +181,8 @@ makeCourseTable whereClause colChoices psValidator = do
]
, dbtStyle = def
{ dbsFilterLayout = defaultDBSFilterLayout
, dbsTemplate = DBSTCourse (_dbrOutput . _1) (_dbrOutput . _5) (_dbrOutput . _3) (_dbrOutput . _4)
-- ^ course ^ lecturer list ^ isRegistered ^ school
, dbsTemplate = DBSTCourse (_dbrOutput . _1) (_dbrOutput . _5) (_dbrOutput . _3) (_dbrOutput . _4) (_dbrOutput . _6 . _Just)
-- ^ course ^ lecturer list ^ isRegistered ^ school ^ allocation
}
, dbtParams = def
, dbtIdent = "courses" :: Text

View File

@ -105,7 +105,7 @@ import Data.Semigroup as Sem (Semigroup(..))
import qualified Data.Conduit.List as C
import Handler.Utils.DateTime (formatTimeW)
import Handler.Utils.DateTime (formatTimeRangeW)
import qualified Control.Monad.Catch as Catch
@ -465,7 +465,7 @@ data DBStyle r = DBStyle
}
data DBSTemplateMode r = DBSTDefault
| DBSTCourse (Lens' r (Entity Course)) (Lens' r [Entity User]) (Lens' r Bool) (Lens' r (Entity School))
| DBSTCourse (Lens' r (Entity Course)) (Lens' r [Entity User]) (Lens' r Bool) (Lens' r (Entity School)) (Traversal' r (Entity Allocation))
instance Default (DBStyle r) where
def = DBStyle
@ -1057,12 +1057,12 @@ dbTable PSValidator{..} dbtable@DBTable{ dbtIdent = dbtIdent'@(toPathPiece -> db
attrs = sortableContent ^. cellAttrs
piSorting' = [ sSet | sSet <- fromMaybe [] piSorting, Just (sortKey sSet) /= sortableKey ]
case dbsTemplate of
DBSTCourse _ _ _ _ -> return $(widgetFile "table/course/header")
DBSTDefault -> return $(widgetFile "table/cell/header")
DBSTCourse{} -> return $(widgetFile "table/course/header")
DBSTDefault -> return $(widgetFile "table/cell/header")
in do
wHeaders <- maybe (return Nothing) (fmap Just . genHeaders) pSortable
case dbsTemplate of
DBSTCourse c l r s -> do
DBSTCourse c l r s a -> do
wRows <- forM rows $ \row' -> let
Course{..} = row' ^. c . _entityVal
lecturerUsers = row' ^. l
@ -1070,6 +1070,7 @@ dbTable PSValidator{..} dbtable@DBTable{ dbtIdent = dbtIdent'@(toPathPiece -> db
isRegistered = row' ^. r
courseSchoolName = schoolName $ row' ^. s . _entityVal
courseSemester = (termToText . unTermKey) courseTerm
courseAllocation = row' ^? a
in return $(widgetFile "table/course/course-teaser")
return $(widgetFile "table/course/colonnade")
DBSTDefault -> do

View File

@ -34,26 +34,42 @@ $newline never
<dd .deflist__dd>
^{formatTimeRangeW SelFormatDateTime fromT allocationStaffAllocationTo}
$if is _Just muid
$if mayRegister || is _Just registration
<section id=allocation-participation>
<h2>
_{MsgAllocationParticipation}
$if mayRegister
^{registerForm'}
$else
$maybe Entity _ AllocationUser{allocationUserTotalCourses} <- registration
<dl .deflist>
<dt .deflist__dt>
_{MsgAllocationTotalCourses}
<dd .deflist__dd>
#{allocationUserTotalCourses}
$else
<section id=allocation-participation>
<h2>
_{MsgAllocationParticipation}
$# TODO show datetime of automatic allocation
$#
$# <dt .deflist__dt>
$# _{MsgAllocationProcess}
$# <dd .deflist__dd>
$# ^{formatTimeRangeW SelFormatDateTime fromT allocationProcess}
$#
<section id=allocation-participation>
<h2>
_{MsgAllocationParticipation}
$if is _Nothing muid
<p>
_{MsgAllocationParticipationLoginFirst}
_{MsgAllocationParticipationLoginFirst}
$elseif mayRegister
$# existing registrations may also be edited in this case
^{registerForm'}
$elseif is _Just registration
$# show existing registration even if it cannot be changed now
$maybe Entity _ AllocationUser{allocationUserTotalCourses} <- registration
<dl .deflist>
<dt .deflist__dt>
_{MsgAllocationTotalCourses}
<dd .deflist__dd>
#{allocationUserTotalCourses}
$else
$# Provide helpful information for confused students who cannot register now
$maybe daysToOpen <- daysToRegistrationStart
<p>
_{MsgAllocationRegisterOpensIn (formatDiffDays daysToOpen)}
$nothing
<p>
_{MsgAllocationRegisterClosed}
<p>
$# This redundant links prevents useless help requests from frantic users
^{allocationInfoModal}
$if not (null courseWidgets)
<section .allocation>

View File

@ -184,10 +184,10 @@ h4 {
&:last-child {
margin: 0.5rem 0 0;
}
&:first-of-type {
margin: 0;
&:first-of-type {
margin: 0;
}
}
}
}

View File

@ -0,0 +1,85 @@
$newline text
<section>
<p>
Jede Zentralanmeldung durchläuft
der Reihe nach folgende Phasen:
<dl .deflist>
<dt .deflist__dt>
_{MsgAllocationStaffRegister}
<dd .deflist__dd>
<p>
Veranstalter können nur in diesem Zeitraum ihre Veranstaltungen
zur Zentralanmeldung hinzufügen oder entfernen.
<p>
Pro Veranstaltung wird einzeln festgelegt,
ob Studierende einen Bewerbungstext und/oder Bewerbungsdateien
einreichen sollen.
Veranstalter stellen auch Anweisungen zur Bewerbung ein,
z.B. welchen Inhalt abzugebende Bewerbungsdateien enthalten sollen.
<p>
Zur Zentralanmeldung eingetragene Kurse
erlauben während dem gesamten Ablauf
der Zentralanmeldung keine anderweitigen Kursanmeldung mehr,
auch nicht durch den Veranstalter selbst.
<dt .deflist__dt>
_{MsgAllocationRegister}
<dd .deflist__dd>
<p>
Studierende können sich nur in diesem Zeitraum
auf Plätze in Kursen einer Zentralanmeldung bewerben.
<p>
Bewerber können jedem Kurs der Zentralanmeldung eine Priorität
zuweisen, zwischen "dieser Kurs wäre meine erste Wahl"
und "diesen Kurs besuche ich auf keinen Fall".
Es kann auch mehreren Kursen die gleiche Priorität eingeräumt werden.
<p>
Studierende können auch mehr als einen Platz
in verschiedenen Kursen einer Zentralanmeldung anfordern,
falls die Kurskapazitäten und/oder Dringlichkeit ausreichend sind.
<p>
Bewerbungstexte und/oder Bewerbungsdateien
sind pro Kurs anzugeben, falls vom Veranstalter gefordert.
<dt .deflist__dt>
_{MsgAllocationStaffAllocation}
<dd .deflist__dd>
<p>
Veranstalter können nur in diesem Zeitraum die
Bewerbungen einsehen und bewerten.
$# <p>
$# Nur in manchen Zentralanmeldungen dürfen Veranstalter
$# Bewerber jetzt direkt ablehnen und/oder übernehmen.
$# <p>
$# Veranstalter haben noch eine letzte Möglichkeit,
$# die Kurskapazität anzupassen.
<dt .deflist__dt>
_{MsgAllocationProcess}
<dd .deflist__dd>
<p>
Die Plätze werden gemäß Studienfortschritt, Dringlichkeit
und der Bewertung durch den Veranstalter auf die Bewerber verteilt.
<p>
Die Bewerber werden diekt in den jeweiligen Kursen angemeldet.
Eine Abmeldung durch Studierende ist nicht erlaubt.
Übernommene Bewerber, welche einen zugeteilten Platz
ohne Angabe eines triftigen Grundes nicht antreten,
werden in zukünftigen Zentralanmeldungen
unter Umständen benachteiligt.
<p>
Veranstalter können frühestens nach der erfolgten Zuteilung
Teilnehmer selbst an-/abmelden
und ggf. Nachrücker für freigewordene Plätze anfordern.
<p>
Der Ablauf einer Zentralanmeldung kann unter Umständen noch variieren.
<em>
Insbesondere: #
Fehlt in der Übersichtsseite einer Zentralanmeldung
die Angabe einer dieser Phasen, dann wurde der entsprechende Zeitraum
leider noch nicht festgelegt!
<p>
Mehrere Zentralanmeldungen werden völlig unabhängig voneinander
abgewickelt.

View File

@ -17,9 +17,16 @@
$forall lecturer <- courseLecturers
<li>
#{lecturer}
$maybe regTo <- courseRegisterTo
<div .course-teaser__duedate-label>_{MsgRegisterTo}
<div .course-teaser__duedate-value>^{formatTimeW SelFormatDateTime regTo}
$maybe Entity _ Allocation{allocationTerm, allocationSchool, allocationShorthand, allocationName} <- courseAllocation
<div .course-teaser__duedate-label>_{MsgRegistration}
<div .course-teaser__duedate-value>
<a href=@{AllocationR allocationTerm allocationSchool allocationShorthand AShowR}>
#{allocationName}
$nothing
$maybe regFrom <- courseRegisterFrom
<div .course-teaser__duedate-label>_{MsgRegistration}
<div .course-teaser__duedate-value>^{formatTimeRangeW SelFormatDateTime regFrom courseRegisterTo}
$maybe desc <- courseDescription
<div .course-teaser__chevron>
<div .course-teaser__description>#{desc}