From ee2e504ffad276fbb0adc189175d29adb3e31e03 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Fri, 28 Feb 2020 20:53:24 +0100 Subject: [PATCH] feat(allocations): explanations & introduce grade-ordinal-proportion BREAKING CHANGE: influence of grades on allocation priority now relative when priorities are ordinal --- config/settings.yml | 7 +++--- frontend/src/app.sass | 4 ++++ messages/uniworx/de-de-formal.msg | 3 ++- src/Foundation.hs | 2 +- src/Handler/Allocation/Prios.hs | 14 +++++++---- src/Handler/Allocation/Users.hs | 13 ++++++++--- src/Handler/Utils/Allocation.hs | 8 ++++++- src/Settings.hs | 6 ++--- src/Utils/Icon.hs | 2 ++ src/Utils/Message.hs | 5 +++- .../allocation-priorities/de-de-formal.hamlet | 23 +++++++++++++++++++ .../numeric/de-de-formal.hamlet | 11 ++++++--- .../ordinal/de-de-formal.hamlet | 7 ++++-- 13 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 templates/i18n/allocation-priorities/de-de-formal.hamlet diff --git a/config/settings.yml b/config/settings.yml index e348b6e91..196f8e97e 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -143,9 +143,10 @@ user-defaults: # This encodes the weight of the lecturer ratings on the same scale as the # centrally supplied priorities. allocation-grade-scale: 25 -# This encodes how many ordinal places lecturer ratings may move students up or -# down when central priorities are supplied as ordered list. -allocation-grade-ordinal-places: 3 +# This encodes, as a proportion of the number of places, how many +# ordinal places lecturer ratings may move students up or down when +# central priorities are supplied as ordered list. +allocation-grade-ordinal-proportion: 0.075 instance-id: "_env:INSTANCE_ID:instance" ribbon: "_env:RIBBON:" diff --git a/frontend/src/app.sass b/frontend/src/app.sass index 6b65ab057..fee98fe59 100644 --- a/frontend/src/app.sass +++ b/frontend/src/app.sass @@ -472,6 +472,10 @@ ul.list--inline .deflist__dt font-weight: 600 + .deflist__explanation + color: var(--color-fontsec) + font-size: 0.9rem + .deflist__dd font-size: 18px margin-bottom: 10px diff --git a/messages/uniworx/de-de-formal.msg b/messages/uniworx/de-de-formal.msg index a71029fa9..39b865efb 100644 --- a/messages/uniworx/de-de-formal.msg +++ b/messages/uniworx/de-de-formal.msg @@ -2369,4 +2369,5 @@ AllocationPrioritiesOrdinal: Dringlichkeiten durch Sortierung AllocationPrioritiesTitle tid@TermId ssh@SchoolId ash@AllocationShorthand: #{tid}-#{ssh}-#{ash}: Zentrale Dringlichkeiten AllocationPrioritiesFile: CSV-Datei AllocationPrioritiesSunk num@Int64: Zentrale Prioritäten für #{num} Bewerber erfolgreich hinterlegt -AllocationPrioritiesMissing num@Int64: Für #{num} Bewerber ist keine zentrale Priorität hinterlegt, da in der hochgeladenen CSV-Datei die #{pluralDE num "entsprechende Matrikelnummer" "entsprechenden Matrikelnummern"} nicht gefunden #{pluralDE num "wurde" "wurden"} \ No newline at end of file +AllocationPrioritiesMissing num@Int64: Für #{num} Bewerber ist keine zentrale Priorität hinterlegt, da in der hochgeladenen CSV-Datei die #{pluralDE num "entsprechende Matrikelnummer" "entsprechenden Matrikelnummern"} nicht gefunden #{pluralDE num "wurde" "wurden"} +AllocationMissingPrioritiesIgnored: Bewerber, für die keine zentrale Priorität angegeben wird, werden bei der Vergabe ignoriert! \ No newline at end of file diff --git a/src/Foundation.hs b/src/Foundation.hs index 79fae88f8..6596c912c 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -3028,7 +3028,7 @@ pageActions (AllocationR tid ssh ash AUsersR) = return { navLabel = MsgMenuAllocationPriorities , navRoute = AllocationR tid ssh ash APriosR , navAccess' = return True - , navType = NavTypeLink { navModal = True } + , navType = NavTypeLink { navModal = False } , navQuick' = mempty , navForceActive = False } diff --git a/src/Handler/Allocation/Prios.hs b/src/Handler/Allocation/Prios.hs index 60ad57cae..9edc03250 100644 --- a/src/Handler/Allocation/Prios.hs +++ b/src/Handler/Allocation/Prios.hs @@ -49,8 +49,10 @@ postAPriosR tid ssh ash = do AllocationPrioritiesNumeric -> return $(i18nWidgetFile "allocation-priority-explanation/numeric") AllocationPrioritiesOrdinal -> return $(i18nWidgetFile "allocation-priority-explanation/ordinal") + ignoreWarningMsg <- messageIconI Warning IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored ((priosRes, priosView), priosEnctype) <- runFormPost . renderAForm FormStandard $ (,) <$> apopt (explainedSelectionField Nothing (explainOptionList optionsFinite explainAllocationPrioMode)) (fslI MsgAllocationPrioritiesMode) (Just $ bool AllocationPrioritiesOrdinal AllocationPrioritiesNumeric doNumericPrios) + <* aformMessage ignoreWarningMsg <*> areq fileField (fslI MsgAllocationPrioritiesFile) Nothing formResult priosRes $ \(mode, fInfo) -> do @@ -76,7 +78,11 @@ postAPriosR tid ssh ash = do siteLayoutMsg MsgMenuAllocationPriorities $ do setTitleI $ MsgAllocationPrioritiesTitle tid ssh ash - wrapForm priosView def - { formEncoding = priosEnctype - , formAction = Just . SomeRoute $ AllocationR tid ssh ash APriosR - } + let priosForm = wrapForm priosView def + { formEncoding = priosEnctype + , formAction = Just . SomeRoute $ AllocationR tid ssh ash APriosR + } + gradeScale <- getsYesod $ view _appAllocationGradeScale + gradeOrdinalProportion <- getsYesod $ view _appAllocationGradeOrdinalProportion + + $(i18nWidgetFile "allocation-priorities") diff --git a/src/Handler/Allocation/Users.hs b/src/Handler/Allocation/Users.hs index 4e3183426..c714f6a33 100644 --- a/src/Handler/Allocation/Users.hs +++ b/src/Handler/Allocation/Users.hs @@ -10,7 +10,7 @@ import Handler.Utils import Handler.Utils.Allocation import qualified Database.Esqueleto as E -import qualified Database.Esqueleto.Utils.TH as E +import qualified Database.Esqueleto.Utils as E import qualified Data.Csv as Csv @@ -103,11 +103,15 @@ instance CsvColumnsExplained AllocationUserTableCsv where getAUsersR, postAUsersR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html getAUsersR = postAUsersR postAUsersR tid ssh ash = do - usersTable <- runDB $ do + (usersTable, missingPriorities) <- runDB $ do Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash now <- liftIO getCurrentTime resultsDone <- (<= NTop (Just now)) . NTop <$> allocationDone aId + missingPriorities <- E.selectExists . E.from $ \allocationUser -> + E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId + E.&&. E.isNothing (allocationUser E.^. AllocationUserPriority) + csvName <- getMessageRender <*> pure (MsgAllocationUsersCsvName tid ssh ash) let @@ -220,9 +224,12 @@ postAUsersR tid ssh ash = do & defaultSorting [SortAscBy "priority", SortAscBy "user-matriculation"] & defaultPagesize PagesizeAll - dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable + usersTable <- dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable + return (usersTable, missingPriorities) siteLayoutMsg MsgMenuAllocationUsers $ do setTitleI $ MsgAllocationUsersTitle tid ssh ash + when missingPriorities $ + notification NotificationBroad =<< messageIconI Warning IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored usersTable diff --git a/src/Handler/Utils/Allocation.hs b/src/Handler/Utils/Allocation.hs index 48e70448b..d756228f0 100644 --- a/src/Handler/Utils/Allocation.hs +++ b/src/Handler/Utils/Allocation.hs @@ -119,7 +119,13 @@ computeAllocation allocId cRestr = do return ((courseApplicationUser, courseApplicationCourse), (courseApplicationAllocationPriority, courseApplicationRatingPoints)) gradeScale <- getsYesod $ view _appAllocationGradeScale - gradeOrdinalPlaces <- getsYesod $ view _appAllocationGradeOrdinalPlaces + gradeOrdinalProportion <- getsYesod $ view _appAllocationGradeOrdinalProportion + let ordinalUsers = getSum . flip foldMap users'' $ \(_, prio) -> case prio of + AllocationPriorityOrdinal{} -> Sum 1 + _other -> mempty + gradeOrdinalPlaces :: Natural + gradeOrdinalPlaces = round . abs $ ordinalUsers * gradeOrdinalProportion + let centralNudge user cloneIndex grade = case allocationPrio user of AllocationPriorityNumeric{..} -> let allocationPriorities' = under vector (sortOn Down) allocationPriorities diff --git a/src/Settings.hs b/src/Settings.hs index a611d19b9..63238163b 100644 --- a/src/Settings.hs +++ b/src/Settings.hs @@ -125,8 +125,8 @@ data AppSettings = AppSettings , appTransactionLogIPRetentionTime :: NominalDiffTime - , appAllocationGradeScale :: Rational - , appAllocationGradeOrdinalPlaces :: Natural + , appAllocationGradeScale + , appAllocationGradeOrdinalProportion :: Rational , appReloadTemplates :: Bool -- ^ Use the reload version of templates @@ -423,7 +423,7 @@ instance FromJSON AppSettings where appTransactionLogIPRetentionTime <- o .: "ip-retention-time" appAllocationGradeScale <- o .: "allocation-grade-scale" <|> fmap toRational (o .: "allocation-grade-scale" :: Aeson.Parser Scientific) - appAllocationGradeOrdinalPlaces <- o .: "allocation-grade-ordinal-places" + appAllocationGradeOrdinalProportion <- o .: "allocation-grade-ordinal-proportion" <|> fmap toRational (o .: "allocation-grade-ordinal-proportion" :: Aeson.Parser Scientific) appUserDefaults <- o .: "user-defaults" appAuthPWHash <- o .: "auth-pw-hash" diff --git a/src/Utils/Icon.hs b/src/Utils/Icon.hs index 37b29ec16..1853c9a88 100644 --- a/src/Utils/Icon.hs +++ b/src/Utils/Icon.hs @@ -82,6 +82,7 @@ data Icon | IconMenuAdmin | IconPageActionPrimaryExpand | IconPageActionSecondary | IconBreadcrumbSeparator + | IconMissingAllocationPriority deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable) iconText :: Icon -> Text @@ -142,6 +143,7 @@ iconText = \case IconPageActionPrimaryExpand -> "bars" IconPageActionSecondary -> "ellipsis-h" IconBreadcrumbSeparator -> "angle-right" + IconMissingAllocationPriority -> "empty-set" instance Universe Icon instance Finite Icon diff --git a/src/Utils/Message.hs b/src/Utils/Message.hs index 71b4d95a3..345db9881 100644 --- a/src/Utils/Message.hs +++ b/src/Utils/Message.hs @@ -6,7 +6,7 @@ module Utils.Message , addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget , statusToUrgencyClass , Message(..) - , messageIconI, messageIconIHamlet, messageIconWidget + , messageIconI, messageIconIHamlet, messageIconFile, messageIconWidget , messageI, messageIHamlet, messageFile, messageWidget, messageTooltip ) where @@ -178,6 +178,9 @@ addMessageFile mc tPath = [e|addMessageIHamlet mc $(ihamletFile tPath)|] messageFile :: MessageStatus -> FilePath -> ExpQ messageFile mc tPath = [e|messageIHamlet mc $(ihamletFile tPath)|] +messageIconFile :: MessageStatus -> Icon -> FilePath -> ExpQ +messageIconFile mc mi tPath = [e|messageIHamlet mc mi $(ihamletFile tPath)|] + addMessageWidget :: forall m site. ( MonadHandler m , HandlerSite m ~ site diff --git a/templates/i18n/allocation-priorities/de-de-formal.hamlet b/templates/i18n/allocation-priorities/de-de-formal.hamlet new file mode 100644 index 000000000..8a4e19422 --- /dev/null +++ b/templates/i18n/allocation-priorities/de-de-formal.hamlet @@ -0,0 +1,23 @@ +$newline never +
+ ^{priosForm} +
+
+
+ Einfluss von Bewertungen bei numerischen Dringlichkeiten +

+ Dozenten können, durch Hinterlegen von Bewertungen, die Vergabe # + in einem Maße beeinflussen, das einer Abweichung der # + zentralen Dringlichkeit um plus bzw. minus diesen Wert, # + entspricht. +

+ #{rationalToFixed2 gradeScale} +
+ Einfluss von Bewertungen bei Dringlichkeiten durch Sortierung +

+ Dozenten können, durch Hinterlegen von Bewertungen, die # + Vergabe in einem Maße beeinflussen, das einer Verschiebung des # + Bewerbers (auf- bzw. abwärts) um diese Proportion, in der nach # + Dringlichkeit sortierten Bewerberliste, entspricht. +

+ #{textPercent gradeOrdinalProportion 1} diff --git a/templates/i18n/allocation-priority-explanation/numeric/de-de-formal.hamlet b/templates/i18n/allocation-priority-explanation/numeric/de-de-formal.hamlet index b526d2b6e..f54026a5f 100644 --- a/templates/i18n/allocation-priority-explanation/numeric/de-de-formal.hamlet +++ b/templates/i18n/allocation-priority-explanation/numeric/de-de-formal.hamlet @@ -9,10 +9,15 @@ Alle weiteren Spalten werden als ganze Zahlen interpretiert und # kodieren die jeweilige zentrale Dringlichkeit bei der Vergabe der # Plätze. # -Hierbei wird die erste Dringlichkeits-Spalte verwendet zur Vergabe des # -jeweils ersten Platzes, die zweite Spalte für den zweiten Platz, usw. # +Größere Zahlen kodieren eine höhere Dringlichkeit. # -Größere Zahlen kodieren eine höhere Dringlichkeit. +Hierbei wird die höchste der jeweiligen Dringlichkeiten verwendet zur # +Vergabe des jeweils ersten Platzes, die nächst niedrigere für den # +zweiten Platz, usw.. # + +Werden für einen Bewerber mehr Plätze in Betracht gezogen, als # +Dringlichkeiten für ihn angegeben wurden, so wird hierfür die # +niedrigste Dringlichkeit verwendet.
diff --git a/templates/i18n/allocation-priority-explanation/ordinal/de-de-formal.hamlet b/templates/i18n/allocation-priority-explanation/ordinal/de-de-formal.hamlet index b11e5bfc4..652ac5018 100644 --- a/templates/i18n/allocation-priority-explanation/ordinal/de-de-formal.hamlet +++ b/templates/i18n/allocation-priority-explanation/ordinal/de-de-formal.hamlet @@ -9,8 +9,11 @@ Die zentrale Dringlichkeit ergibt sich ausschließlich anhand der # Sortierung der CSV-Datei. # Bewerber, deren Matrikelnummer später in der Datei vorkommt, erhalten # -für alle ihre Plätze eine höhere Dringlichkeit, als Bewerber, deren # -Matrikelnummern in der Datei früher vorkommen. # +eine höhere Dringlichkeit, als Bewerber, deren Matrikelnummern in der # +Datei früher vorkommen. # + +Für ihren zweiten Platz haben alle Bewerber eine niedrigere # +Dringlichkeit als andere Bewerber für ihren ersten Platz, usw..