feat(dbtable): extra representations
This commit is contained in:
parent
9a3f401b38
commit
2c0fc63be1
@ -346,6 +346,7 @@ postAdminFeaturesR = do
|
|||||||
& defaultSorting [SortAscBy "key"]
|
& defaultSorting [SortAscBy "key"]
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in dbTable psValidator DBTable{..}
|
in dbTable psValidator DBTable{..}
|
||||||
|
|
||||||
mkStudytermsTable :: Set StudyTermsId -> Set StudyTermsId -> Set (Entity School) -> DB (FormResult (DBFormResult StudyTermsId (Maybe Text, Maybe Text, Set SchoolId, Set StudyTermsId, Maybe StudyDegreeId, Maybe StudyFieldType) (DBRow (Entity StudyTerms, Set (Entity StudyTerms), Set SchoolId))), Widget)
|
mkStudytermsTable :: Set StudyTermsId -> Set StudyTermsId -> Set (Entity School) -> DB (FormResult (DBFormResult StudyTermsId (Maybe Text, Maybe Text, Set SchoolId, Set StudyTermsId, Maybe StudyDegreeId, Maybe StudyFieldType) (DBRow (Entity StudyTerms, Set (Entity StudyTerms), Set SchoolId))), Widget)
|
||||||
@ -401,6 +402,8 @@ postAdminFeaturesR = do
|
|||||||
& defaultSorting [SortAscBy "isnew", SortAscBy "isbad", SortAscBy "key"]
|
& defaultSorting [SortAscBy "isnew", SortAscBy "isbad", SortAscBy "key"]
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
queryField = id
|
queryField = id
|
||||||
_dbrKey' :: Getter (DBRow (Entity StudyTerms, _, _)) StudyTermsId
|
_dbrKey' :: Getter (DBRow (Entity StudyTerms, _, _)) StudyTermsId
|
||||||
@ -438,6 +441,7 @@ postAdminFeaturesR = do
|
|||||||
psValidator = def & defaultSorting [SortAscBy "incidence", SortAscBy "key", SortAscBy "name"]
|
psValidator = def & defaultSorting [SortAscBy "incidence", SortAscBy "key", SortAscBy "name"]
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in dbTable psValidator DBTable{..}
|
in dbTable psValidator DBTable{..}
|
||||||
|
|
||||||
mkParentCandidateTable =
|
mkParentCandidateTable =
|
||||||
@ -477,6 +481,8 @@ postAdminFeaturesR = do
|
|||||||
& defaultSorting [SortAscBy "child", SortAscBy "incidence", SortAscBy "parent"]
|
& defaultSorting [SortAscBy "child", SortAscBy "incidence", SortAscBy "parent"]
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
queryCandidate (c `E.LeftOuterJoin` _ `E.LeftOuterJoin` _) = c
|
queryCandidate (c `E.LeftOuterJoin` _ `E.LeftOuterJoin` _) = c
|
||||||
queryParent (_ `E.LeftOuterJoin` p `E.LeftOuterJoin` _) = p
|
queryParent (_ `E.LeftOuterJoin` p `E.LeftOuterJoin` _) = p
|
||||||
@ -517,6 +523,8 @@ postAdminFeaturesR = do
|
|||||||
& defaultSorting [SortAscBy "key", SortAscBy "incidence"]
|
& defaultSorting [SortAscBy "key", SortAscBy "incidence"]
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
queryCandidate (c `E.LeftOuterJoin` _) = c
|
queryCandidate (c `E.LeftOuterJoin` _) = c
|
||||||
queryTerm (_ `E.LeftOuterJoin` t) = t
|
queryTerm (_ `E.LeftOuterJoin` t) = t
|
||||||
|
|||||||
@ -128,6 +128,8 @@ getAllocationListR = do
|
|||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
dbtIdent = allocationListIdent
|
dbtIdent = allocationListIdent
|
||||||
|
|
||||||
psValidator :: PSValidator _ _
|
psValidator :: PSValidator _ _
|
||||||
|
|||||||
@ -317,6 +317,7 @@ postAUsersR tid ssh ash = do
|
|||||||
, dbtCsvExampleData = Nothing
|
, dbtCsvExampleData = Nothing
|
||||||
}
|
}
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
allocationUsersDBTableValidator = def
|
allocationUsersDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "priority", SortAscBy "user-matriculation"]
|
& defaultSorting [SortAscBy "priority", SortAscBy "user-matriculation"]
|
||||||
& defaultPagesize (PagesizeLimit 500)
|
& defaultPagesize (PagesizeLimit 500)
|
||||||
|
|||||||
@ -491,6 +491,8 @@ postCApplicationsR tid ssh csh = do
|
|||||||
where
|
where
|
||||||
Entity _ User{..} = existing ^. singular (ix appId . resultUser)
|
Entity _ User{..} = existing ^. singular (ix appId . resultUser)
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
dbtIdent = courseApplicationsIdent
|
dbtIdent = courseApplicationsIdent
|
||||||
|
|
||||||
psValidator :: PSValidator _ _
|
psValidator :: PSValidator _ _
|
||||||
|
|||||||
@ -197,6 +197,7 @@ makeCourseTable whereClause colChoices psValidator = do
|
|||||||
, dbtIdent = "courses" :: Text
|
, dbtIdent = "courses" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
getCourseListR :: Handler Html
|
getCourseListR :: Handler Html
|
||||||
|
|||||||
@ -239,6 +239,7 @@ getCShowR tid ssh csh = do
|
|||||||
dbtIdent = "tutorials"
|
dbtIdent = "tutorials"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
tutorialDBTableValidator = def
|
tutorialDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "type", SortAscBy "name"]
|
& defaultSorting [SortAscBy "type", SortAscBy "name"]
|
||||||
|
|||||||
@ -377,6 +377,7 @@ courseUserExamsSection (Entity cid Course{..}) (Entity uid _) = do
|
|||||||
dbtIdent = "course-user-exams"
|
dbtIdent = "course-user-exams"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
examDBTableValidator = def & defaultSorting [SortAscBy "registration-time"]
|
examDBTableValidator = def & defaultSorting [SortAscBy "registration-time"]
|
||||||
postprocess :: FormResult (First ExamActionData, DBFormResult ExamId (Bool, _) _) -> FormResult (ExamActionData, Map ExamId _)
|
postprocess :: FormResult (First ExamActionData, DBFormResult ExamId (Bool, _) _) -> FormResult (ExamActionData, Map ExamId _)
|
||||||
postprocess inp = do
|
postprocess inp = do
|
||||||
@ -499,6 +500,7 @@ courseUserTutorialsSection (Entity cid Course{..}) (Entity uid _) = do
|
|||||||
dbtIdent = "tutorials"
|
dbtIdent = "tutorials"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
tutorialDBTableValidator = def & defaultSorting [SortAscBy "type", SortAscBy "name"]
|
tutorialDBTableValidator = def & defaultSorting [SortAscBy "type", SortAscBy "name"]
|
||||||
postprocess :: FormResult (First TutorialActionData, DBFormResult TutorialParticipantId (Bool, _) _) -> FormResult (TutorialActionData, Map TutorialParticipantId _)
|
postprocess :: FormResult (First TutorialActionData, DBFormResult TutorialParticipantId (Bool, _) _) -> FormResult (TutorialActionData, Map TutorialParticipantId _)
|
||||||
postprocess inp = do
|
postprocess inp = do
|
||||||
|
|||||||
@ -167,10 +167,10 @@ colUserSheets shns = cap (Sortable Nothing caption) $ foldMap userSheetCol shns
|
|||||||
|
|
||||||
|
|
||||||
data UserTableCsv = UserTableCsv
|
data UserTableCsv = UserTableCsv
|
||||||
{ csvUserName :: Text
|
{ csvUserName :: UserDisplayName
|
||||||
, csvUserSex :: Maybe Sex
|
, csvUserSex :: Maybe Sex
|
||||||
, csvUserMatriculation :: Maybe Text
|
, csvUserMatriculation :: Maybe UserMatriculation
|
||||||
, csvUserEmail :: CI Email
|
, csvUserEmail :: UserEmail
|
||||||
, csvUserStudyFeatures :: UserTableStudyFeatures
|
, csvUserStudyFeatures :: UserTableStudyFeatures
|
||||||
, csvUserSubmissionGroup :: Maybe SubmissionGroupName
|
, csvUserSubmissionGroup :: Maybe SubmissionGroupName
|
||||||
, csvUserRegistration :: UTCTime
|
, csvUserRegistration :: UTCTime
|
||||||
@ -482,6 +482,7 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
CourseUserNote{..} <- lift . lift $ getJust noteId
|
CourseUserNote{..} <- lift . lift $ getJust noteId
|
||||||
return courseUserNoteNote
|
return courseUserNoteNote
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = withCsvExtraRep (UserCsvExportData True) dbtCsvEncode []
|
||||||
over _1 postprocess <$> dbTable psValidator DBTable{..}
|
over _1 postprocess <$> dbTable psValidator DBTable{..}
|
||||||
where
|
where
|
||||||
postprocess :: FormResult (First act', DBFormResult UserId Bool UserTableData) -> FormResult (act', Set UserId)
|
postprocess :: FormResult (First act', DBFormResult UserId Bool UserTableData) -> FormResult (act', Set UserId)
|
||||||
|
|||||||
@ -71,6 +71,7 @@ mkExamTable (Entity cid Course{..}) = do
|
|||||||
dbtIdent = "exams"
|
dbtIdent = "exams"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
examDBTableValidator = def
|
examDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "time"]
|
& defaultSorting [SortAscBy "time"]
|
||||||
|
|||||||
@ -944,6 +944,8 @@ postEUsersR tid ssh csh examn = do
|
|||||||
[occId] -> return occId
|
[occId] -> return occId
|
||||||
_other -> throwM ExamUserCsvExceptionNoMatchingOccurrence
|
_other -> throwM ExamUserCsvExceptionNoMatchingOccurrence
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
examUsersDBTableValidator = def & defaultSorting [SortAscBy "user-name"]
|
examUsersDBTableValidator = def & defaultSorting [SortAscBy "user-name"]
|
||||||
& defaultPagesize PagesizeAll
|
& defaultPagesize PagesizeAll
|
||||||
|
|
||||||
|
|||||||
@ -406,6 +406,8 @@ postEGradesR tid ssh csh examn = do
|
|||||||
}
|
}
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
examUsersDBTableValidator = def & defaultSorting [SortAscBy "is-synced", SortAscBy "user-name"]
|
examUsersDBTableValidator = def & defaultSorting [SortAscBy "is-synced", SortAscBy "user-name"]
|
||||||
& defaultPagesize PagesizeAll
|
& defaultPagesize PagesizeAll
|
||||||
|
|
||||||
|
|||||||
@ -249,6 +249,8 @@ getEOExamsR = do
|
|||||||
|
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
examsDBTableValidator = def
|
examsDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "is-synced", SortAscBy "exam-time"]
|
& defaultSorting [SortAscBy "is-synced", SortAscBy "exam-time"]
|
||||||
|
|||||||
@ -70,6 +70,7 @@ getEExamListR = do
|
|||||||
dbtIdent = "external-exams"
|
dbtIdent = "external-exams"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
examDBTableValidator = def
|
examDBTableValidator = def
|
||||||
& defaultSorting [SortDescBy "term", SortAscBy "school", SortAscBy "course", SortAscBy "name"]
|
& defaultSorting [SortDescBy "term", SortAscBy "school", SortAscBy "course", SortAscBy "name"]
|
||||||
& forceFilter "may-access" (Any True)
|
& forceFilter "may-access" (Any True)
|
||||||
|
|||||||
@ -144,6 +144,7 @@ getMaterialListR tid ssh csh = do
|
|||||||
, dbtFilterUI = mempty
|
, dbtFilterUI = mempty
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
let headingLong = prependCourseTitle tid ssh csh MsgMaterialListHeading
|
let headingLong = prependCourseTitle tid ssh csh MsgMaterialListHeading
|
||||||
@ -248,6 +249,7 @@ getMShowR tid ssh csh mnm = do
|
|||||||
]
|
]
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
return (matEnt,fileTable',zipLink)
|
return (matEnt,fileTable',zipLink)
|
||||||
-- File table has no filtering by access, because we assume that
|
-- File table has no filtering by access, because we assume that
|
||||||
|
|||||||
@ -199,6 +199,7 @@ newsUpcomingSheets uid = do
|
|||||||
, dbtIdent = "upcoming-sheets" :: Text
|
, dbtIdent = "upcoming-sheets" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
$(widgetFile "news/upcomingSheets")
|
$(widgetFile "news/upcomingSheets")
|
||||||
|
|
||||||
@ -334,6 +335,7 @@ newsUpcomingExams uid = do
|
|||||||
dbtIdent = "exams"
|
dbtIdent = "exams"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
examDBTableValidator = def
|
examDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "time"]
|
& defaultSorting [SortAscBy "time"]
|
||||||
|
|||||||
@ -533,6 +533,7 @@ mkOwnedCoursesTable =
|
|||||||
dbtParams = def
|
dbtParams = def
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid in (_1 %~ getAny) <$> dbTableWidget validator DBTable{..}
|
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid in (_1 %~ getAny) <$> dbTableWidget validator DBTable{..}
|
||||||
|
|
||||||
|
|
||||||
@ -585,6 +586,7 @@ mkEnrolledCoursesTable =
|
|||||||
, dbtParams = def
|
, dbtParams = def
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -665,6 +667,7 @@ mkSubmissionTable =
|
|||||||
dbtParams = def
|
dbtParams = def
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
||||||
dbtSorting = dbtSorting' uid
|
dbtSorting = dbtSorting' uid
|
||||||
in dbTableWidget' validator DBTable{..}
|
in dbTableWidget' validator DBTable{..}
|
||||||
@ -725,6 +728,7 @@ mkSubmissionGroupTable =
|
|||||||
dbtParams = def
|
dbtParams = def
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
||||||
in dbTableWidget' validator DBTable{..}
|
in dbTableWidget' validator DBTable{..}
|
||||||
|
|
||||||
@ -800,6 +804,7 @@ mkCorrectionsTable =
|
|||||||
dbtParams = def
|
dbtParams = def
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
in \uid -> let dbtSQLQuery = dbtSQLQuery' uid
|
||||||
in dbTableWidget' validator DBTable{..}
|
in dbTableWidget' validator DBTable{..}
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,8 @@ getSchoolListR = do
|
|||||||
|
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
dbtIdent :: Text
|
dbtIdent :: Text
|
||||||
dbtIdent = "schools"
|
dbtIdent = "schools"
|
||||||
|
|||||||
@ -174,6 +174,7 @@ getSheetListR tid ssh csh = do
|
|||||||
, dbtIdent = "sheets" :: Text
|
, dbtIdent = "sheets" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
-- ) ( -- !!!DEPRECTAED!!! Summary only over shown rows !!!
|
-- ) ( -- !!!DEPRECTAED!!! Summary only over shown rows !!!
|
||||||
-- -- Collect summary over all Sheets, not just the ones shown due to pagination:
|
-- -- Collect summary over all Sheets, not just the ones shown due to pagination:
|
||||||
|
|||||||
@ -97,6 +97,7 @@ getSShowR tid ssh csh shn = do
|
|||||||
, dbtParams = def
|
, dbtParams = def
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
(hasHints, hasSolution) <- runDB $ do
|
(hasHints, hasSolution) <- runDB $ do
|
||||||
hasHints <- E.selectExists . E.from $ \sheet' ->
|
hasHints <- E.selectExists . E.from $ \sheet' ->
|
||||||
|
|||||||
@ -536,6 +536,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
, dbtParams = def
|
, dbtParams = def
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
mFileTable <- traverse (runDB . dbTableWidget' def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid
|
mFileTable <- traverse (runDB . dbTableWidget' def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid
|
||||||
|
|
||||||
|
|||||||
@ -409,6 +409,7 @@ makeCorrectionsTable whereClause dbtColonnade dbtFilterUI psValidator dbtParams
|
|||||||
, dbtIdent = "corrections" :: Text
|
, dbtIdent = "corrections" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
data ActionCorrections = CorrDownload
|
data ActionCorrections = CorrDownload
|
||||||
|
|||||||
@ -249,6 +249,7 @@ postMessageListR = do
|
|||||||
, dbtIdent = "messages" :: Text
|
, dbtIdent = "messages" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
let tableRes = tableRes' <&> _2 %~ Map.keysSet . Map.filter id . getDBFormResult (const False)
|
let tableRes = tableRes' <&> _2 %~ Map.keysSet . Map.filter id . getDBFormResult (const False)
|
||||||
|
|||||||
@ -154,6 +154,7 @@ getTermShowR = do
|
|||||||
dbtIdent = "terms" :: Text
|
dbtIdent = "terms" :: Text
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
termDBTableValidator = def & defaultSorting [SortDescBy "term-id"]
|
termDBTableValidator = def & defaultSorting [SortDescBy "term-id"]
|
||||||
in dbTableWidget' termDBTableValidator termDBTable
|
in dbTableWidget' termDBTableValidator termDBTable
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
|
|||||||
@ -91,6 +91,7 @@ getCTutorialListR tid ssh csh = do
|
|||||||
dbtIdent = "tutorials"
|
dbtIdent = "tutorials"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
|
|
||||||
tutorialDBTableValidator = def
|
tutorialDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "type", SortAscBy "name"]
|
& defaultSorting [SortAscBy "type", SortAscBy "name"]
|
||||||
|
|||||||
@ -215,6 +215,7 @@ postUsersR = do
|
|||||||
, dbtIdent = "users" :: Text
|
, dbtIdent = "users" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
, dbtCsvDecode = Nothing
|
, dbtCsvDecode = Nothing
|
||||||
|
, dbtExtraReps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
formResult usersRes $ \case
|
formResult usersRes $ \case
|
||||||
|
|||||||
@ -529,6 +529,7 @@ makeExternalExamUsersTable mode (Entity eeId ExternalExam{..}) = do
|
|||||||
, GuessUserFirstName <$> csvEUserFirstName
|
, GuessUserFirstName <$> csvEUserFirstName
|
||||||
]
|
]
|
||||||
maybe (throwM ExamUserCsvExceptionNoMatchingUser) return =<< guessUser criteria (Just 1) -- we're only interested in at most one match
|
maybe (throwM ExamUserCsvExceptionNoMatchingUser) return =<< guessUser criteria (Just 1) -- we're only interested in at most one match
|
||||||
|
dbtExtraReps = []
|
||||||
externalExamUsersDBTableValidator = def
|
externalExamUsersDBTableValidator = def
|
||||||
& defaultSorting (bool id (SortAscBy "is-synced" :) (mode == EEUMGrades) [SortAscBy "user-name"])
|
& defaultSorting (bool id (SortAscBy "is-synced" :) (mode == EEUMGrades) [SortAscBy "user-name"])
|
||||||
& defaultPagesize PagesizeAll
|
& defaultPagesize PagesizeAll
|
||||||
|
|||||||
@ -13,9 +13,10 @@ module Handler.Utils.Table.Pagination
|
|||||||
, module Handler.Utils.Table.Pagination.CsvColumnExplanations
|
, module Handler.Utils.Table.Pagination.CsvColumnExplanations
|
||||||
, DBCsvActionMode(..)
|
, DBCsvActionMode(..)
|
||||||
, DBCsvDiff(..), _DBCsvDiffNew, _DBCsvDiffExisting, _DBCsvDiffMissing, _dbCsvOldKey, _dbCsvOld, _dbCsvNewKey, _dbCsvNew
|
, DBCsvDiff(..), _DBCsvDiffNew, _DBCsvDiffExisting, _DBCsvDiffMissing, _dbCsvOldKey, _dbCsvOld, _dbCsvNewKey, _dbCsvNew
|
||||||
, DBTCsvEncode(..), DBTCsvDecode(..)
|
, DBTCsvEncode(..), DBTCsvDecode(..), DBTExtraRep(..)
|
||||||
, DBTable(..), DBFilterUI, IsDBTable(..), DBCell(..)
|
, DBTable(..), DBFilterUI, IsDBTable(..), DBCell(..)
|
||||||
, noCsvEncode, simpleCsvEncode, simpleCsvEncodeM
|
, noCsvEncode, simpleCsvEncode, simpleCsvEncodeM
|
||||||
|
, withCsvExtraRep
|
||||||
, singletonFilter
|
, singletonFilter
|
||||||
, DBParams(..)
|
, DBParams(..)
|
||||||
, cellAttrs, cellContents
|
, cellAttrs, cellContents
|
||||||
@ -120,6 +121,8 @@ import qualified Data.Csv as Csv
|
|||||||
|
|
||||||
import Jobs.Queue
|
import Jobs.Queue
|
||||||
|
|
||||||
|
import Data.Typeable (eqT)
|
||||||
|
|
||||||
|
|
||||||
#if MIN_VERSION_base(4,11,0)
|
#if MIN_VERSION_base(4,11,0)
|
||||||
type Monoid' = Monoid
|
type Monoid' = Monoid
|
||||||
@ -585,11 +588,17 @@ data DBTCsvEncode r' k' csv = forall exportData.
|
|||||||
) => DBTCsvEncode
|
) => DBTCsvEncode
|
||||||
{ dbtCsvExportForm :: AForm DB exportData
|
{ dbtCsvExportForm :: AForm DB exportData
|
||||||
, dbtCsvHeader :: Maybe exportData -> DB Csv.Header -- ^ @exportData@ is @Nothing@, if we're reporting an error or exporting example data
|
, dbtCsvHeader :: Maybe exportData -> DB Csv.Header -- ^ @exportData@ is @Nothing@, if we're reporting an error or exporting example data
|
||||||
, dbtCsvExampleData :: Maybe [csv]
|
, dbtCsvExampleData :: Maybe [csv]
|
||||||
, dbtCsvDoEncode :: exportData -> ConduitT (k', r') csv DB ()
|
, dbtCsvDoEncode :: exportData -> ConduitT (k', r') csv DB ()
|
||||||
, dbtCsvName :: FilePath
|
, dbtCsvName :: FilePath
|
||||||
, dbtCsvNoExportData :: Maybe (AnIso' exportData ())
|
, dbtCsvNoExportData :: Maybe (AnIso' exportData ())
|
||||||
}
|
}
|
||||||
|
data DBTExtraRep r' k' = forall rep.
|
||||||
|
( HasContentType rep
|
||||||
|
, DBTableKey k'
|
||||||
|
) => DBTExtraRep
|
||||||
|
{ dbtERepDoEncode :: ConduitT (k', r') Void DB rep
|
||||||
|
}
|
||||||
data DBTCsvDecode r' k' csv = forall route csvAction csvActionClass csvException.
|
data DBTCsvDecode r' k' csv = forall route csvAction csvActionClass csvException.
|
||||||
( FromNamedRecord csv, ToNamedRecord csv
|
( FromNamedRecord csv, ToNamedRecord csv
|
||||||
, DBTableKey k'
|
, DBTableKey k'
|
||||||
@ -628,6 +637,7 @@ data DBTable m x = forall a r r' h i t k k' csv colonnade (p :: Pillar).
|
|||||||
, dbtParams :: DBParams m x
|
, dbtParams :: DBParams m x
|
||||||
, dbtCsvEncode :: Maybe (DBTCsvEncode r' k' csv)
|
, dbtCsvEncode :: Maybe (DBTCsvEncode r' k' csv)
|
||||||
, dbtCsvDecode :: Maybe (DBTCsvDecode r' k' csv)
|
, dbtCsvDecode :: Maybe (DBTCsvDecode r' k' csv)
|
||||||
|
, dbtExtraReps :: [DBTExtraRep r' k']
|
||||||
, dbtIdent :: i
|
, dbtIdent :: i
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,6 +676,19 @@ simpleCsvEncodeM fName f = Just DBTCsvEncode
|
|||||||
, dbtCsvExampleData = Nothing
|
, dbtCsvExampleData = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withCsvExtraRep :: forall exportData csv r' k'.
|
||||||
|
Typeable exportData
|
||||||
|
=> exportData
|
||||||
|
-> Maybe (DBTCsvEncode r' k' csv)
|
||||||
|
-> [DBTExtraRep r' k'] -> [DBTExtraRep r' k']
|
||||||
|
withCsvExtraRep exportData mEncode = maybe id (flip snoc) csvExtraRep
|
||||||
|
where csvExtraRep = do
|
||||||
|
DBTCsvEncode{ dbtCsvNoExportData = (_ :: Maybe (AnIso' exportData' ())), .. } <- mEncode
|
||||||
|
Refl <- eqT @exportData @exportData'
|
||||||
|
return DBTExtraRep
|
||||||
|
{ dbtERepDoEncode = toCsvRendered <$> lift (dbtCsvHeader $ Just exportData) <*> (dbtCsvDoEncode exportData .| C.foldMap (pure @[]))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class (MonadHandler m, HandlerSite m ~ UniWorX, Monoid' x, Monoid' (DBCell m x), Default (DBParams m x)) => IsDBTable (m :: Type -> Type) (x :: Type) where
|
class (MonadHandler m, HandlerSite m ~ UniWorX, Monoid' x, Monoid' (DBCell m x), Default (DBParams m x)) => IsDBTable (m :: Type -> Type) (x :: Type) where
|
||||||
data DBParams m x :: Type
|
data DBParams m x :: Type
|
||||||
@ -1262,6 +1285,28 @@ dbTable PSValidator{..} dbtable@DBTable{ dbtIdent = dbtIdent'@(toPathPiece -> db
|
|||||||
]
|
]
|
||||||
_other -> return ()
|
_other -> return ()
|
||||||
|
|
||||||
|
let extraReps = maybe id (flip snoc) csvRep dbtExtraReps
|
||||||
|
where csvRep = do
|
||||||
|
DBTCsvEncode{..} <- dbtCsvEncode
|
||||||
|
noExportData' <- cloneIso <$> dbtCsvNoExportData
|
||||||
|
let exportData = noExportData' # ()
|
||||||
|
return DBTExtraRep
|
||||||
|
{ dbtERepDoEncode = toCsvRendered <$> lift (dbtCsvHeader $ Just exportData) <*> (dbtCsvDoEncode exportData .| C.foldMap (pure @[]))
|
||||||
|
}
|
||||||
|
extraReps' = (typeHtml, Nothing) : map ((,) <$> (\DBTExtraRep{..} -> getContentType dbtERepDoEncode) <*> Just) extraReps
|
||||||
|
doAltRep = maybe True (== dbtIdent) <$> lookupGlobalGetParam GetSelectTable
|
||||||
|
|
||||||
|
maybeT (return ()) $ do
|
||||||
|
guardM doAltRep
|
||||||
|
|
||||||
|
cts <- reqAccept <$> getRequest
|
||||||
|
|
||||||
|
altRep <- hoistMaybe <=< asum $ do
|
||||||
|
mRep <- hoistMaybe . selectRep' extraReps' =<< cts
|
||||||
|
return . return $ mRep <&> \DBTExtraRep{..} -> fmap toTypedContent . runConduit $ C.sourceList (zip currentKeys rows) .| dbtERepDoEncode
|
||||||
|
|
||||||
|
lift $ sendResponse =<< altRep
|
||||||
|
|
||||||
let
|
let
|
||||||
rowCount
|
rowCount
|
||||||
| selectPagesize = fromMaybe 0 $ rows' ^? _head . _1 . _Value
|
| selectPagesize = fromMaybe 0 $ rows' ^? _head . _1 . _Value
|
||||||
@ -1706,4 +1751,4 @@ cap' (view _Cornice -> cornice) = case cornice of
|
|||||||
| otherwise = (_Rowspan # (), "2") : filter (hasn't $ _1 . _Rowspan) attrs
|
| otherwise = (_Rowspan # (), "2") : filter (hasn't $ _1 . _Rowspan) attrs
|
||||||
|
|
||||||
_Rowspan :: Prism' Text ()
|
_Rowspan :: Prism' Text ()
|
||||||
_Rowspan = prism' (\() -> "rowspan") $ flip guardOn () . ((==) `on` CI.mk) "rowspan"
|
_Rowspan = nearly <$> id <*> ((==) `on` CI.mk) $ "rowspan"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ module Handler.Utils.Workflow.Workflow
|
|||||||
( ensureScope
|
( ensureScope
|
||||||
, followEdge
|
, followEdge
|
||||||
, followAutomaticEdges, WorkflowAutomaticEdgeException(..)
|
, followAutomaticEdges, WorkflowAutomaticEdgeException(..)
|
||||||
|
, sourceWorkflowActionInfos
|
||||||
, module Handler.Utils.Workflow.Restriction
|
, module Handler.Utils.Workflow.Restriction
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -14,6 +15,8 @@ import Handler.Utils.Workflow.Restriction
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
import qualified Data.Conduit.Combinators as C
|
||||||
|
|
||||||
|
|
||||||
ensureScope :: IdWorkflowScope -> CryptoFileNameWorkflowWorkflow -> MaybeT DB WorkflowWorkflowId
|
ensureScope :: IdWorkflowScope -> CryptoFileNameWorkflowWorkflow -> MaybeT DB WorkflowWorkflowId
|
||||||
ensureScope wiScope cID = do
|
ensureScope wiScope cID = do
|
||||||
@ -75,3 +78,22 @@ followAutomaticEdges WorkflowGraph{..} = go []
|
|||||||
return (edgeLbl, nodeLbl)
|
return (edgeLbl, nodeLbl)
|
||||||
filledPayloads = Map.keysSet . Map.filter (not . Set.null) $ workflowStateCurrentPayloads history
|
filledPayloads = Map.keysSet . Map.filter (not . Set.null) $ workflowStateCurrentPayloads history
|
||||||
edgeDecisionInput = (cState, filledPayloads)
|
edgeDecisionInput = (cState, filledPayloads)
|
||||||
|
|
||||||
|
|
||||||
|
sourceWorkflowActionInfos
|
||||||
|
:: forall backend m.
|
||||||
|
( MonadHandler m, HandlerSite m ~ UniWorX
|
||||||
|
, BackendCompatible SqlReadBackend backend
|
||||||
|
, MonadCrypto m, MonadCryptoKey m ~ CryptoIDKey
|
||||||
|
, MonadCatch m
|
||||||
|
)
|
||||||
|
=> WorkflowWorkflowId
|
||||||
|
-> WorkflowState FileReference UserId
|
||||||
|
-> ConduitT () (WorkflowActionInfo FileReference UserId) (ReaderT backend m) ()
|
||||||
|
-- ^ Does `mayViewWorkflowAction`
|
||||||
|
sourceWorkflowActionInfos wwId wState = do
|
||||||
|
mAuthId <- maybeAuthId
|
||||||
|
let authCheck WorkflowActionInfo{..}
|
||||||
|
= mayViewWorkflowAction mAuthId wwId waiAction
|
||||||
|
yieldMany (workflowActionInfos wState) .| C.filterM authCheck
|
||||||
|
|
||||||
|
|||||||
@ -131,6 +131,7 @@ getAdminWorkflowDefinitionListR = do
|
|||||||
dbtIdent = "workflow-definitions"
|
dbtIdent = "workflow-definitions"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
workflowDefinitionsDBTableValidator = def
|
workflowDefinitionsDBTableValidator = def
|
||||||
& defaultPagesize PagesizeAll
|
& defaultPagesize PagesizeAll
|
||||||
& defaultSorting [SortAscBy "scope", SortAscBy "name"]
|
& defaultSorting [SortAscBy "scope", SortAscBy "name"]
|
||||||
|
|||||||
@ -118,6 +118,7 @@ getAdminWorkflowInstanceListR = do
|
|||||||
dbtIdent = "workflow-instances"
|
dbtIdent = "workflow-instances"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = []
|
||||||
workflowInstancesDBTableValidator = def
|
workflowInstancesDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "scope", SortAscBy "name"]
|
& defaultSorting [SortAscBy "scope", SortAscBy "name"]
|
||||||
in dbTableDB' workflowInstancesDBTableValidator workflowInstancesDBTable
|
in dbTableDB' workflowInstancesDBTableValidator workflowInstancesDBTable
|
||||||
|
|||||||
@ -11,9 +11,10 @@ module Handler.Workflow.Workflow.List
|
|||||||
, getTopWorkflowWorkflowListR
|
, getTopWorkflowWorkflowListR
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import
|
import Import hiding (Last(..), WriterT)
|
||||||
|
|
||||||
import Utils.Workflow
|
import Utils.Workflow
|
||||||
|
import Handler.Utils.Workflow.Workflow
|
||||||
import Handler.Utils.Workflow.CanonicalRoute
|
import Handler.Utils.Workflow.CanonicalRoute
|
||||||
|
|
||||||
import Handler.Workflow.Workflow.Workflow (WorkflowHistoryItemActor'(..), WorkflowHistoryItemActor)
|
import Handler.Workflow.Workflow.Workflow (WorkflowHistoryItemActor'(..), WorkflowHistoryItemActor)
|
||||||
@ -28,6 +29,13 @@ import qualified Data.CaseInsensitive as CI
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
import qualified Data.Conduit.Combinators as C
|
||||||
|
|
||||||
|
import Data.Semigroup (Last(..))
|
||||||
|
import qualified Data.Monoid as Monoid (Last(..))
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Writer.Strict (WriterT)
|
||||||
|
|
||||||
|
|
||||||
getGlobalWorkflowWorkflowListR :: Handler Html
|
getGlobalWorkflowWorkflowListR :: Handler Html
|
||||||
getGlobalWorkflowWorkflowListR = workflowWorkflowListR WSGlobal
|
getGlobalWorkflowWorkflowListR = workflowWorkflowListR WSGlobal
|
||||||
@ -115,14 +123,49 @@ type WorkflowWorkflowActionData = ( Maybe Text
|
|||||||
, Maybe Icon
|
, Maybe Icon
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data JsonWorkflowWorkflow = JsonWorkflowWorkflow
|
||||||
|
{ jwwScope :: Maybe RouteWorkflowScope
|
||||||
|
, jwwInstance :: Maybe JsonWorkflowInstance
|
||||||
|
, jwwLastAction :: Maybe JsonWorkflowAction
|
||||||
|
, jwwPayload :: Map WorkflowPayloadLabel JsonWorkflowPayload
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
data JsonWorkflowAction = JsonWorkflowAction
|
||||||
|
{ jwaIx :: CryptoUUIDWorkflowStateIndex
|
||||||
|
, jwaTo :: Maybe WorkflowGraphNodeLabel
|
||||||
|
, jwaUser :: Maybe JsonWorkflowUser
|
||||||
|
, jwaTime :: UTCTime
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
data JsonWorkflowInstance = JsonWorkflowInstance
|
||||||
|
{ jwiScope :: RouteWorkflowScope
|
||||||
|
, jwiName :: WorkflowInstanceName
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
data JsonWorkflowPayload = JsonWorkflowPayload
|
||||||
|
{ jwpPayload :: [WorkflowFieldPayloadW Void JsonWorkflowUser]
|
||||||
|
, jwpHasFiles :: Bool
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
data JsonWorkflowUser
|
||||||
|
= JsonWorkflowUserUser
|
||||||
|
{ jwuDisplayName :: UserDisplayName
|
||||||
|
, jwuMatriculation :: Maybe UserMatriculation
|
||||||
|
, jwuDisplayEmail :: UserEmail
|
||||||
|
}
|
||||||
|
| JsonWorkflowUserAnonymous
|
||||||
|
| JsonWorkflowUserHidden
|
||||||
|
| JsonWorkflowUserGone
|
||||||
|
deriving (Generic)
|
||||||
|
|
||||||
resultWorkflowWorkflowId :: Lens' WorkflowWorkflowData CryptoFileNameWorkflowWorkflow
|
resultWorkflowWorkflowId :: Lens' WorkflowWorkflowData CryptoFileNameWorkflowWorkflow
|
||||||
resultWorkflowWorkflowId = _dbrOutput . _1
|
resultWorkflowWorkflowId = _dbrOutput . _1
|
||||||
|
|
||||||
resultRouteScope :: Lens' WorkflowWorkflowData (Maybe RouteWorkflowScope)
|
resultRouteScope :: Lens' WorkflowWorkflowData (Maybe RouteWorkflowScope)
|
||||||
resultRouteScope = _dbrOutput . _2
|
resultRouteScope = _dbrOutput . _2
|
||||||
|
|
||||||
_resultWorkflowWorkflow :: Lens' WorkflowWorkflowData (Entity WorkflowWorkflow)
|
resultWorkflowWorkflow :: Lens' WorkflowWorkflowData (Entity WorkflowWorkflow)
|
||||||
_resultWorkflowWorkflow = _dbrOutput . _3
|
resultWorkflowWorkflow = _dbrOutput . _3
|
||||||
|
|
||||||
resultWorkflowInstance :: Lens' WorkflowWorkflowData (Maybe (Entity WorkflowInstance))
|
resultWorkflowInstance :: Lens' WorkflowWorkflowData (Maybe (Entity WorkflowInstance))
|
||||||
resultWorkflowInstance = _dbrOutput . _4
|
resultWorkflowInstance = _dbrOutput . _4
|
||||||
@ -288,7 +331,7 @@ workflowWorkflowList (title, heading) WWListColumns{..} sqlPred = do
|
|||||||
, singletonMap "current-state" . FilterProjected $ \x (criteria :: Set Text) ->
|
, singletonMap "current-state" . FilterProjected $ \x (criteria :: Set Text) ->
|
||||||
let criteria' = map CI.mk . unpack <$> Set.toList criteria
|
let criteria' = map CI.mk . unpack <$> Set.toList criteria
|
||||||
in maybe False (\cSt -> any (`isInfixOf` cSt) criteria') $ x ^? resultLastAction . _Just . actionTo . _Just . to (map CI.mk . unpack)
|
in maybe False (\cSt -> any (`isInfixOf` cSt) criteria') $ x ^? resultLastAction . _Just . actionTo . _Just . to (map CI.mk . unpack)
|
||||||
, singletonMap "final" . FilterProjected $ \x (criterion :: Last Bool) -> case getLast criterion of
|
, singletonMap "final" . FilterProjected $ \x (criterion :: Monoid.Last Bool) -> case Monoid.getLast criterion of
|
||||||
Nothing -> True
|
Nothing -> True
|
||||||
Just needle -> let val = has (resultLastAction . _Just . actionTo . _Just) x
|
Just needle -> let val = has (resultLastAction . _Just . actionTo . _Just) x
|
||||||
&& has (resultLastAction . _Just . actionFinal . _Just) x
|
&& has (resultLastAction . _Just . actionFinal . _Just) x
|
||||||
@ -306,6 +349,78 @@ workflowWorkflowList (title, heading) WWListColumns{..} sqlPred = do
|
|||||||
dbtIdent = "workflow-workflows"
|
dbtIdent = "workflow-workflows"
|
||||||
dbtCsvEncode = noCsvEncode
|
dbtCsvEncode = noCsvEncode
|
||||||
dbtCsvDecode = Nothing
|
dbtCsvDecode = Nothing
|
||||||
|
dbtExtraReps = [ DBTExtraRep $ toPrettyJSON <$> repWorkflowWorkflowJson, DBTExtraRep $ toYAML <$> repWorkflowWorkflowJson ]
|
||||||
|
|
||||||
|
repWorkflowWorkflowJson :: ConduitT (E.Value WorkflowWorkflowId, WorkflowWorkflowData) Void DB (Map CryptoFileNameWorkflowWorkflow JsonWorkflowWorkflow)
|
||||||
|
repWorkflowWorkflowJson = C.foldMapM $ \(E.Value wwId, res) -> do
|
||||||
|
cID <- encrypt wwId
|
||||||
|
Map.singleton cID <$> do
|
||||||
|
let jwwScope = guardOnM wwListColumnScope $ res ^. resultRouteScope
|
||||||
|
jwwInstance <- fmap join . for (guardOnM wwListColumnInstance $ res ^. resultWorkflowInstance) $ \(Entity _ WorkflowInstance{..}) -> runMaybeT $ do
|
||||||
|
jwiScope <- toRouteWorkflowScope $ _DBWorkflowScope # workflowInstanceScope
|
||||||
|
let jwiName = workflowInstanceName
|
||||||
|
return JsonWorkflowInstance{..}
|
||||||
|
(fmap getLast -> wState) <-
|
||||||
|
let go :: forall m.
|
||||||
|
( MonadHandler m
|
||||||
|
, HandlerSite m ~ UniWorX
|
||||||
|
, MonadCatch m
|
||||||
|
)
|
||||||
|
=> WorkflowActionInfo FileReference UserId
|
||||||
|
-> WriterT (Maybe (Last (CryptoUUIDWorkflowStateIndex, Maybe WorkflowGraphNodeLabel, Maybe JsonWorkflowUser, UTCTime, Map WorkflowPayloadLabel JsonWorkflowPayload))) (SqlPersistT m) ()
|
||||||
|
go WorkflowActionInfo{ waiIx = stIx, waiHistory = (workflowStateCurrentPayloads -> currentPayload), waiAction = WorkflowAction{..}} = maybeT (return ()) $ do
|
||||||
|
stCID <- encryptWorkflowStateIndex wwId stIx
|
||||||
|
|
||||||
|
rScope <- hoistMaybe $ res ^. resultRouteScope
|
||||||
|
|
||||||
|
let toJsonUser (Just (Entity _ User{..})) = JsonWorkflowUserUser
|
||||||
|
{ jwuDisplayName = userDisplayName
|
||||||
|
, jwuMatriculation = userMatrikelnummer
|
||||||
|
, jwuDisplayEmail = userDisplayEmail
|
||||||
|
}
|
||||||
|
toJsonUser Nothing = JsonWorkflowUserGone
|
||||||
|
|
||||||
|
mVia = Map.lookup wpVia . wgnEdges =<< Map.lookup wpTo wgNodes
|
||||||
|
hasWorkflowRole' role = $cachedHereBinary (rScope, wwId, role) . lift . lift $ is _Authorized <$> hasWorkflowRole (Just wwId) role canonRoute False
|
||||||
|
canonRoute = _WorkflowScopeRoute # (rScope, WorkflowWorkflowR cID WWWorkflowR)
|
||||||
|
|
||||||
|
aUser <- for wpUser $ \wpUser' -> lift . maybeT (return JsonWorkflowUserHidden) $ do
|
||||||
|
viewActors <- hoistMaybe $ preview _wgeViewActor =<< mVia
|
||||||
|
guardM $ anyM (otoList viewActors) hasWorkflowRole'
|
||||||
|
resUser <- lift . lift $ traverse getEntity wpUser'
|
||||||
|
return $ case resUser of
|
||||||
|
Just mEnt -> toJsonUser mEnt
|
||||||
|
Nothing -> JsonWorkflowUserAnonymous
|
||||||
|
|
||||||
|
payload <- do
|
||||||
|
payload' <- fmap Map.fromList . forMaybeM (Map.toList currentPayload) $ \x@(payloadLbl, _) -> x <$ do
|
||||||
|
WorkflowPayloadView{..} <- hoistMaybe . Map.lookup payloadLbl $ Map.findWithDefault Map.empty wpTo (wgnPayloadView <$> wgNodes)
|
||||||
|
guardM . $cachedHereBinary payloadLbl . anyM (otoList wpvViewers) $ lift . hasWorkflowRole'
|
||||||
|
forM payload' $ \(otoList -> payloads) -> fmap (uncurry JsonWorkflowPayload . over _2 getAny) . execWriterT @_ @(_, Any) . forM_ payloads $ \case
|
||||||
|
WorkflowFieldPayloadW (WFPText t ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPText t)
|
||||||
|
WorkflowFieldPayloadW (WFPNumber n ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPNumber n)
|
||||||
|
WorkflowFieldPayloadW (WFPBool b ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPBool b)
|
||||||
|
WorkflowFieldPayloadW (WFPDay d ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPDay d)
|
||||||
|
WorkflowFieldPayloadW (WFPFile _ ) -> tell (mempty, Any True)
|
||||||
|
WorkflowFieldPayloadW (WFPUser uid) -> tell . (, mempty) . pure . review (_WorkflowFieldPayloadW . _WorkflowFieldPayload) . toJsonUser =<< lift (lift . lift $ getEntity uid)
|
||||||
|
|
||||||
|
nTo <- runMaybeT $ do
|
||||||
|
WGN{..} <- hoistMaybe $ Map.lookup wpTo wgNodes
|
||||||
|
WorkflowNodeView{..} <- hoistMaybe wgnViewers
|
||||||
|
guardM . lift $ anyM (otoList wnvViewers) hasWorkflowRole'
|
||||||
|
return wpTo
|
||||||
|
|
||||||
|
tell . Just $ Last (stCID, nTo, aUser, wpTime, payload)
|
||||||
|
|
||||||
|
Entity _ WorkflowWorkflow{..} = res ^. resultWorkflowWorkflow
|
||||||
|
wState = review _DBWorkflowState workflowWorkflowState
|
||||||
|
WorkflowGraph{..} = _DBWorkflowGraph # workflowWorkflowGraph
|
||||||
|
in runConduit $ sourceWorkflowActionInfos wwId wState .| execWriterC (C.mapM_ go)
|
||||||
|
|
||||||
|
let jwwLastAction = wState <&> \(jwaIx, jwaTo, jwaUser, jwaTime, _) -> JsonWorkflowAction{..}
|
||||||
|
jwwPayload = wState ^. _Just . _5
|
||||||
|
|
||||||
|
return JsonWorkflowWorkflow{..}
|
||||||
workflowWorkflowDBTableValidator = def
|
workflowWorkflowDBTableValidator = def
|
||||||
& defaultSorting defSort
|
& defaultSorting defSort
|
||||||
& forceFilter "may-access" (Any True)
|
& forceFilter "may-access" (Any True)
|
||||||
@ -317,3 +432,24 @@ workflowWorkflowList (title, heading) WWListColumns{..} sqlPred = do
|
|||||||
siteLayoutMsg heading $ do
|
siteLayoutMsg heading $ do
|
||||||
setTitleI title
|
setTitleI title
|
||||||
$(widgetFile "workflows/workflow-list")
|
$(widgetFile "workflows/workflow-list")
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
} ''JsonWorkflowWorkflow
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
} ''JsonWorkflowAction
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
} ''JsonWorkflowInstance
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
} ''JsonWorkflowPayload
|
||||||
|
|
||||||
|
deriveJSON defaultOptions
|
||||||
|
{ constructorTagModifier = camelToPathPiece' 3
|
||||||
|
, fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
} ''JsonWorkflowUser
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import qualified Data.Set as Set
|
|||||||
import qualified Data.Sequence as Seq
|
import qualified Data.Sequence as Seq
|
||||||
|
|
||||||
import qualified Control.Monad.State.Class as State
|
import qualified Control.Monad.State.Class as State
|
||||||
import Control.Monad.Trans.RWS.Strict (RWST, execRWST)
|
import Control.Monad.Trans.RWS.Strict (RWST)
|
||||||
|
|
||||||
import qualified Crypto.Saltine.Class as Saltine
|
import qualified Crypto.Saltine.Class as Saltine
|
||||||
import qualified Data.Binary as Binary
|
import qualified Data.Binary as Binary
|
||||||
@ -36,7 +36,7 @@ import qualified Data.Scientific as Scientific
|
|||||||
import Text.Blaze (toMarkup)
|
import Text.Blaze (toMarkup)
|
||||||
import Data.Void (absurd)
|
import Data.Void (absurd)
|
||||||
|
|
||||||
import Data.List (inits)
|
import qualified Data.Conduit.Combinators as C
|
||||||
|
|
||||||
|
|
||||||
data WorkflowHistoryItemActor' user = WHIASelf | WHIAOther (Maybe user) | WHIAHidden | WHIAGone
|
data WorkflowHistoryItemActor' user = WHIASelf | WHIAOther (Maybe user) | WHIAHidden | WHIAGone
|
||||||
@ -108,14 +108,10 @@ workflowR rScope cID = do
|
|||||||
, HandlerSite m ~ UniWorX
|
, HandlerSite m ~ UniWorX
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
)
|
)
|
||||||
=> WorkflowStateIndex
|
=> WorkflowActionInfo FileReference UserId
|
||||||
-> Maybe WorkflowGraphNodeLabel
|
|
||||||
-> [WorkflowAction FileReference UserId]
|
|
||||||
-> WorkflowAction FileReference UserId
|
|
||||||
-> RWST () (Maybe (Last WorkflowCurrentState), [WorkflowHistoryItem]) (Map WorkflowPayloadLabel (Set (WorkflowFieldPayloadW FileReference UserId))) (SqlPersistT m) ()
|
-> RWST () (Maybe (Last WorkflowCurrentState), [WorkflowHistoryItem]) (Map WorkflowPayloadLabel (Set (WorkflowFieldPayloadW FileReference UserId))) (SqlPersistT m) ()
|
||||||
go stIx wpFrom history@(workflowStateCurrentPayloads -> currentPayload) act@WorkflowAction{..} = maybeT (return ()) $ do
|
go WorkflowActionInfo{ waiIx = stIx, waiFrom = wpFrom, waiHistory = history@(workflowStateCurrentPayloads -> currentPayload), waiAction = WorkflowAction{..} } = maybeT (return ()) $ do
|
||||||
mAuthId <- maybeAuthId
|
mAuthId <- maybeAuthId
|
||||||
guardM . lift . lift . hoist liftHandler $ mayViewWorkflowAction mAuthId wwId act
|
|
||||||
|
|
||||||
stCID <- encryptWorkflowStateIndex wwId stIx
|
stCID <- encryptWorkflowStateIndex wwId stIx
|
||||||
let nodeView nodeLbl = do
|
let nodeView nodeLbl = do
|
||||||
@ -160,32 +156,18 @@ workflowR rScope cID = do
|
|||||||
payloadSort :: WorkflowFieldPayloadW Void (Maybe (Entity User))
|
payloadSort :: WorkflowFieldPayloadW Void (Maybe (Entity User))
|
||||||
-> WorkflowFieldPayloadW Void (Maybe (Entity User))
|
-> WorkflowFieldPayloadW Void (Maybe (Entity User))
|
||||||
-> Ordering
|
-> Ordering
|
||||||
payloadSort (WorkflowFieldPayloadW a) (WorkflowFieldPayloadW b) = case (a, b) of
|
payloadSort = workflowPayloadSort ordFiles ordUsers
|
||||||
(WFPFile a', _ ) -> absurd a'
|
where
|
||||||
(_, WFPFile a' ) -> absurd a'
|
ordFiles = absurd
|
||||||
(WFPText a', WFPText b' ) -> compareUnicode a' b'
|
ordUsers a' b' = case (a', b') of
|
||||||
(WFPText{}, _ ) -> LT
|
(Nothing, _) -> GT
|
||||||
(WFPNumber a', WFPNumber b') -> compare a' b'
|
(_, Nothing) -> LT
|
||||||
(WFPNumber{}, WFPText{} ) -> GT
|
(Just (Entity _ uA), Just (Entity _ uB))
|
||||||
(WFPNumber{}, _ ) -> LT
|
-> (compareUnicode `on` userSurname) uA uB
|
||||||
(WFPBool a', WFPBool b' ) -> compare a' b'
|
<> (compareUnicode `on` userDisplayName) uA uB
|
||||||
(WFPBool{}, WFPText{} ) -> GT
|
<> comparing userIdent uA uB
|
||||||
(WFPBool{}, WFPNumber{} ) -> GT
|
|
||||||
(WFPBool{}, _ ) -> LT
|
forM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort)) . mapMOf _2 (traverse toTextUrl . bool Nothing (Just fRoute) . getAny) <=< execWriterT @_ @(_, Any) . forM_ payloads $ \case
|
||||||
(WFPDay a', WFPDay b' ) -> compare a' b'
|
|
||||||
(WFPDay{}, WFPText{} ) -> GT
|
|
||||||
(WFPDay{}, WFPNumber{} ) -> GT
|
|
||||||
(WFPDay{}, WFPBool{} ) -> GT
|
|
||||||
(WFPDay{}, _ ) -> LT
|
|
||||||
(WFPUser a', WFPUser b' ) -> case (a', b') of
|
|
||||||
(Nothing, _) -> GT
|
|
||||||
(_, Nothing) -> LT
|
|
||||||
(Just (Entity _ uA), Just (Entity _ uB))
|
|
||||||
-> (compareUnicode `on` userSurname) uA uB
|
|
||||||
<> (compareUnicode `on` userDisplayName) uA uB
|
|
||||||
<> comparing userIdent uA uB
|
|
||||||
(WFPUser{}, _ ) -> GT
|
|
||||||
forM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort)) . mapMOf _2 (traverse toTextUrl . bool Nothing (Just fRoute) . getAny) <=< execWriterT @_ @(_, Any). forM_ payloads $ \case
|
|
||||||
WorkflowFieldPayloadW (WFPText t ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPText t)
|
WorkflowFieldPayloadW (WFPText t ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPText t)
|
||||||
WorkflowFieldPayloadW (WFPNumber n ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPNumber n)
|
WorkflowFieldPayloadW (WFPNumber n ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPNumber n)
|
||||||
WorkflowFieldPayloadW (WFPBool b ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPBool b)
|
WorkflowFieldPayloadW (WFPBool b ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPBool b)
|
||||||
@ -215,14 +197,8 @@ workflowR rScope cID = do
|
|||||||
, pure WorkflowHistoryItem{..}
|
, pure WorkflowHistoryItem{..}
|
||||||
)
|
)
|
||||||
WorkflowGraph{..} = wGraph
|
WorkflowGraph{..} = wGraph
|
||||||
wState = otoList $ review _DBWorkflowState workflowWorkflowState
|
wState = review _DBWorkflowState workflowWorkflowState
|
||||||
in fmap (over _2 (sortOn (Down . whiTime) . reverse) . view _2) . (\act -> execRWST act () Map.empty) $ sequence_
|
in fmap (over _2 (sortOn (Down . whiTime) . reverse) . view _2) . runConduit $ sourceWorkflowActionInfos wwId wState .| execRWSC () Map.empty (C.mapM_ go)
|
||||||
[ go stIx fromSt payload act
|
|
||||||
| fromSt <- Nothing : map (Just . wpTo) wState
|
|
||||||
| act <- wState
|
|
||||||
| stIx <- [minBound..]
|
|
||||||
| payload <- tailEx $ inits wState
|
|
||||||
]
|
|
||||||
return (mEdge, (workflowState, workflowHistory))
|
return (mEdge, (workflowState, workflowHistory))
|
||||||
|
|
||||||
sequenceOf_ (_Just . _1 . _1 . _Just) mEdge
|
sequenceOf_ (_Just . _1 . _1 . _Just) mEdge
|
||||||
|
|||||||
@ -22,8 +22,10 @@ module Model.Types.Workflow
|
|||||||
, WorkflowPayloadLabel(..)
|
, WorkflowPayloadLabel(..)
|
||||||
, WorkflowStateIndex(..), workflowStateIndex, workflowStateSection
|
, WorkflowStateIndex(..), workflowStateIndex, workflowStateSection
|
||||||
, WorkflowState
|
, WorkflowState
|
||||||
|
, WorkflowActionInfo(..), workflowActionInfos
|
||||||
, WorkflowAction(..), _wpTo, _wpVia, _wpPayload, _wpUser, _wpTime
|
, WorkflowAction(..), _wpTo, _wpVia, _wpPayload, _wpUser, _wpTime
|
||||||
, WorkflowFieldPayloadW(..), _WorkflowFieldPayloadW, IsWorkflowFieldPayload', IsWorkflowFieldPayload
|
, WorkflowFieldPayloadW(..), _WorkflowFieldPayloadW, IsWorkflowFieldPayload', IsWorkflowFieldPayload
|
||||||
|
, workflowPayloadSort
|
||||||
, WorkflowFieldPayload(..), _WorkflowFieldPayload
|
, WorkflowFieldPayload(..), _WorkflowFieldPayload
|
||||||
, workflowStatePayload, workflowStateCurrentPayloads
|
, workflowStatePayload, workflowStateCurrentPayloads
|
||||||
, WorkflowChildren
|
, WorkflowChildren
|
||||||
@ -59,6 +61,10 @@ import Unsafe.Coerce
|
|||||||
|
|
||||||
import Utils.Lens.TH
|
import Utils.Lens.TH
|
||||||
|
|
||||||
|
import Data.List (inits)
|
||||||
|
|
||||||
|
import Data.RFC5051 (compareUnicode)
|
||||||
|
|
||||||
|
|
||||||
----- WORKFLOW GRAPH -----
|
----- WORKFLOW GRAPH -----
|
||||||
|
|
||||||
@ -364,6 +370,23 @@ data WorkflowAction fileid userid = WorkflowAction
|
|||||||
}
|
}
|
||||||
deriving (Eq, Ord, Show, Generic, Typeable)
|
deriving (Eq, Ord, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
data WorkflowActionInfo fileid userid = WorkflowActionInfo
|
||||||
|
{ waiIx :: WorkflowStateIndex
|
||||||
|
, waiFrom :: Maybe WorkflowGraphNodeLabel
|
||||||
|
, waiHistory :: [WorkflowAction fileid userid]
|
||||||
|
, waiAction :: WorkflowAction fileid userid
|
||||||
|
} deriving (Eq, Ord, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
workflowActionInfos :: WorkflowState fileid userid -> [WorkflowActionInfo fileid userid]
|
||||||
|
workflowActionInfos wState
|
||||||
|
= [ WorkflowActionInfo{..}
|
||||||
|
| waiFrom <- Nothing : map (Just . wpTo) wState'
|
||||||
|
| waiAction <- wState'
|
||||||
|
| waiIx <- [minBound..]
|
||||||
|
| waiHistory <- tailEx $ inits wState'
|
||||||
|
]
|
||||||
|
where wState' = otoList wState
|
||||||
|
|
||||||
data WorkflowFieldPayloadW fileid userid = forall payload. IsWorkflowFieldPayload' fileid userid payload => WorkflowFieldPayloadW (WorkflowFieldPayload fileid userid payload)
|
data WorkflowFieldPayloadW fileid userid = forall payload. IsWorkflowFieldPayload' fileid userid payload => WorkflowFieldPayloadW (WorkflowFieldPayload fileid userid payload)
|
||||||
deriving (Typeable)
|
deriving (Typeable)
|
||||||
|
|
||||||
@ -395,6 +418,35 @@ instance (Ord fileid, Ord userid, Typeable fileid, Typeable userid) => Ord (Work
|
|||||||
(WFPFile{}, _) -> LT
|
(WFPFile{}, _) -> LT
|
||||||
(WFPUser{}, _) -> GT
|
(WFPUser{}, _) -> GT
|
||||||
|
|
||||||
|
workflowPayloadSort
|
||||||
|
:: forall fileid userid.
|
||||||
|
(fileid -> fileid -> Ordering)
|
||||||
|
-> (userid -> userid -> Ordering)
|
||||||
|
-> (WorkflowFieldPayloadW fileid userid -> WorkflowFieldPayloadW fileid userid -> Ordering)
|
||||||
|
workflowPayloadSort ordFiles ordUsers (WorkflowFieldPayloadW a) (WorkflowFieldPayloadW b) = case (a, b) of
|
||||||
|
(WFPText a', WFPText b' ) -> compareUnicode a' b'
|
||||||
|
(WFPText{}, _ ) -> LT
|
||||||
|
(WFPNumber a', WFPNumber b') -> compare a' b'
|
||||||
|
(WFPNumber{}, WFPText{} ) -> GT
|
||||||
|
(WFPNumber{}, _ ) -> LT
|
||||||
|
(WFPBool a', WFPBool b' ) -> compare a' b'
|
||||||
|
(WFPBool{}, WFPText{} ) -> GT
|
||||||
|
(WFPBool{}, WFPNumber{} ) -> GT
|
||||||
|
(WFPBool{}, _ ) -> LT
|
||||||
|
(WFPDay a', WFPDay b' ) -> compare a' b'
|
||||||
|
(WFPDay{}, WFPText{} ) -> GT
|
||||||
|
(WFPDay{}, WFPNumber{} ) -> GT
|
||||||
|
(WFPDay{}, WFPBool{} ) -> GT
|
||||||
|
(WFPDay{}, _ ) -> LT
|
||||||
|
(WFPFile a', WFPFile b' ) -> ordFiles a' b'
|
||||||
|
(WFPFile{}, WFPText{} ) -> GT
|
||||||
|
(WFPFile{}, WFPNumber{} ) -> GT
|
||||||
|
(WFPFile{}, WFPBool{} ) -> GT
|
||||||
|
(WFPFile{}, WFPDay{} ) -> GT
|
||||||
|
(WFPFile{}, _ ) -> LT
|
||||||
|
(WFPUser a', WFPUser b' ) -> ordUsers a' b'
|
||||||
|
(WFPUser{}, _ ) -> GT
|
||||||
|
|
||||||
instance (Show fileid, Show userid) => Show (WorkflowFieldPayloadW fileid userid) where
|
instance (Show fileid, Show userid) => Show (WorkflowFieldPayloadW fileid userid) where
|
||||||
show (WorkflowFieldPayloadW payload) = show payload
|
show (WorkflowFieldPayloadW payload) = show payload
|
||||||
|
|
||||||
|
|||||||
18
src/Utils.hs
18
src/Utils.hs
@ -17,6 +17,7 @@ import Data.CaseInsensitive (CI)
|
|||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Char8 as CBS
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
import qualified Data.Text.Encoding as Text
|
import qualified Data.Text.Encoding as Text
|
||||||
|
|
||||||
@ -222,7 +223,22 @@ delimitInternalState act = bracket createInternalState closeInternalState $ \new
|
|||||||
= HandlerData { handlerResource = newInternalState
|
= HandlerData { handlerResource = newInternalState
|
||||||
, ..
|
, ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectRep' :: [(ContentType, a)] -> ContentType -> Maybe a
|
||||||
|
selectRep' cMap _ | null cMap = Nothing
|
||||||
|
selectRep' cMap' needle = asum
|
||||||
|
[ guardOnM (needleMain == "*" && needleSub == "*") $ preview (folded . _2) cMap'
|
||||||
|
, guardOnM (needleSub == "*") $ preview (folded . filtered (views _1 $ views _1 (== needleMain) . contentTypeTypes) . _2) cMap'
|
||||||
|
, Map.lookup needle cMap
|
||||||
|
, Map.lookup (noSpaces needle) cMap
|
||||||
|
, Map.lookup (simpleContentType needle) cMap
|
||||||
|
]
|
||||||
|
where
|
||||||
|
cMap = Map.fromListWith const $ over _1 <$> [id, noSpaces, simpleContentType] <*> cMap'
|
||||||
|
|
||||||
|
(needleMain, needleSub) = contentTypeTypes needle
|
||||||
|
|
||||||
|
noSpaces = CBS.filter (/= ' ')
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
-- Text and String --
|
-- Text and String --
|
||||||
|
|||||||
@ -14,11 +14,12 @@ import Settings.Mime
|
|||||||
|
|
||||||
import Data.Csv hiding (Name)
|
import Data.Csv hiding (Name)
|
||||||
import Data.Csv.Conduit (CsvParseError)
|
import Data.Csv.Conduit (CsvParseError)
|
||||||
|
import qualified Data.Csv.Incremental as Incremental
|
||||||
|
|
||||||
import Language.Haskell.TH (Name)
|
import Language.Haskell.TH (Name)
|
||||||
import Language.Haskell.TH.Lib
|
import Language.Haskell.TH.Lib
|
||||||
|
|
||||||
import Yesod.Core.Content (ContentType, simpleContentType)
|
import Yesod.Core.Content
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
@ -54,6 +55,17 @@ data CsvRendered = CsvRendered
|
|||||||
, csvRenderedData :: [NamedRecord]
|
, csvRenderedData :: [NamedRecord]
|
||||||
} deriving (Eq, Read, Show, Generic, Typeable)
|
} deriving (Eq, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
instance ToContent CsvRendered where
|
||||||
|
toContent CsvRendered{..} = toContent . Incremental.encodeByName csvRenderedHeader $ foldr ((<>) . Incremental.encodeNamedRecord) mempty csvRenderedData
|
||||||
|
|
||||||
|
instance ToTypedContent CsvRendered where
|
||||||
|
toTypedContent = TypedContent
|
||||||
|
<$> getContentType . Identity
|
||||||
|
<*> toContent
|
||||||
|
|
||||||
|
instance HasContentType CsvRendered where
|
||||||
|
getContentType _ = typeCsv'
|
||||||
|
|
||||||
toCsvRendered :: forall mono.
|
toCsvRendered :: forall mono.
|
||||||
( ToNamedRecord (Element mono)
|
( ToNamedRecord (Element mono)
|
||||||
, MonoFoldable mono
|
, MonoFoldable mono
|
||||||
|
|||||||
@ -31,6 +31,7 @@ data GlobalGetParam = GetLang
|
|||||||
| GetDryRun
|
| GetDryRun
|
||||||
| GetDownload
|
| GetDownload
|
||||||
| GetError
|
| GetError
|
||||||
|
| GetSelectTable
|
||||||
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)
|
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)
|
||||||
deriving anyclass (Universe, Finite)
|
deriving anyclass (Universe, Finite)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user