chore(lms): make model compile again, sort out model errors
This commit is contained in:
parent
aa73359893
commit
3d3ac9d77c
@ -3,65 +3,70 @@ Qualification
|
|||||||
shorthand (CI Text)
|
shorthand (CI Text)
|
||||||
name (CI Text)
|
name (CI Text)
|
||||||
description StoredMarkup Maybe -- user-defined large Html, ought to contain full description
|
description StoredMarkup Maybe -- user-defined large Html, ought to contain full description
|
||||||
validDuration Word Maybe -- qualification is valid for this number of months
|
validDuration Word Maybe -- qualification is valid for this number of months
|
||||||
auditDuration Word Maybe -- number of month to keep audit log
|
auditDuration Word Maybe -- number of month to keep audit log
|
||||||
refreshWithin CalendarDiffDays Maybe -- refresher is scheduled within this number of month before expiry
|
refreshWithin CalendarDiffDays Maybe -- refresher is scheduled within this number of month before expiry
|
||||||
-- refreshInvitation StoredMarkup -- fest verdrahtet I18N-MSGs, nur Anzeige auf Webseite
|
elearningOnly Bool -- successful E-learing automatically increases validity
|
||||||
-- expiryNotification StoredMarkup Maybe
|
-- refreshInvitation StoredMarkup -- hard-coded I18N-MSGs used instead, but displayed on qualification page
|
||||||
elearningOnly Bool -- successful E-learing automatically increases validity
|
-- expiryNotification StoredMarkup Maybe -- configurable user-profile-notifcations are used instead
|
||||||
UniqueSchoolShort school shorthand -- must be unique per school and shorthand
|
UniqueSchoolShort school shorthand -- must be unique per school and shorthand
|
||||||
UniqueSchoolName school name -- must be unique per school and name
|
UniqueSchoolName school name -- must be unique per school and name
|
||||||
deriving Generic
|
deriving Generic
|
||||||
|
|
||||||
-- Verknüpfung mit Exams fehlt only
|
|
||||||
|
|
||||||
QualificationUser
|
|
||||||
user User
|
|
||||||
qualification QualficationId
|
|
||||||
validUntil UTCTime
|
|
||||||
firstHeld UTCTime -- timestamp qualification earned
|
|
||||||
lastRefresh UTCTIme -- lastRefresh > validUntil possible, indicates E-Learning success, but needs more (e.g. an exam)
|
|
||||||
UniqueQualificationUser qualification user
|
|
||||||
|
|
||||||
QualificationEdit
|
QualificationEdit
|
||||||
user User
|
user User
|
||||||
time UTCTime
|
time UTCTime
|
||||||
qualification QualificationId OnDeleteCascade OnUpdateCascade
|
qualification QualificationId OnDeleteCascade OnUpdateCascade
|
||||||
deriving Generic
|
deriving Generic
|
||||||
|
|
||||||
|
-- TODO: connect Qualification with Exams!
|
||||||
|
|
||||||
|
QualificationUser
|
||||||
|
user User
|
||||||
|
qualification QualificationId
|
||||||
|
validUntil UTCTime
|
||||||
|
lastRefresh UTCTime -- lastRefresh > validUntil possible, if Qualification^elearningOnly == False
|
||||||
|
firstHeld UTCTime -- first time the qualification was earned, should never change
|
||||||
|
UniqueQualificationUser qualification user
|
||||||
|
deriving Generic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- LMS Interface Tables, need regular processing by background jobs
|
-- LMS Interface Tables, need regular processing by background jobs
|
||||||
-- Logging?
|
|
||||||
LmsUser
|
LmsUser
|
||||||
qualification QualificationId
|
qualification QualificationId
|
||||||
user UserId
|
user UserId
|
||||||
ident LmsIdent
|
ident LmsIdent
|
||||||
pin Text
|
pin Text
|
||||||
resetPin Bool
|
resetPin Bool -- should the pin be reset?
|
||||||
deleted Bool
|
delete Bool -- should the ident be deleted? TODO: do we need this?
|
||||||
started UTCTime Maybe
|
started UTCTime Maybe
|
||||||
ended UTCTime Maybe
|
submitted UTCTime Maybe -- ident was sent to LMS (should happen only once)
|
||||||
|
ended UTCTime Maybe -- ident was deleted in LMS
|
||||||
UniqueLmsUser qualification ident
|
UniqueLmsUser qualification ident
|
||||||
deriving Generic
|
deriving Generic
|
||||||
|
|
||||||
LmsAudit
|
-- LmsUserlist stores LMS upload ofr later processing only
|
||||||
qualifaction QualifactionId
|
|
||||||
ident LmsIdent
|
|
||||||
lastSeen UTCTime
|
|
||||||
notificationType LmsNotification
|
|
||||||
|
|
||||||
LmsUserlist
|
LmsUserlist
|
||||||
qualification QualificationId
|
qualification QualificationId
|
||||||
ident LmsIdent
|
ident LmsIdent
|
||||||
failed Bool
|
failed Bool
|
||||||
timestamp UTCTime default=now()
|
timestamp UTCTime default=now()
|
||||||
UniqueLmsUserlist qualification ident
|
|
||||||
deriving Generic
|
deriving Generic
|
||||||
|
|
||||||
-- QualificationId is redundant here; but known due to external upload
|
-- LmsUserlist stores LMS upload ofr later processing only
|
||||||
LmsResult
|
LmsResult
|
||||||
qualification QualificationId
|
qualification QualificationId
|
||||||
ident LmsIdent
|
ident LmsIdent
|
||||||
success Day
|
success Day
|
||||||
timestamp UTCTime default=now()
|
timestamp UTCTime default=now()
|
||||||
UniqueLmsResult qualification ident
|
deriving Generic
|
||||||
|
|
||||||
|
-- Logs all processed rows from LmsUserlist and LmsResult
|
||||||
|
LmsAudit
|
||||||
|
qualification QualificationId
|
||||||
|
ident LmsIdent
|
||||||
|
notificationType LmsNotification
|
||||||
|
received UTCTime
|
||||||
|
processed UTCTime default=now()
|
||||||
deriving Generic
|
deriving Generic
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
|
|
||||||
module Data.Time.Clock.Instances
|
module Data.Time.Clock.Instances
|
||||||
@ -32,7 +33,7 @@ instance PersistField NominalDiffTime where
|
|||||||
instance PersistFieldSql NominalDiffTime where
|
instance PersistFieldSql NominalDiffTime where
|
||||||
sqlType _ = sqlType (Proxy @Rational)
|
sqlType _ = sqlType (Proxy @Rational)
|
||||||
|
|
||||||
|
deriving instance Generic Day
|
||||||
deriving instance Generic UTCTime
|
deriving instance Generic UTCTime
|
||||||
instance Hashable UTCTime
|
instance Hashable UTCTime
|
||||||
|
|
||||||
@ -40,14 +41,26 @@ instance PathPiece UTCTime where
|
|||||||
toPathPiece = pack . iso8601Show
|
toPathPiece = pack . iso8601Show
|
||||||
fromPathPiece = iso8601ParseM . unpack
|
fromPathPiece = iso8601ParseM . unpack
|
||||||
|
|
||||||
instance Csv.ToField UTCTime where
|
-- UTCTime, Day, etc.
|
||||||
|
instance {-# OVERLAPPABLE #-} ISO8601 t => Csv.ToField t where -- Error: overlaps Csv.ToField String, but no instance ISO8601 String exists?!
|
||||||
toField = Csv.toField . iso8601Show
|
toField = Csv.toField . iso8601Show
|
||||||
|
{-
|
||||||
|
• Overlapping instances for Csv.ToField String
|
||||||
|
arising from a use of ‘Csv.toField’
|
||||||
|
Matching instances:
|
||||||
|
instance ISO8601 t => Csv.ToField t
|
||||||
|
-- Defined at src/Data/Time/Clock/Instances.hs:45:11
|
||||||
|
instance Csv.ToField [Char]
|
||||||
|
-- Defined in ‘cassava-0.5.2.0:Data.Csv.Conversion’
|
||||||
|
• In the first argument of ‘(.)’, namely ‘Csv.toField’
|
||||||
|
In the expression: Csv.toField . iso8601Show
|
||||||
|
In an equation for ‘Csv.toField’:
|
||||||
|
Csv.toField = Csv.toField . iso8601Show
|
||||||
|
-}
|
||||||
|
|
||||||
instance Csv.FromField UTCTime where
|
instance {-# OVERLAPPABLE #-} ISO8601 t => Csv.FromField t where -- overlapped for ZonedTime in Handler.Utils.DateTime
|
||||||
parseField = iso8601ParseM <=< Csv.parseField
|
parseField = iso8601ParseM <=< Csv.parseField
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- CalendarDiffDays
|
-- CalendarDiffDays
|
||||||
--
|
--
|
||||||
-- CalendarDiffDays is basically a pair of Integers, we are stored in the DB as an Array of Word (Word8 probably suffices already)
|
-- CalendarDiffDays is basically a pair of Integers, we are stored in the DB as an Array of Word (Word8 probably suffices already)
|
||||||
|
|||||||
@ -150,7 +150,7 @@ mkUserlistTable qid = do
|
|||||||
dbtRowKey = (E.^. LmsUserlistId)
|
dbtRowKey = (E.^. LmsUserlistId)
|
||||||
dbtProj = dbtProjFilteredPostId -- TODO: or dbtProjSimple what is the difference?
|
dbtProj = dbtProjFilteredPostId -- TODO: or dbtProjSimple what is the difference?
|
||||||
dbtColonnade = dbColonnade $ mconcat
|
dbtColonnade = dbColonnade $ mconcat
|
||||||
[ sortable (Just "ident") (i18nCell MsgTableLmsIdent) $ \DBRow{ dbrOutput = Entity _ LmsUserlist{..} } -> textCell lmsUserlistIdent
|
[ sortable (Just "ident") (i18nCell MsgTableLmsIdent) $ \DBRow{ dbrOutput = Entity _ LmsUserlist{..} } -> textCell $ getLmsIdent lmsUserlistIdent
|
||||||
, sortable (Just "failed") (i18nCell MsgTableLmsFailed) $ \DBRow{ dbrOutput = Entity _ LmsUserlist{..} } -> isBadCell lmsUserlistFailed
|
, sortable (Just "failed") (i18nCell MsgTableLmsFailed) $ \DBRow{ dbrOutput = Entity _ LmsUserlist{..} } -> isBadCell lmsUserlistFailed
|
||||||
]
|
]
|
||||||
dbtSorting = Map.fromList
|
dbtSorting = Map.fromList
|
||||||
|
|||||||
@ -69,7 +69,7 @@ resultUser = _dbrOutput . _4 . _Just
|
|||||||
-- required for import only
|
-- required for import only
|
||||||
data LmsResultTableCsv = LmsResultTableCsv
|
data LmsResultTableCsv = LmsResultTableCsv
|
||||||
{ csvLRTident :: LmsIdent
|
{ csvLRTident :: LmsIdent
|
||||||
, csvLRTsuccess :: UTCTime
|
, csvLRTsuccess :: Day
|
||||||
}
|
}
|
||||||
deriving Generic
|
deriving Generic
|
||||||
makeLenses_ ''LmsResultTableCsv
|
makeLenses_ ''LmsResultTableCsv
|
||||||
@ -80,19 +80,19 @@ instance Csv.FromRecord LmsResultTableCsv -- default suffices
|
|||||||
|
|
||||||
-- csv with headers
|
-- csv with headers
|
||||||
lmsResultTableCsvHeader :: Csv.Header
|
lmsResultTableCsvHeader :: Csv.Header
|
||||||
lmsResultTableCsvHeader = Csv.header [ "identification", "timestamp-success" ]
|
lmsResultTableCsvHeader = Csv.header [ "identification", "day-success" ]
|
||||||
|
|
||||||
instance ToNamedRecord LmsResultTableCsv where
|
instance ToNamedRecord LmsResultTableCsv where
|
||||||
toNamedRecord LmsResultTableCsv{..} = Csv.namedRecord
|
toNamedRecord LmsResultTableCsv{..} = Csv.namedRecord
|
||||||
[ "identification" Csv..= csvLRTident
|
[ "identification" Csv..= csvLRTident
|
||||||
, "timestamp-success" Csv..= csvLRTsuccess
|
, "day-success" Csv..= csvLRTsuccess
|
||||||
]
|
]
|
||||||
|
|
||||||
instance FromNamedRecord LmsResultTableCsv where
|
instance FromNamedRecord LmsResultTableCsv where
|
||||||
parseNamedRecord (lsfHeaderTranslate -> csv)
|
parseNamedRecord (lsfHeaderTranslate -> csv)
|
||||||
= LmsResultTableCsv
|
= LmsResultTableCsv
|
||||||
<$> csv Csv..: "identification"
|
<$> csv Csv..: "identification"
|
||||||
<*> csv Csv..: "timestamp-success"
|
<*> csv Csv..: "day-success"
|
||||||
|
|
||||||
|
|
||||||
instance CsvColumnsExplained LmsResultTableCsv where
|
instance CsvColumnsExplained LmsResultTableCsv where
|
||||||
@ -124,8 +124,8 @@ mkResultTable qid = do
|
|||||||
dbtRowKey = queryLmsResult >>> (E.^. LmsResultId)
|
dbtRowKey = queryLmsResult >>> (E.^. LmsResultId)
|
||||||
dbtProj = dbtProjFilteredPostId -- TODO: or dbtProjSimple what is the difference?
|
dbtProj = dbtProjFilteredPostId -- TODO: or dbtProjSimple what is the difference?
|
||||||
dbtColonnade = dbColonnade $ mconcat
|
dbtColonnade = dbColonnade $ mconcat
|
||||||
[ sortable (Just "ident") (i18nCell MsgTableLmsIdent) $ \(view $ resultLmsResult . _entityVal . _lmsResultIdent -> ident) -> textCell ident
|
[ sortable (Just "ident") (i18nCell MsgTableLmsIdent) $ \(view $ resultLmsResult . _entityVal . _lmsResultIdent . _getLmsIdent -> ident) -> textCell ident
|
||||||
, sortable (Just "sucess") (i18nCell MsgTableLmsSuccess) $ \(view $ resultLmsResult . _entityVal . _lmsResultSuccess -> success) -> dateTimeCell success
|
, sortable (Just "sucess") (i18nCell MsgTableLmsSuccess) $ \(view $ resultLmsResult . _entityVal . _lmsResultSuccess -> success) -> dayCell success
|
||||||
] -- TODO: add more columns for manual debugging view !!!
|
] -- TODO: add more columns for manual debugging view !!!
|
||||||
dbtSorting = Map.fromList
|
dbtSorting = Map.fromList
|
||||||
[ ("ident" , SortColumn $ queryLmsResult >>> (E.^. LmsResultIdent))
|
[ ("ident" , SortColumn $ queryLmsResult >>> (E.^. LmsResultIdent))
|
||||||
@ -154,4 +154,3 @@ getLmsResultR qid = do
|
|||||||
siteLayoutMsg MsgMenuLmsResult $ do
|
siteLayoutMsg MsgMenuLmsResult $ do
|
||||||
setTitleI MsgMenuLmsResult
|
setTitleI MsgMenuLmsResult
|
||||||
$(widgetFile "lms-result")
|
$(widgetFile "lms-result")
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ import Data.Time.Zones
|
|||||||
import qualified Data.Time.Zones as TZ
|
import qualified Data.Time.Zones as TZ
|
||||||
|
|
||||||
import qualified Data.Time.Format as Time
|
import qualified Data.Time.Format as Time
|
||||||
import Data.Time.Format.ISO8601 (iso8601Show)
|
-- import Data.Time.Format.ISO8601 (iso8601Show)
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
@ -317,10 +317,12 @@ formatTimeRangeMail = formatTimeRange' formatTimeMail
|
|||||||
formatGregorianW :: (YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId) => Integer -> Int -> Int -> WidgetFor UniWorX ()
|
formatGregorianW :: (YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId) => Integer -> Int -> Int -> WidgetFor UniWorX ()
|
||||||
formatGregorianW y m d = formatTimeW SelFormatDate $ fromGregorian y m d
|
formatGregorianW y m d = formatTimeW SelFormatDate $ fromGregorian y m d
|
||||||
|
|
||||||
instance Csv.ToField ZonedTime where
|
-- generic instance from Data.Time.Clock.Instances suffices
|
||||||
toField = Csv.toField . iso8601Show
|
--instance Csv.ToField ZonedTime where
|
||||||
|
-- toField = Csv.toField . iso8601Show
|
||||||
|
|
||||||
instance Csv.FromField ZonedTime where
|
-- overlaps instance from Data.Time.Clock.Instances
|
||||||
|
instance {-# OVERLAPS #-} Csv.FromField ZonedTime where
|
||||||
parseField = parse <=< Csv.parseField
|
parseField = parse <=< Csv.parseField
|
||||||
where
|
where
|
||||||
parse t = asum $ do
|
parse t = asum $ do
|
||||||
|
|||||||
@ -131,11 +131,15 @@ modalCell content = cell $ modal (toWidget $ hasComment True) (Right $ toWidget
|
|||||||
timeCell :: IsDBTable m a => UTCTime -> DBCell m a
|
timeCell :: IsDBTable m a => UTCTime -> DBCell m a
|
||||||
timeCell t = cell $ formatTime SelFormatTime t >>= toWidget
|
timeCell t = cell $ formatTime SelFormatTime t >>= toWidget
|
||||||
|
|
||||||
|
dateTimeCell :: IsDBTable m a => UTCTime -> DBCell m a
|
||||||
|
dateTimeCell t = cell $ formatTime SelFormatDateTime t >>= toWidget
|
||||||
|
|
||||||
dateCell :: IsDBTable m a => UTCTime -> DBCell m a
|
dateCell :: IsDBTable m a => UTCTime -> DBCell m a
|
||||||
dateCell t = cell $ formatTime SelFormatDate t >>= toWidget
|
dateCell t = cell $ formatTime SelFormatDate t >>= toWidget
|
||||||
|
|
||||||
dateTimeCell :: IsDBTable m a => UTCTime -> DBCell m a
|
dayCell :: IsDBTable m a => Day -> DBCell m a
|
||||||
dateTimeCell t = cell $ formatTime SelFormatDateTime t >>= toWidget
|
dayCell utctDay = cell $ formatTime SelFormatDate UTCTime{..} >>= toWidget
|
||||||
|
where utctDayTime = 0
|
||||||
|
|
||||||
-- | Show a date, and highlight date earlier than given watershed with an icon and cell class Warning
|
-- | Show a date, and highlight date earlier than given watershed with an icon and cell class Warning
|
||||||
--
|
--
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{-|
|
{-|
|
||||||
Module: Model.Types.Lms
|
Module: Model.Types.Lms
|
||||||
Description: Types for Lms
|
Description: Types for Learning Management System Interface operated by Know how! AG
|
||||||
|
|
||||||
-}
|
-}
|
||||||
module Model.Types.Lms
|
module Model.Types.Lms
|
||||||
@ -8,11 +8,23 @@ module Model.Types.Lms
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Import.NoModel
|
import Import.NoModel
|
||||||
|
import Database.Persist.Sql
|
||||||
|
import qualified Data.Csv as Csv
|
||||||
|
import Utils.Lens.TH
|
||||||
|
|
||||||
|
newtype LmsIdent = LmsIdent { getLmsIdent :: Text }
|
||||||
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
deriving newtype (NFData, PersistField, PersistFieldSql, Csv.ToField, Csv.FromField)
|
||||||
|
|
||||||
type LmsIdent = Text
|
makeLenses_ ''LmsIdent
|
||||||
|
|
||||||
data LmsNotfication = Blocked | Successs | Alive
|
data LmsNotification = LmsAlive | LmsBlocked | LmsSuccesss Day
|
||||||
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable, NFData)
|
||||||
deriving (Universe, Finite, NFData)
|
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ constructorTagModifier = camelToPathPiece' 1
|
||||||
|
, fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
, omitNothingFields = True
|
||||||
|
, sumEncoding = TaggedObject "lmsaudit" "lmsaction"
|
||||||
|
} ''LmsNotification
|
||||||
|
derivePersistFieldJSON ''LmsNotification
|
||||||
|
|||||||
Reference in New Issue
Block a user