From 0a3eaa29946ba00ba0c9597d124f4ca5cc25620d Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 25 Nov 2020 15:00:16 +0100 Subject: [PATCH] fix(workflows): cleanup --- messages/uniworx/en-eu.msg | 127 ++ src/Handler/Utils/Workflow/EdgeForm.hs | 17 +- src/Handler/Utils/Workflow/Form.hs | 6 +- src/Handler/Workflow/Workflow/Workflow.hs | 6 +- src/Model/Types/File.hs | 2 +- src/Model/Types/TH/JSON.hs | 5 +- src/Model/Types/Workflow.hs | 44 +- src/Utils/I18n.hs | 3 + src/Utils/Workflow.hs | 2 - src/Utils/Workflow/Lint.hs | 3 + test/Database/Fill.hs | 36 + testdata/recognitions.yaml | 739 ++++++++++++ testdata/theses.yaml | 1276 +++++++++++---------- 13 files changed, 1605 insertions(+), 661 deletions(-) create mode 100644 testdata/recognitions.yaml diff --git a/messages/uniworx/en-eu.msg b/messages/uniworx/en-eu.msg index 63fcf266b..59a888709 100644 --- a/messages/uniworx/en-eu.msg +++ b/messages/uniworx/en-eu.msg @@ -537,6 +537,17 @@ UnauthorizedPasswordResetToken: This authorisation-token may no longer be used t UnauthorizedAllocatedCourseRegister: Direct enrollment to this course is currently not allowed due to participation in a central allocation UnauthorizedAllocatedCourseDeregister: Deregistration from this course is currently not allowed due to participation in a central allocation UnauthorizedAllocatedCourseDelete: Courses that participate in a central allocation may not be deleted +UnauthorizedWorkflowInitiate: You currently may not initiate a new running workflow +UnauthorizedWorkflowWrite: You are currently not allowed to initiate any state transition within the workflow +UnauthorizedWorkflowRead: The workflow currently contains no states or data you are permitted to view +UnauthorizedWorkflowInstancesNotEmpty: There are workflow instances for which you are allowed to initiate a new running workflow +UnauthorizedWorkflowWorkflowsNotEmpty: There are running workflows, which you may view +UnauthorizedWorkflowFiles: You are not allowed to download the given workflow files in the given historical state + +WorkflowRoleUserMismatch: You aren't any of the users authorized by the workflow +WorkflowRoleAlreadyInitiated: This workflow was already initiated +WorkflowRoleNoSuchWorkflowWorkflow: The given workflow could not be found +WorkflowRoleNoPayload: This workflow does not contain any data EMail: Email EMailUnknown email: Email #{email} does not belong to any known user. @@ -1410,6 +1421,20 @@ MenuAdminCrontab: Crontab MenuAdminWorkflowDefinitionList: Workflows MenuAdminWorkflowDefinitionNew: New workflow definition MenuAdminWorkflowDefinitionDelete: Delete +MenuAdminWorkflowInstanceList: Workflow instances +MenuAdminWorkflowInstanceNew: New workflow instance +MenuAdminWorkflowDefinitionInstantiate: Instantiate +MenuWorkflowInstanceDelete: Delete +MenuWorkflowInstanceWorkflows: Running workflows +MenuWorkflowInstanceInitiate: Start workflow +MenuWorkflowInstanceEdit: Edit +MenuWorkflowWorkflowList: Running workflows +MenuWorkflowWorkflowEdit: Edit +MenuWorkflowWorkflowDelete: Delete +MenuGlobalWorkflowInstanceList: System-wide workflows +MenuTopWorkflowInstanceList: Workflows +MenuTopWorkflowWorkflowList: Running workflows +MenuTopWorkflowWorkflowListHeader: Workflows BreadcrumbSubmissionFile: File BreadcrumbSubmissionUserInvite: Invitation to participate in a submission @@ -1491,6 +1516,25 @@ BreadcrumbAdminWorkflowDefinitionList: Workflow definitions BreadcrumbAdminWorkflowDefinitionNew: New workflow definition BreadcrumbAdminWorkflowDefinitionEdit renderedWorkflowScope' wfdn: #{wfdn} (#{renderedWorkflowScope'}) BreadcrumbAdminWorkflowDefinitionDelete: Delete +BreadcrumbAdminWorkflowDefinitionInstantiate: Instantiate +BreadcrumbAdminWorkflowInstanceList: Workflow instances +BreadcrumbAdminWorkflowInstanceNew: New workflow-instance +BreadcrumbAdminWorkflowWorkflowList: Initiated workflows +BreadcrumbAdminWorkflowWorkflowNew: Initiate workflow +BreadcrumbWorkflowInstanceEdit win: #{win} +BreadcrumbWorkflowInstanceDelete: Delete +BreadcrumbWorkflowInstanceWorkflowList: Running workflows +BreadcrumbWorkflowInstanceInitiate: Start workflow +BreadcrumbWorkflowInstanceList: Workflows +BreadcrumbWorkflowInstanceNew: New workflow +BreadcrumbWorkflowWorkflowList: Running workflows +BreadcrumbWorkflowWorkflow workflow: #{toPathPiece workflow} +BreadcrumbWorkflowWorkflowFiles: Files +BreadcrumbWorkflowWorkflowEdit: Edit +BreadcrumbWorkflowWorkflowDelete: Delete +BreadcrumbGlobalWorkflowInstanceList: System-wide workflows +BreadcrumbTopWorkflowInstanceList: Workflows +BreadcrumbTopWorkflowWorkflowList: Running workflows ExternalExamEdit coursen examn: Edit: #{coursen}, #{examn} ExternalExamGrades coursen examn: Exam achievements: #{coursen}, #{examn} @@ -1546,6 +1590,7 @@ AuthTagAuthentication: User is authenticated AuthTagRead: Access is read only AuthTagWrite: Access might write AuthTagSubmissionGroup: User is part of a submission group +AuthTagWorkflow: User has matching workflow role DeleteCopyStringIfSure n: If you are sure that you want to permanently delete the #{pluralEN n "object" "objects"} listed below, please copy the shown text. DeletePressButtonIfSure n: If you are sure that you want to permanently delete the #{pluralEN n "object" "objects"} listed below, please confirm the action by pressing the button. @@ -2942,15 +2987,78 @@ WorkflowScopeKindTerm: Per term WorkflowScopeKindSchool: Per school WorkflowScopeKindTermSchool: Per school & term WorkflowScopeKindCourse: Per course +WorkflowScopeGlobal: System-wide +WorkflowScopeTermSchool tid ssh: #{tid} #{ssh} +WorkflowScopeCourse tid ssh csh: #{tid} #{ssh} #{csh} WorkflowDefinitionScope: Scope WorkflowDefinitionName: Name +WorkflowDefinitionDescriptions: Description +WorkflowDefinitionDescriptionsLanguageExists: A description in this language already exists WorkflowDescriptionLanguage: Language code (RFC1766) WorkflowDescriptionTitle: Title WorkflowDescription: Description + +GlobalWorkflowInstancesHeading: Workflows (system-wide) +GlobalWorkflowInstancesTitle: Workflows (system-wide) + +GlobalWorkflowInstanceInitiateHeading workflowInstanceTitle: Initiate workflow: #{workflowInstanceTitle} +GlobalWorkflowInstanceInitiateTitle: Initiate workflow + +SchoolWorkflowInstancesHeading ssh: Workflows (#{ssh}) +SchoolWorkflowInstancesTitle ssh: Workflows (#{ssh}) + +SchoolWorkflowInstanceInitiateHeading ssh workflowInstanceTitle: Initiate workflow: #{ssh}, #{workflowInstanceTitle} +SchoolWorkflowInstanceInitiateTitle ssh: Initiate workflow: #{ssh} + +WorkflowEdgeNumberedVariant edgeLabel i: #{edgeLabel} (variant #{i}) +WorkflowEdgeFormEdge: Action +WorkflowEdgeFormHiddenPayload i: Hidden dataset #{i} +WorkflowEdgeFormPayloadOneFieldRequired: At least one field per dataset needs to be filled +WorkflowEdgeFormPayloadOneFieldRequiredFor payloadDisplayLabel: At least one field for “#{payloadDisplayLabel}” needs to be filled +WorkflowEdgeFormFieldNumberTooSmall minSci: Number must be at least #{formatScientific Scientific.Generic Nothing minSci} +WorkflowEdgeFormFieldNumberTooLarge maxSci: Number must be at most #{formatScientific Scientific.Generic Nothing maxSci} +WorkflowEdgeFormFieldUserNotFound: Email could not be resolved to an user +WorkflowEdgeFormFieldMultipleNoneAdded: No entries (yet) +WorkflowEdgeFormFieldCaptureUserLabel: Current user + +WorkflowWorkflowWorkflowHistoryHeading: History +WorkflowWorkflowWorkflowEdgeFormHeading: Trigger action within workflow +WorkflowWorkflowWorkflowEdgeSuccess: Successfully triggered action +WorkflowWorkflowWorkflowHistoryUserSelf: You +WorkflowWorkflowWorkflowHistoryUserNotLoggedIn: Not-logged in user +WorkflowWorkflowWorkflowHistoryUserGone: Deleted user +WorkflowWorkflowWorkflowHistoryUserHidden: Hidden user +WorkflowWorkflowWorkflowHistoryUserAutomatic: Automatic +WorkflowWorkflowWorkflowHistoryActionAutomatic: Automatic +WorkflowWorkflowWorkflowHistoryStateHidden: Hidden state +WorkflowWorkflowWorkflowHistoryActionLabel: Action +WorkflowWorkflowWorkflowHistoryFromLabel: Previous state +WorkflowWorkflowWorkflowHistoryToLabel: New state +WorkflowWorkflowWorkflowHistoryPayloadLabel: Data changes +WorkflowWorkflowFilesArchiveName wwCID wpl stCID: #{foldCase (toPathPiece wwCID)}-#{foldCase (toPathPiece stCID)}-#{foldCase (foldMap unidecode (toPathPiece wpl))}.zip +WorkflowWorkflowWorkflowStateHeading: State/Data +WorkflowWorkflowWorkflowPayloadHeading: Current data +WorkflowWorkflowWorkflowStateStateLabel: Current state +WorkflowWorkflowWorkflowStateStateHidden: Hidden state + +WorkflowPayloadFiles: File(s) +WorkflowPayloadBoolTrue: Yes +WorkflowPayloadBoolFalse: No +WorkflowPayloadUserGone: Deleted user + +TopWorkflowInstancesHeading: Workflows +TopWorkflowInstancesTitle: Workflows + +GlobalWorkflowWorkflowWorkflowHeading workflowWorkflowId: Workflow #{toPathPiece workflowWorkflowId} +GlobalWorkflowWorkflowWorkflowTitle workflowWorkflowId: Workflow #{toPathPiece workflowWorkflowId} + +SchoolWorkflowWorkflowWorkflowHeading ssh workflowWorkflowId: Workflow #{ssh}, #{toPathPiece workflowWorkflowId} +SchoolWorkflowWorkflowWorkflowTitle ssh workflowWorkflowId: Workflow #{ssh}, #{toPathPiece workflowWorkflowId} WorkflowDefinitionGraph: Specification WorkflowDefinitionKeyDoesNotExist renderedCryptoID: Referenced id does not exist: #{renderedCryptoID} WorkflowDefinitionFiles: Files WorkflowFileIdentDoesNotExist fileIdent: Referenced file does not exist: #{fileIdent} +WorkflowUserDoesNotExist userIdent: Referenced user does not exist: #{userIdent} WorkflowDefinitionFileIdentExists: A file with the given reference id already exists WorkflowDefinitionFileIdent: File reference id WorkflowDefinitionFile: File @@ -2959,6 +3067,9 @@ WorkflowDefinitionEdited: Successfully replaced workflow definition WorkflowDefinitionCollision: A workflow definition with this name already exists WorkflowDefinitionNewTitle: Create new workflow definition WorkflowDefinitionEditTitle: Edit workflow definition +WorkflowDefinitionInstanceCategory: Category +WorkflowDefinitionWarningLinterIssuesMessage: There were linter issues +WorkflowDefinitionWarningLinterIssues: There are the following linter issues: WorkflowDefinitionListTitle: Workflow definitions WorkflowDefinitionInstanceCount: Instances @@ -2967,6 +3078,22 @@ WorkflowDefinitionConcreteInstanceCount num: #{num} instances WorkflowDefinitionConcreteWorkflowCount num: #{num} workflows WorkflowDefinitionDeleteQuestion: Do you really want to delete the workflow definition listed below? WorkflowDefinitionDeleted: Successfully deleted workflow definition +WorkflowDefinitionInstantiateTitle: Instantiate workflow definition +WorkflowDefinitionInstantiated: Instance created + +WorkflowScope: Scope +WorkflowInstanceName: Name +WorkflowInstanceCategory: Category +WorkflowInstanceCollision: There already exists a workflow instance with the given name and category +WorkflowInstanceListTitle: Workflow instances +WorkflowInstanceDescription: Instance description +WorkflowInstanceDescriptions: Instance description +WorkflowInstanceDescriptionsLanguageExists: A instance description in the given language already exists +WorkflowInstanceCreated: Instance created +WorkflowInstanceDescriptionTitle: Instance title +WorkflowInstanceWorkflowCount: Workflows + +WorkflowInstanceInitiateSuccess: Successfully initiated workflow ChangelogItemFeature: Feature ChangelogItemBugfix: Bugfix diff --git a/src/Handler/Utils/Workflow/EdgeForm.hs b/src/Handler/Utils/Workflow/EdgeForm.hs index a5bdaa33e..a0466f725 100644 --- a/src/Handler/Utils/Workflow/EdgeForm.hs +++ b/src/Handler/Utils/Workflow/EdgeForm.hs @@ -54,6 +54,9 @@ import qualified Text.Blaze as Blaze import qualified Text.Blaze.Renderer.Text as Blaze +{-# ANN module ("HLint: ignore Use newtype instead of data"::String) #-} + + data WorkflowEdgeForm = WorkflowEdgeForm { wefEdge :: (WorkflowGraphNodeLabel, WorkflowGraphEdgeLabel) , wefPayload :: Map WorkflowPayloadLabel (Set (WorkflowFieldPayloadW FileReference UserId)) @@ -256,7 +259,7 @@ workflowEdgePayloadFields specs = evalRWST (forM specs $ runExceptT . renderSpec -> Field Handler payload' -> FieldSettings UniWorX -> Maybe payload' - -> _ ((Bool, FormResult (Maybe (NonEmpty (WorkflowFieldPayloadW FileReference UserId))))) + -> _ (Bool, FormResult (Maybe (NonEmpty (WorkflowFieldPayloadW FileReference UserId)))) f' toNonEmpty' isOpt fld fs mx = lift . (<* tell (All isOpt)) . lift $ over (_2 . mapped) (fmap (fmap . review $ _WorkflowFieldPayloadW . _WorkflowFieldPayload) . toNonEmpty' =<<) . bool (is (_FormSuccess . _Just) &&& id) (True, ) isOpt <$> wopt fld fs (Just <$> mx) f :: forall payload'. _ @@ -264,7 +267,7 @@ workflowEdgePayloadFields specs = evalRWST (forM specs $ runExceptT . renderSpec -> Field Handler payload' -> FieldSettings UniWorX -> Maybe payload' - -> _ ((Bool, FormResult (Maybe (NonEmpty (WorkflowFieldPayloadW FileReference UserId))))) + -> _ (Bool, FormResult (Maybe (NonEmpty (WorkflowFieldPayloadW FileReference UserId)))) f = f' (nonEmpty . pure) extractPrevs :: forall payload' m xs. ( IsWorkflowFieldPayload' FileReference UserId payload' @@ -314,9 +317,9 @@ workflowEdgePayloadFields specs = evalRWST (forM specs $ runExceptT . renderSpec ) ( fsl (slI18n wpfnLabel) & maybe id (addPlaceholder . slI18n) wpfnPlaceholder - & maybe id (\wpfnMin' -> addAttr "min" . tshow $ formatScientific Scientific.Fixed Nothing wpfnMin') wpfnMin - & maybe id (\wpfnMax' -> addAttr "max" . tshow $ formatScientific Scientific.Fixed Nothing wpfnMax') wpfnMax - & maybe (addAttr "step" "any") (\wpfnStep' -> addAttr "step" . tshow $ formatScientific Scientific.Fixed Nothing wpfnStep') wpfnStep + & maybe id (addAttr "min" . tshow . formatScientific Scientific.Fixed Nothing) wpfnMin + & maybe id (addAttr "max" . tshow . formatScientific Scientific.Fixed Nothing) wpfnMax + & maybe (addAttr "step" "any") (addAttr "step" . tshow . formatScientific Scientific.Fixed Nothing) wpfnStep & maybe id (addName . ($ "number")) mNudge ) (prev <|> wpfnDefault) @@ -423,11 +426,11 @@ workflowEdgePayloadFields specs = evalRWST (forM specs $ runExceptT . renderSpec -> (Text -> Text) -> FieldView UniWorX -> Maybe (Html -> MForm (ExceptT WorkflowPayloadLabel Handler) (FormResult (Map ListPosition (Maybe (WorkflowFieldPayloadW FileReference UserId)) -> FormResult (Map ListPosition (Maybe (WorkflowFieldPayloadW FileReference UserId)))), Widget)) - miAdd _pos _dim nudge submitView = Just $ \csrf -> over (_1 . _FormSuccess) tweakRes <$> miForm nudge (Left submitView) csrf + miAdd _pos _dim nudge submitView = Just $ over (mapped . _1 . _FormSuccess) tweakRes . miForm nudge (Left submitView) where tweakRes :: Maybe (NonEmpty (WorkflowFieldPayloadW FileReference UserId)) -> Map ListPosition (Maybe (WorkflowFieldPayloadW FileReference UserId)) -> FormResult (Map ListPosition (Maybe (WorkflowFieldPayloadW FileReference UserId))) - tweakRes newDat prevData = Map.fromList . zip [startKey..] <$> pure (map Just $ newDat ^.. _Just . folded) + tweakRes newDat prevData = pure . Map.fromList . zip [startKey..] . map Just $ newDat ^.. _Just . folded where startKey = maybe 0 succ $ fst <$> Map.lookupMax prevData miCell :: ListPosition diff --git a/src/Handler/Utils/Workflow/Form.hs b/src/Handler/Utils/Workflow/Form.hs index feeceeb94..e88fa82f5 100644 --- a/src/Handler/Utils/Workflow/Form.hs +++ b/src/Handler/Utils/Workflow/Form.hs @@ -113,7 +113,7 @@ workflowGraphForm template = validateAForm validateWorkflowGraphForm . hoistAFor fileForm :: (Text -> Text) -> Maybe (FileIdent, FileReference) -> Form (FileIdent, FileReference) fileForm nudge fileTemplate csrf = do (fileIdentRes, fileIdentView) <- mpreq (isoField _Unwrapped ciField) (fslI MsgWorkflowDefinitionFileIdent & addName (nudge "ident")) (view _1 <$> fileTemplate) - (fileRes, fileView) <- mpreq (singleFileField . fromMaybe (return ()) $ views _2 yield <$> fileTemplate) (fslI MsgWorkflowDefinitionFile & addName (nudge "file")) (views _2 yield <$> fileTemplate) + (fileRes, fileView) <- mpreq (singleFileField $ maybe (return ()) (views _2 yield) fileTemplate) (fslI MsgWorkflowDefinitionFile & addName (nudge "file")) (views _2 yield <$> fileTemplate) fileRes' <- liftHandler . runDB $ case fileRes of FormSuccess uploads -> maybe FormMissing FormSuccess <$> runConduit (transPipe liftHandler uploads .| C.head) FormFailure errs -> return $ FormFailure errs @@ -155,8 +155,8 @@ toWorkflowGraphForm g = liftHandler . fmap (uncurry WorkflowGraphForm . over _2 Just fIdent -> return fIdent Nothing -> do cMap <- State.get - let candidateIdents = map (review _Wrapped . CI.mk) $ - map pack $ fileReferenceTitle : [ base <.> show n <.> ext | n <- [1..] :: [Natural], let (base, ext) = splitExtension fileReferenceTitle ] + let candidateIdents = map (review _Wrapped . CI.mk . pack) $ + fileReferenceTitle : [ base <.> show n <.> ext | let (base, ext) = splitExtension fileReferenceTitle, n <- [1..] :: [Natural] ] fIdent = case filter (`Bimap.notMember` cMap) candidateIdents of fIdent' : _ -> fIdent' [] -> error "candidateIdents should be infinite; cMap should be finite" diff --git a/src/Handler/Workflow/Workflow/Workflow.hs b/src/Handler/Workflow/Workflow/Workflow.hs index c8da74226..08f2f211b 100644 --- a/src/Handler/Workflow/Workflow/Workflow.hs +++ b/src/Handler/Workflow/Workflow/Workflow.hs @@ -116,7 +116,7 @@ workflowR wwId = do mAuthId <- maybeAuthId guardM . lift . lift . hoist liftHandler $ mayViewWorkflowAction mAuthId wwId act - stCID <- encrypt stIx + stCID <- encryptWorkflowStateIndex wwId stIx let nodeView nodeLbl = do WorkflowNodeView{..} <- hoistMaybe $ Map.lookup nodeLbl wgNodes >>= wgnViewers guardM $ anyM (otoList wnvViewers) hasWorkflowRole' @@ -182,7 +182,7 @@ workflowR wwId = do <> (compareUnicode `on` userDisplayName) uA uB <> comparing userIdent uA uB (WFPUser{}, _ ) -> GT - flip mapM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort) . over _2 (bool Nothing (Just fRoute). getAny)) . execWriterT . flip mapM_ payloads $ \case + forM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort) . over _2 (bool Nothing (Just fRoute). getAny)) . execWriterT . 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) @@ -262,7 +262,7 @@ getWorkflowFilesR :: WorkflowWorkflowId -> WorkflowPayloadLabel -> CryptoUUIDWor getWorkflowFilesR wwId wpl stCID = do fRefs <- runDB $ do WorkflowWorkflow{..} <- get404 wwId - stIx <- decrypt stCID + stIx <- decryptWorkflowStateIndex wwId stCID payloads <- maybeT notFound . workflowStateSection stIx $ _DBWorkflowState # workflowWorkflowState mAuthId <- maybeAuthId payloads' <- fmap (Map.findWithDefault Set.empty wpl . workflowStateCurrentPayloads) . filterM (mayViewWorkflowAction mAuthId wwId) $ otoList payloads diff --git a/src/Model/Types/File.hs b/src/Model/Types/File.hs index 98964171f..5beb0ef55 100644 --- a/src/Model/Types/File.hs +++ b/src/Model/Types/File.hs @@ -247,7 +247,7 @@ class FileReferenceTitleMapConvertible add f1 f2 where _FileReferenceTitleMap :: Traversal (FileReferenceTitleMap f1 add) (FileReferenceTitleMap f2 add) (f1, add) (f2, add) instance FileReferenceTitleMapConvertible add FileReference FileReference where - _FileReferenceTitleMap = iso unFileReferenceFileReferenceTitleMap FileReferenceFileReferenceTitleMap . iso (map (\(fileReferenceTitle, (FileReferenceFileReferenceTitleMapElem fileReferenceContent fileReferenceModified additional)) -> (FileReference{..}, additional)) . Map.toList) (Map.fromList . map (\(FileReference{..}, additional) -> (fileReferenceTitle, FileReferenceFileReferenceTitleMapElem fileReferenceContent fileReferenceModified additional))) . traverse + _FileReferenceTitleMap = iso unFileReferenceFileReferenceTitleMap FileReferenceFileReferenceTitleMap . iso (map (\(fileReferenceTitle, FileReferenceFileReferenceTitleMapElem fileReferenceContent fileReferenceModified additional) -> (FileReference{..}, additional)) . Map.toList) (Map.fromList . map (\(FileReference{..}, additional) -> (fileReferenceTitle, FileReferenceFileReferenceTitleMapElem fileReferenceContent fileReferenceModified additional))) . traverse data FileFieldUserOption a = FileFieldUserOption diff --git a/src/Model/Types/TH/JSON.hs b/src/Model/Types/TH/JSON.hs index 84b7b6282..b50100d22 100644 --- a/src/Model/Types/TH/JSON.hs +++ b/src/Model/Types/TH/JSON.hs @@ -68,10 +68,7 @@ predNFAesonOptions = defaultOptions } -workflowGraphAesonOptions, workflowGraphEdgeAesonOptions, workflowGraphNodeAesonOptions, workflowActionAesonOptions, workflowPayloadViewAesonOptions, workflowNodeViewAesonOptions, workflowNodeMessageAesonOptions :: Options -workflowGraphAesonOptions = defaultOptions - { fieldLabelModifier = camelToPathPiece' 1 - } +workflowGraphEdgeAesonOptions, workflowGraphNodeAesonOptions, workflowActionAesonOptions, workflowPayloadViewAesonOptions, workflowNodeViewAesonOptions, workflowNodeMessageAesonOptions :: Options workflowGraphEdgeAesonOptions = defaultOptions { constructorTagModifier = camelToPathPiece' 3 , fieldLabelModifier = camelToPathPiece' 1 diff --git a/src/Model/Types/Workflow.hs b/src/Model/Types/Workflow.hs index 538184a1d..7b77a213b 100644 --- a/src/Model/Types/Workflow.hs +++ b/src/Model/Types/Workflow.hs @@ -61,7 +61,7 @@ import Utils.Lens.TH ----- WORKFLOW GRAPH ----- -data WorkflowGraph fileid userid = WorkflowGraph +newtype WorkflowGraph fileid userid = WorkflowGraph { wgNodes :: Map WorkflowGraphNodeLabel (WorkflowGraphNode fileid userid) } deriving (Generic, Typeable) @@ -342,7 +342,7 @@ workflowStateSection :: MonadPlus m => WorkflowStateIndex -> WorkflowState fileid userid -> m (WorkflowState fileid userid) -workflowStateSection i wSt = maybe mzero return . fromNullable . Seq.fromList =<< sequenceA (map (flip workflowStateIndex wSt) [0..i]) +workflowStateSection i wSt = maybe mzero return . fromNullable . Seq.fromList =<< traverse (`workflowStateIndex` wSt) [0..i] data WorkflowAction fileid userid = WorkflowAction { wpTo :: WorkflowGraphNodeLabel @@ -628,14 +628,14 @@ instance (FromJSON userid, Ord userid) => FromJSON (WorkflowPayloadView userid) parseJSON = genericParseJSON workflowPayloadViewAesonOptions instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (WorkflowGraph fileid userid) where - toJSON = genericToJSON workflowGraphAesonOptions + toJSON = toJSON . wgNodes instance ( FromJSON fileid, FromJSON userid , Ord fileid, Ord userid , Typeable fileid, Typeable userid , FromJSON (FileField fileid) , Ord (FileField fileid) ) => FromJSON (WorkflowGraph fileid userid) where - parseJSON = genericParseJSON workflowGraphAesonOptions + parseJSON = fmap WorkflowGraph . parseJSON instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (WorkflowGraphEdge fileid userid) where toJSON = genericToJSON workflowGraphEdgeAesonOptions @@ -652,11 +652,10 @@ instance ToJSON WorkflowGraphEdgeFormOrder where Nothing -> JSON.String "_" Just sci -> JSON.Number sci instance FromJSON WorkflowGraphEdgeFormOrder where - parseJSON v = fmap WorkflowGraphEdgeFormOrder $ asum - [ Just <$> parseJSON v - , flip (JSON.withText "WorkflowGraphEdgeFormOrder") v $ \t -> maybe (fail "WorkflowGraphEdgeFormOrder: could not parse String as Number") (return . Just) $ readMay t - , flip (JSON.withText "WorkflowGraphEdgeFormOrder") v $ bool (fail "WorkflowGraphEdgeFormOrder: unexpected String, expecting either number or \"_\"") (pure Nothing) . (== "_") - ] + parseJSON v = fmap WorkflowGraphEdgeFormOrder $ + Just <$> parseJSON v + <|> JSON.withText "WorkflowGraphEdgeFormOrder" (maybe (fail "WorkflowGraphEdgeFormOrder: could not parse String as Number") (return . Just) . readMay) v + <|> JSON.withText "WorkflowGraphEdgeFormOrder" (bool (fail "WorkflowGraphEdgeFormOrder: unexpected String, expecting either number or \"_\"") (pure Nothing) . (== "_")) v instance ToJSONKey WorkflowGraphEdgeFormOrder where toJSONKey = JSON.ToJSONKeyText (maybe "_" toText' . unWorkflowGraphEdgeFormOrder) (maybe (JSON.text "_") toEncoding' . unWorkflowGraphEdgeFormOrder) @@ -678,17 +677,16 @@ instance ( FromJSON fileid, FromJSON userid , FromJSON (FileField fileid), Ord (FileField fileid) ) => FromJSON (WorkflowGraphEdgeForm fileid userid) where parseJSON = JSON.withObject "WorkflowGraphEdgeForm" $ \o -> do - o' <- parseJSON $ JSON.Object o :: JSON.Parser (Map WorkflowPayloadLabel (NonNull (Set (JSON.Value)))) - fmap WorkflowGraphEdgeForm . for o' $ \(Set.toList . toNullable -> o'') -> fmap (impureNonNull . Set.fromList) . for o'' $ \o''' -> asum - [ parseJSON o''' - , impureNonNull . Map.singleton (WorkflowGraphEdgeFormOrder Nothing) <$> parseJSON o''' - ] + o' <- parseJSON $ JSON.Object o :: JSON.Parser (Map WorkflowPayloadLabel (NonNull (Set JSON.Value))) + fmap WorkflowGraphEdgeForm . for o' $ \(Set.toList . toNullable -> o'') -> fmap (impureNonNull . Set.fromList) . for o'' $ \o''' -> + parseJSON o''' + <|> impureNonNull . Map.singleton (WorkflowGraphEdgeFormOrder Nothing) <$> parseJSON o''' instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (WorkflowPayloadSpec fileid userid) where toJSON (WorkflowPayloadSpec f) = toJSON f instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (WorkflowPayloadField fileid userid payload) where - toJSON (WorkflowPayloadFieldText{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldText{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFText' , "label" JSON..= wpftLabel , "placeholder" JSON..= wpftPlaceholder @@ -697,7 +695,7 @@ instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (Wo , "large" JSON..= wpftLarge , "optional" JSON..= wpftOptional ] - toJSON (WorkflowPayloadFieldNumber{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldNumber{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFNumber' , "label" JSON..= wpfnLabel , "placeholder" JSON..= wpfnPlaceholder @@ -708,42 +706,42 @@ instance (ToJSON fileid, ToJSON userid, ToJSON (FileField fileid)) => ToJSON (Wo , "step" JSON..= wpfnStep , "optional" JSON..= wpfnOptional ] - toJSON (WorkflowPayloadFieldBool{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldBool{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFBool' , "label" JSON..= wpfbLabel , "tooltip" JSON..= wpfbTooltip , "default" JSON..= wpfbDefault , "optional" JSON..= wpfbOptional ] - toJSON (WorkflowPayloadFieldDay{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldDay{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFDay' , "label" JSON..= wpfdLabel , "tooltip" JSON..= wpfdTooltip , "default" JSON..= wpfdDefault , "optional" JSON..= wpfdOptional ] - toJSON (WorkflowPayloadFieldFile{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldFile{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFFile' , "label" JSON..= wpffLabel , "tooltip" JSON..= wpffTooltip , "config" JSON..= wpffConfig , "optional" JSON..= wpffOptional ] - toJSON (WorkflowPayloadFieldUser{..}) = JSON.object $ omitNothing + toJSON WorkflowPayloadFieldUser{..} = JSON.object $ omitNothing [ "tag" JSON..= WPFUser' , "label" JSON..= wpfuLabel , "tooltip" JSON..= wpfuTooltip , "default" JSON..= wpfuDefault , "optional" JSON..= wpfuOptional ] - toJSON (WorkflowPayloadFieldCaptureUser{}) = JSON.object + toJSON WorkflowPayloadFieldCaptureUser{} = JSON.object [ "tag" JSON..= WPFCaptureUser' ] - toJSON (WorkflowPayloadFieldReference{..}) = JSON.object + toJSON WorkflowPayloadFieldReference{..} = JSON.object [ "tag" JSON..= WPFReference' , "target" JSON..= wpfrTarget ] - toJSON (WorkflowPayloadFieldMultiple{..}) = JSON.object + toJSON WorkflowPayloadFieldMultiple{..} = JSON.object [ "tag" JSON..= WPFMultiple' , "label" JSON..= wpfmLabel , "tooltip" JSON..= wpfmTooltip diff --git a/src/Utils/I18n.hs b/src/Utils/I18n.hs index 3c58c4213..a2c811a06 100644 --- a/src/Utils/I18n.hs +++ b/src/Utils/I18n.hs @@ -47,6 +47,9 @@ import Control.Lens.Extras (is) import Control.Monad.Fail (fail) +{-# ANN module ("HLint: ignore Use newtype instead of data"::String) #-} + + data I18n a = I18n { i18nFallback :: a , i18nFallbackLang :: Maybe Lang diff --git a/src/Utils/Workflow.hs b/src/Utils/Workflow.hs index b53a4e11b..ee7c1a32d 100644 --- a/src/Utils/Workflow.hs +++ b/src/Utils/Workflow.hs @@ -1,5 +1,3 @@ -{-# OPTIONS -Wno-error=redundant-constraints #-} - module Utils.Workflow ( _DBWorkflowScope , fromRouteWorkflowScope, toRouteWorkflowScope diff --git a/src/Utils/Workflow/Lint.hs b/src/Utils/Workflow/Lint.hs index 5ec41819c..b68dcf946 100644 --- a/src/Utils/Workflow/Lint.hs +++ b/src/Utils/Workflow/Lint.hs @@ -8,6 +8,9 @@ import Import.NoFoundation import qualified Data.Set as Set import qualified Data.Map as Map + +{-# ANN module ("HLint: ignore Use newtype instead of data"::String) #-} + data WorkflowGraphLinterIssue = WGLUnknownGraphNodeLabel WorkflowGraphNodeLabel diff --git a/test/Database/Fill.hs b/test/Database/Fill.hs index d0c340971..1cb2cf566 100644 --- a/test/Database/Fill.hs +++ b/test/Database/Fill.hs @@ -1331,6 +1331,42 @@ fillDb = do , workflowInstanceDescriptionDescription = Just "Hier können Sie Abschlussarbeiten bei der Prüfungsverwaltung angemeldet werden, der relevante Student die Arbeit digital abgeben und im Anschluss auch die Benotung an die Prüfungsverwaltung übermittelt werden." } + do + workflowDefinitionGraph <- Yaml.decodeFileThrow $ testdataDir "recognitions.yaml" + for_ (lintWorkflowGraph workflowDefinitionGraph) $ mapM_ throwM + let + recognitionsWorkflowDef = WorkflowDefinition{..} + where workflowDefinitionInstanceCategory = Just "recognitions" + workflowDefinitionName = "recognitions" + workflowDefinitionScope = WSSchool' + wdId <- insert recognitionsWorkflowDef + insert_ WorkflowDefinitionDescription + { workflowDefinitionDescriptionDefinition = wdId + , workflowDefinitionDescriptionLanguage = "de-de-formal" + , workflowDefinitionDescriptionTitle = "Anerkennungen" + , workflowDefinitionDescriptionDescription = Just "Erlaubt Anerkennungen von Leistungen in Uni2work zu verwalten" + } + insert_ WorkflowDefinitionInstanceDescription + { workflowDefinitionInstanceDescriptionDefinition = wdId + , workflowDefinitionInstanceDescriptionLanguage = "de-de-formal" + , workflowDefinitionInstanceDescriptionTitle = "Anerekennungen" + , workflowDefinitionInstanceDescriptionDescription = Nothing + } + let + recognitionsWorkflowInst = WorkflowInstance{..} + where workflowInstanceDefinition = Just wdId + workflowInstanceGraph = workflowDefinitionGraph + workflowInstanceScope = WSSchool $ unSchoolKey ifi + workflowInstanceName = workflowDefinitionName recognitionsWorkflowDef + workflowInstanceCategory = workflowDefinitionInstanceCategory recognitionsWorkflowDef + wiId <- insert recognitionsWorkflowInst + insert_ WorkflowInstanceDescription + { workflowInstanceDescriptionInstance = wiId + , workflowInstanceDescriptionLanguage = "de-de-formal" + , workflowInstanceDescriptionTitle = "Anerkennungen" + , workflowInstanceDescriptionDescription = Nothing + } + forM_ universeF $ \changelogItem -> do let ptn = "templates/i18n/changelog/" <> unpack (toPathPiece changelogItem) <> ".*" files <- liftIO $ glob ptn diff --git a/testdata/recognitions.yaml b/testdata/recognitions.yaml new file mode 100644 index 000000000..c8fc4afe5 --- /dev/null +++ b/testdata/recognitions.yaml @@ -0,0 +1,739 @@ +"init": + final: false + messages: [] + edges: + "antrag freischalten": + display-label: "Einzelnen Anerkennungsantrag freischalten" + mode: initial + actors: + - &pruefungsamt + tag: authorized + authorized: { "dnf-terms": [[{"tag": "variable", "var": "exam-office"}]] } + view-actor: + - *pruefungsamt + form: + "student": + - tag: user + label: "Student" + tooltip: null + default: null + optional: false + viewers: + display-label: "Antrag freigeschaltet" + viewers: + - *pruefungsamt + - &student + tag: payload-reference + payload-label: "student" + payload-view: &payload-view-init + "student": + viewers: + - *pruefungsamt + display-label: "Student" + +"itkompetenz antrag, student": + final: false + messages: &messages-antrag-student + - <<: &message-antrag-student + viewers: + - *student + status: warning + content: "Sie können Ihren Antrag aktuell beliebig editieren. Sie müssen ihn jedoch „zur Begutachtung einreichen“ bevor er von der Prüfungsverwaltung bearbeitet wird. Danach können Sie ihn erst wieder editieren, falls die Prüfungsverwaltung den Antrag an Sie zurück gibt." + edges: + "itkompetenz beantragen": + mode: manual + display-label: "Eine Veranstaltung als IT-Kompetenz anerkennen (nur Informatik-Hauptfach Bachelor)" + source: "init" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: &itkompetenz-form + "titel": &titel-form + - "1": + tag: text + label: "Titelvorschlag für Veranstaltung" + tooltip: null + default: null + optional: false + "titel, englisch": &entitel-form + - "2": + tag: text + label: "Titelvorschlag für Verastaltung, auf Englisch" + tooltip: null + default: null + optional: false + "beleg": &beleg-form + - "3": &beleg-field + tag: file + label: "Bescheid über durchgeführte Tätigkeit" + tooltip: null + optional: false + config: + unpack-zips: + default: false + force: true + multiple: false + all-empty-ok: false + max-file-size: 5242880 + "itkompetenz editieren": + mode: manual + display-label: "Antrag bearbeiten (IT-Kompetenz)" + source: "itkompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: *itkompetenz-form + "itkompetenz antrag zurueck": + mode: manual + display-label: "Antrag an Student zurück geben" + source: "itkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &itkompetenz-notizen-form + "titel": *titel-form + "titel, englisch": *entitel-form + "notizen": ¬izen-form + - "4": + tag: text + large: true + label: "Notizen / Anmerkungen" + tooltip: "Zur Kommunikation mit dem Studenten" + default: null + optional: false + viewers: + display-label: "Antrag in Bearbeitung (IT-Kompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: &payload-view-itkompetenz-notizen + <<: &payload-view-itkompetenz + <<: *payload-view-init + "titel": + viewers: + - *student + - *pruefungsamt + display-label: "Titel" + "titel, englisch": + viewers: + - *student + - *pruefungsamt + display-label: "Titel, Englisch" + "beleg": + viewers: + - *student + - *pruefungsamt + display-label: "Beleg" + "notizen": + viewers: + - *student + - *pruefungsamt + display-label: "Notizen / Anmerkungen" +"itkompetenz antrag, pa": + final: false + messages: [] + viewers: + display-label: "Antrag in Begutachtung (IT-Kompetenz)" + viewers: + - *student + - *pruefungsamt + edges: + "itkompetenz einreichen": + mode: manual + display-label: "Antrag zur Begutachtung einreichen" + source: "itkompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: {} + payload-view: *payload-view-itkompetenz-notizen +"itkompetenz ok": + final: true + messages: [] + edges: + "itkompetenz akzeptieren": + mode: manual + display-label: "Antrag genehmigen" + source: "itkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "titel": *titel-form + "titel, englisch": *entitel-form + viewers: + display-label: "Antrag genehmigt (IT-Kompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-itkompetenz +"itkompetenz abgelehnt": + final: true + messages: [] + edges: + "itkompetenz ablehnen": + mode: manual + display-label: "Antrag ablehnen" + source: "itkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + viewers: + display-label: "Antrag abgelehnt (IT-Kompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-itkompetenz + +"medienkompetenz antrag, student": + final: false + messages: *messages-antrag-student + edges: + "medienkompetenz beantragen": + mode: manual + display-label: "Eine Veranstaltung als Medienkompetenz anerkennen (nur Medieninformatik-Hauptfach Bachelor)" + source: "init" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: &medienkompetenz-form + "titel": *titel-form + "titel, englisch": *entitel-form + "beleg": *beleg-form + "medienkompetenz editieren": + mode: manual + display-label: "Antrag bearbeiten (Medienkompetenz)" + source: "medienkompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: *medienkompetenz-form + "medienkompetenz antrag zurueck": + mode: manual + display-label: "Antrag an Student zurück geben" + source: "medienkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &medienkompetenz-notizen-form + "titel": *titel-form + "titel, englisch": *entitel-form + "notizen": *notizen-form + viewers: + display-label: "Antrag in Bearbeitung (Medienkompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: &payload-view-medienkompetenz-notizen + <<: &payload-view-medienkompetenz + <<: *payload-view-init + "titel": + viewers: + - *student + - *pruefungsamt + display-label: "Titel" + "titel, englisch": + viewers: + - *student + - *pruefungsamt + display-label: "Titel, Englisch" + "beleg": + viewers: + - *student + - *pruefungsamt + display-label: "Beleg" + "notizen": + viewers: + - *student + - *pruefungsamt + display-label: "Notizen / Anmerkungen" +"medienkompetenz antrag, pa": + final: false + messages: [] + viewers: + display-label: "Antrag in Begutachtung (Medienkompetenz)" + viewers: + - *student + - *pruefungsamt + edges: + "medienkompetenz einreichen": + mode: manual + display-label: "Antrag zur Begutachtung einreichen" + source: "medienkompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: {} + payload-view: *payload-view-medienkompetenz-notizen +"medienkompetenz ok": + final: true + messages: [] + edges: + "medienkompetenz akzeptieren": + mode: manual + display-label: "Antrag genehmigen" + source: "medienkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "titel": *titel-form + "titel, englisch": *entitel-form + viewers: + display-label: "Antrag genehmigt (Medienkompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-medienkompetenz +"medienkompetenz abgelehnt": + final: true + messages: [] + edges: + "medienkompetenz ablehnen": + mode: manual + display-label: "Antrag ablehnen" + source: "medienkompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + viewers: + display-label: "Antrag abgelehnt (Medienkompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-medienkompetenz + +"tutor antrag, student": + final: false + messages: *messages-antrag-student + edges: + "tutor beantragen": + mode: manual + display-label: "Tutortätigkeit als soziale und persönliche Kompetenz anerkennen lassen (nur (Medien-)Informatik Bachelor)" + source: "init" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: &tutor-form + "institut": &institut-form + - "1": + tag: text + label: "Institut" + tooltip: "An welchem Institut der LMU wurde die Tutortätigkeit ausgeübt?" + default: null + optional: false + "tutorbeleg": &tutorbeleg-form + - "2": + tag: text + label: "Veranstaltungswebseite" + tooltip: "Link zu einer offiziellen Webseite der Veranstaltung, die Sie als Tutor führt (z.B. in Uni2work)" + optional: false + - "3": + <<: *beleg-field + label: "Bestätigung" + tooltip: "Bestätigung der durchgeführten Tutortätigkeit (falls aus Webseite nicht ersichtlich)" + optional: false + "tutor editieren": + mode: manual + display-label: "Antrag bearbeiten (Tutor)" + source: "tutor antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: *tutor-form + "tutor antrag zurueck": + mode: manual + display-label: "Antrag an Student zurück geben" + source: "tutor antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &tutor-notizen-form + "institut": *institut-form + "tutorbeleg": *tutorbeleg-form + "notizen": *notizen-form + viewers: + display-label: "Antrag in Bearbeitung (Tutor)" + viewers: + - *student + - *pruefungsamt + payload-view: &payload-view-tutor-notizen + <<: &payload-view-tutor + <<: *payload-view-init + "institut": + viewers: + - *student + - *pruefungsamt + display-label: "Institut" + "tutorbeleg": + viewers: + - *student + - *pruefungsamt + display-label: "Beleg" + "notizen": + viewers: + - *student + - *pruefungsamt + display-label: "Notizen / Anmerkungen" +"tutor antrag, pa": + final: false + messages: [] + viewers: + display-label: "Antrag in Begutachtung (Tutor)" + viewers: + - *student + - *pruefungsamt + edges: + "tutor einreichen": + mode: manual + display-label: "Antrag zur Begutachtung einreichen" + source: "tutor antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: {} + payload-view: *payload-view-tutor-notizen +"tutor ok": + final: true + messages: [] + edges: + "tutor akzeptieren": + mode: manual + display-label: "Antrag genehmigen" + source: "tutor antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "institut": *institut-form + viewers: + display-label: "Antrag genehmigt (Tutor)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-tutor +"tutor abgelehnt": + final: true + messages: [] + edges: + "tutor ablehnen": + mode: manual + display-label: "Antrag ablehnen" + source: "tutor antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + viewers: + display-label: "Antrag abgelehnt (Tutor)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-tutor + +"sozialekompetenz antrag, student": + final: false + messages: *messages-antrag-student + edges: + "sozialekompetenz beantragen": + mode: manual + display-label: "Tätigkeit (nicht Tutortätigkeit) als soziale und persönliche Kompetenz anerkennen lassen (nur (Medien-)Informatik Bachelor)" + source: "init" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: &sozialekompetenz-form + "titel": *titel-form + "titel, englisch": *entitel-form + "beleg": *beleg-form + "sozialekompetenz editieren": + mode: manual + display-label: "Antrag bearbeiten (Sozialekompetenz)" + source: "sozialekompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: *sozialekompetenz-form + "sozialekompetenz antrag zurueck": + mode: manual + display-label: "Antrag an Student zurück geben" + source: "sozialekompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &sozialekompetenz-notizen-form + "titel": *titel-form + "titel, englisch": *entitel-form + "notizen": *notizen-form + viewers: + display-label: "Antrag in Bearbeitung (Sozialekompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: &payload-view-sozialekompetenz-notizen + <<: &payload-view-sozialekompetenz + <<: *payload-view-init + "titel": + viewers: + - *student + - *pruefungsamt + display-label: "Titel" + "titel, englisch": + viewers: + - *student + - *pruefungsamt + display-label: "Titel, Englisch" + "beleg": + viewers: + - *student + - *pruefungsamt + display-label: "Beleg" + "notizen": + viewers: + - *student + - *pruefungsamt + display-label: "Notizen / Anmerkungen" +"sozialekompetenz antrag, pa": + final: false + messages: [] + viewers: + display-label: "Antrag in Begutachtung (Sozialekompetenz)" + viewers: + - *student + - *pruefungsamt + edges: + "sozialekompetenz einreichen": + mode: manual + display-label: "Antrag zur Begutachtung einreichen" + source: "sozialekompetenz antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: {} + payload-view: *payload-view-sozialekompetenz-notizen +"sozialekompetenz ok": + final: true + messages: [] + edges: + "sozialekompetenz akzeptieren": + mode: manual + display-label: "Antrag genehmigen" + source: "sozialekompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "titel": *titel-form + "titel, englisch": *entitel-form + viewers: + display-label: "Antrag genehmigt (Sozialekompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-sozialekompetenz +"sozialekompetenz abgelehnt": + final: true + messages: [] + edges: + "sozialekompetenz ablehnen": + mode: manual + display-label: "Antrag ablehnen" + source: "sozialekompetenz antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + viewers: + display-label: "Antrag abgelehnt (Sozialekompetenz)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-sozialekompetenz + +"englisch antrag, student": + final: false + messages: *messages-antrag-student + edges: + "englisch beantragen": + mode: manual + display-label: "Note aus dem e-Xplore Technical Englisch Kurs melden" + source: "init" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: &englisch-form + "note": ¬e-form + - "1": ¬e-field + tag: text + label: "Note" + placeholder: "Note" + optional: false + "datum": &datum-form + - "2": &datum-field + tag: day + label: "Datum" + optional: false + "englischbeleg": &englischbeleg-form + - "3": &englischbeleg-field + tag: file + label: "Dokument" + tooltip: "Mindestens die Seite mit Note und Datum" + optional: false + config: + unpack-zips: + default: true + force: true + multiple: true + all-empty-ok: false + max-file-size: 5242880 + "englisch editieren": + mode: manual + display-label: "Antrag bearbeiten (Englisch)" + source: "englisch antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: *englisch-form + "englisch antrag zurueck": + mode: manual + display-label: "Antrag an Student zurück geben" + source: "englisch antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &englisch-notizen-form + "note": *note-form + "datum": *datum-form + "englischbeleg": *englischbeleg-form + "notizen": *notizen-form + viewers: + display-label: "Antrag in Bearbeitung (Englisch)" + viewers: + - *student + - *pruefungsamt + payload-view: &payload-view-englisch-notizen + <<: &payload-view-englisch + <<: *payload-view-init + "note": + viewers: + - *student + - *pruefungsamt + display-label: "Note" + "datum": + viewers: + - *student + - *pruefungsamt + display-label: "Datum" + "englischbeleg": + viewers: + - *student + - *pruefungsamt + display-label: "Beleg" + "notizen": + viewers: + - *student + - *pruefungsamt + display-label: "Notizen / Anmerkungen" +"englisch antrag, pa": + final: false + messages: [] + viewers: + display-label: "Antrag in Begutachtung (Englisch)" + viewers: + - *student + - *pruefungsamt + edges: + "englisch einreichen": + mode: manual + display-label: "Antrag zur Begutachtung einreichen" + source: "englisch antrag, student" + actors: + - *student + view-actor: + - *pruefungsamt + - *student + form: {} + payload-view: *payload-view-englisch-notizen +"englisch ok": + final: true + messages: [] + edges: + "englisch akzeptieren": + mode: manual + display-label: "Antrag genehmigen" + source: "englisch antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "note": *note-form + "datum": *datum-form + viewers: + display-label: "Antrag genehmigt (Englisch)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-englisch +"englisch abgelehnt": + final: true + messages: [] + edges: + "englisch ablehnen": + mode: manual + display-label: "Antrag ablehnen" + source: "englisch antrag, pa" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + viewers: + display-label: "Antrag abgelehnt (Englisch)" + viewers: + - *student + - *pruefungsamt + payload-view: *payload-view-englisch diff --git a/testdata/theses.yaml b/testdata/theses.yaml index 55f6607f2..deb02d3ca 100644 --- a/testdata/theses.yaml +++ b/testdata/theses.yaml @@ -1,643 +1,683 @@ -nodes: - "antrag": +"antrag": + viewers: + display-label: "Antrag angelegt" viewers: - display-label: "Antrag angelegt" + - &pruefungsamt + tag: authorized + authorized: { "dnf-terms": [[{"tag": "variable", "var": "exam-office"}]] } + - &hochschullehrer + tag: payload-reference + payload-label: "hochschullehrer" + - &betreuer + tag: payload-reference + payload-label: "betreuer" + - &student + tag: payload-reference + payload-label: "student" + payload-view: &payload-view + "hochschullehrer": viewers: - - &pruefungsamt - tag: authorized - authorized: { "dnf-terms": [[{"tag": "variable", "var": "exam-office"}]] } - - &hochschullehrer - tag: payload-reference - payload-label: "hochschullehrer" - - &betreuer - tag: payload-reference - payload-label: "betreuer" - - &student - tag: payload-reference - payload-label: "student" - payload-view: &payload-view - "hochschullehrer": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Verantwortliche Hochschullehrer" - "betreuer": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Betreuer" - "student": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Student" - "anmeldetag": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Tag der Anmeldung" - "sprache": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Sprache der Arbeit" - "titel": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Titel, in Sprache der Arbeit" - "titel, englisch": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - - {"tag": "initiator"} - display-label: "Titel, Englisch" - "notizen": - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - {"tag": "initiator"} - display-label: "Notizen" - messages: - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: negated - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag vom Student und von einem verantwortlichen Hochschullehrer bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: variable - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Der Antrag muss zunächst noch vom Student und von einem verantwortlichen Hochschullehrer bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." - final: false - edges: - "antrag als pruefungsamt": - mode: initial - display-label: "Antrag anlegen (als Prüfungsverwaltung)" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: &antrag-forms-pruefungsamt - "hochschullehrer": &hochschullehrer-form - - "1": - tag: multiple - label: "Verantwortliche Hochschullehrer" + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Verantwortliche Hochschullehrer" + "betreuer": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Betreuer" + "student": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Student" + "anmeldetag": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Tag der Anmeldung" + "sprache": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Sprache der Arbeit" + "titel": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Titel, in Sprache der Arbeit" + "titel, englisch": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + - {"tag": "initiator"} + display-label: "Titel, Englisch" + "abgabe": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + display-label: "Abgabe" + "notizen": + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - {"tag": "initiator"} + display-label: "Notizen" + messages: + - viewers: + - *hochschullehrer + - *betreuer + restriction: + dnf-terms: + - - tag: negated + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag vom Student und von einem verantwortlichen Hochschullehrer bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." + - viewers: + - *hochschullehrer + - *betreuer + restriction: + dnf-terms: + - - tag: variable + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Der Antrag muss zunächst noch vom Student und von einem verantwortlichen Hochschullehrer bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." + final: false + edges: + "antrag als pruefungsamt": + mode: initial + display-label: "Antrag anlegen (als Prüfungsverwaltung)" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: &antrag-forms-pruefungsamt + "hochschullehrer": &hochschullehrer-form + - "1": + tag: multiple + label: "Verantwortliche Hochschullehrer" + tooltip: null + default: null + min: 1 + range: null + sub: + tag: user + label: "Verantwortlicher Hochschullehrer" tooltip: null default: null - min: 1 - range: null - sub: - tag: user - label: "Verantwortlicher Hochschullehrer" - tooltip: null - default: null - optional: false - "betreuer": &betreuer-form - - "2": - tag: multiple + optional: false + "betreuer": &betreuer-form + - "2": + tag: multiple + label: "Betreuer" + tooltip: null + default: null + min: 0 + range: null + sub: + tag: user label: "Betreuer" tooltip: null default: null - min: 0 - range: null - sub: - tag: user - label: "Betreuer" - tooltip: null - default: null - optional: false - "student": &student-form - - "3": + optional: false + "student": &student-form + - "3": + tag: user + label: "Student" + tooltip: null + default: null + optional: false + "anmeldetag": &anmeldetag-form-optional + - "4": &anmeldetag-field-optional + tag: day + label: "Tag der Anmeldung" + tooltip: null + default: null + optional: true + "sprache": &sprache-form-optional + - "5": &sprache-field-optional + tag: text + label: "Sprache der Arbeit" + tooltip: null + default: null + optional: true + "titel": &titel-form-optional + - "6": &titel-field-optional + tag: text + label: "Titel, in Sprache der Arbeit" + tooltip: null + default: null + optional: true + "titel, englisch": &entitel-form-optional + - "7": &entitel-field-optional + tag: text + label: "Titel, Englisch" + tooltip: null + default: null + optional: true + "aufgabenstellung": &aufgabenstellung-form + - "8": + tag: text + large: true + label: "Aufgabenstellung" + tooltip: null + default: null + optional: true + "notizen": ¬izen-form + - "10": + tag: text + large: true + label: "Notizen" + tooltip: "Einsehbar für alle Beteiligten, außer den Studenten" + default: null + optional: true + "korrektur als pruefungsamt": &korrektur-pruefungsamt + mode: manual + display-label: "Antrag anpassen" + source: "antrag" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: *antrag-forms-pruefungsamt + "korrektur als pruefungsamt, hochschullehrer": + <<: *korrektur-pruefungsamt + source: "antrag, hochschullehrer" + "korrektur als pruefungsamt, student": + <<: *korrektur-pruefungsamt + source: "antrag, student" + "korrektur als pruefungsamt, student&hochschullehrer": + <<: *korrektur-pruefungsamt + source: "antrag, student&hochschullehrer" + "korrektur als pruefungsamt, student&hochschullehrer&anmeldetag": + <<: *korrektur-pruefungsamt + source: "antrag, student&hochschullehrer, anmeldetag" + "antrag als hochschullehrer": + mode: initial + display-label: "Antrag anlegen (als verantwortlicher Hochschullehrer)" + actors: + - tag: authorized + authorized: { "dnf-terms": [[{"tag": "variable", "var": "lecturer" }]] } + view-actor: &view-actor-all + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + form: &antrag-forms-hochschullehrer + "hochschullehrer": + - "1": + tag: capture-user + - "1.1": + tag: multiple + label: "Zusätzliche verantwortliche Hochschullehrer" + tooltip: null + default: null + min: 0 + range: null + sub: tag: user - label: "Student" + label: "Verantwortlicher Hochschullehrer" tooltip: null default: null optional: false - "anmeldetag": &anmeldetag-form-optional - - "4": &anmeldetag-field-optional - tag: day - label: "Tag der Anmeldung" - tooltip: null - default: null - optional: true - "sprache": &sprache-form-optional - - "5": &sprache-field-optional - tag: text - label: "Sprache der Arbeit" - tooltip: null - default: null - optional: true - "titel": &titel-form-optional - - "6": &titel-field-optional - tag: text - label: "Titel, in Sprache der Arbeit" - tooltip: null - default: null - optional: true - "titel, englisch": &entitel-form-optional - - "7": &entitel-field-optional - tag: text - label: "Titel, Englisch" - tooltip: null - default: null - optional: true - "aufgabenstellung": &aufgabenstellung-form - - "8": - tag: text - large: true - label: "Aufgabenstellung" - tooltip: null - default: null - optional: true - "notizen": ¬izen-form - - "9": - tag: text - large: true - label: "Notizen" - tooltip: "Einsehbar für alle Beteiligten, außer den Studenten" - default: null - optional: true - "korrektur als pruefungsamt": &korrektur-pruefungsamt - mode: manual - display-label: "Antrag anpassen" - source: "antrag" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: *antrag-forms-pruefungsamt - "korrektur als pruefungsamt, hochschullehrer": - <<: *korrektur-pruefungsamt - source: "antrag, hochschullehrer" - "korrektur als pruefungsamt, student": - <<: *korrektur-pruefungsamt - source: "antrag, student" - "korrektur als pruefungsamt, student&hochschullehrer": - <<: *korrektur-pruefungsamt - source: "antrag, student&hochschullehrer" - "korrektur als pruefungsamt, student&hochschullehrer&anmeldetag": - <<: *korrektur-pruefungsamt - source: "antrag, student&hochschullehrer, anmeldetag" - "antrag als hochschullehrer": - mode: initial - display-label: "Antrag anlegen (als verantwortlicher Hochschullehrer)" - actors: - - tag: authorized - authorized: { "dnf-terms": [[{"tag": "variable", "var": "lecturer" }]] } - view-actor: &view-actor-all - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - form: &antrag-forms-hochschullehrer - "hochschullehrer": - - "1": - tag: capture-user - - "1.1": - tag: multiple - label: "Zusätzliche verantwortliche Hochschullehrer" - tooltip: null - default: null - min: 0 - range: null - sub: - tag: user - label: "Verantwortlicher Hochschullehrer" - tooltip: null - default: null - optional: false - "betreuer": *betreuer-form - "student": *student-form - "anmeldetag": *anmeldetag-form-optional - "sprache": *sprache-form-optional - "titel": *titel-form-optional - "titel, englisch": *entitel-form-optional - "aufgabenstellung": *aufgabenstellung-form - "notizen": *notizen-form - "korrektur als hochschullehrer": &korrektur-hochschullehrer - mode: manual - display-label: "Antrag anpassen" - source: "antrag" - actors: - - *hochschullehrer - view-actor: *view-actor-all - form: *antrag-forms-hochschullehrer - "korrektur als hochschullehrer, student": - <<: *korrektur-hochschullehrer - source: "antrag, student" - "antrag als betreuer": - mode: initial - display-label: "Antrag anlegen (als Betreuer)" - actors: - - tag: authorized - authorized: { "dnf-terms": [[{"tag": "variable", "var": "lecturer" }]] } - view-actor: *view-actor-all - form: &antrag-forms-betreuer - "betreuer": - - "2": - tag: capture-user - - "2.1": - tag: multiple - label: "Zusätzliche Betreuer" - tooltip: null - default: null - min: 0 - range: null - sub: - tag: user - label: "Betreuer" - tooltip: null - default: null - optional: false - "hochschullehrer": *hochschullehrer-form - "student": *student-form - "anmeldetag": *anmeldetag-form-optional - "sprache": *sprache-form-optional - "titel": *titel-form-optional - "titel, englisch": *entitel-form-optional - "aufgabenstellung": *aufgabenstellung-form - "notizen": *notizen-form - "betreuer als hochschullehrer": &betreuer-hochschullehrer - mode: manual - display-label: "Eigene Rolle zu Betreuer wechseln" - source: "antrag" - actors: - - *hochschullehrer - view-actor: *view-actor-all - form: *antrag-forms-betreuer - "betreuer als hochschullehrer, student": - <<: *betreuer-hochschullehrer - source: "antrag, student" - "betreuer als hochschullehrer, hochschullehrer": - <<: *betreuer-hochschullehrer - source: "antrag, hochschullehrer" - "betreuer als hochschullehrer, student&hochschullehrer": - <<: *betreuer-hochschullehrer - source: "antrag, student&hochschullehrer" - "betreuer als hochschullehrer, student&hochschullehrer&anmeldetag": - <<: *betreuer-hochschullehrer - source: "antrag, student&hochschullehrer, anmeldetag" - "hochschullehrer als betreuer": &hochschullehrer-betreuer - mode: manual - display-label: "Eigene Rolle zu Hochschullehrer wechseln" - source: "antrag" - actors: - - *betreuer - view-actor: *view-actor-all - form: *antrag-forms-hochschullehrer - "hochschullehrer als betreuer, hochschullehrer": - <<: *hochschullehrer-betreuer - source: "antrag, hochschullehrer" - "hochschullehrer als betreuer, student": - <<: *hochschullehrer-betreuer - source: "antrag, student" - "hochschullehrer als betreuer, student&hochschullehrer": - <<: *hochschullehrer-betreuer - source: "antrag, student&hochschullehrer" - "hochschullehrer als betreuer, student&hochschullehrer&anmeldetag": - <<: *hochschullehrer-betreuer - source: "antrag, student&hochschullehrer, anmeldetag" - "korrektur als betreuer": &korrektur-betreuer - mode: manual - display-label: "Antrag anpassen" - source: "antrag" - actors: - - *betreuer - view-actor: *view-actor-all - form: *antrag-forms-betreuer - "korrektur als betreuer, student": - <<: *korrektur-betreuer - source: "antrag, student" - "korrektur als betreuer, hochschullehrer": - <<: *korrektur-betreuer - source: "antrag, hochschullehrer" - "korrektur als betreuer, student&hochschullehrer": - <<: *korrektur-betreuer - source: "antrag, student&hochschullehrer" - "korrektur als betreuer, student&hochschullehrer&anmeldetag": - <<: *korrektur-betreuer - source: "antrag, student&hochschullehrer, anmeldetag" - "korrektur als student": &korrektur-student - mode: manual - display-label: "Antrag anpassen" - source: "antrag" - actors: - - *student - view-actor: *view-actor-all - form: - "sprache": *sprache-form-optional - "titel": *titel-form-optional - "titel, englisch": *entitel-form-optional - "aufgabenstellung": *aufgabenstellung-form - "korrektur als student, hochschullehrer": - <<: *korrektur-student - source: "antrag, hochschullehrer" - - "antrag, hochschullehrer": - viewers: - display-label: "Antrag angelegt und vom Hochschullehrer bestätigt" - viewers: - - *pruefungsamt + "betreuer": *betreuer-form + "student": *student-form + "anmeldetag": *anmeldetag-form-optional + "sprache": *sprache-form-optional + "titel": *titel-form-optional + "titel, englisch": *entitel-form-optional + "aufgabenstellung": *aufgabenstellung-form + "notizen": *notizen-form + "korrektur als hochschullehrer": &korrektur-hochschullehrer + mode: manual + display-label: "Antrag anpassen" + source: "antrag" + actors: - *hochschullehrer - - *betreuer - payload-view: *payload-view - messages: - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: negated - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag vom Student bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: variable - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Der Antrag muss zunächst noch vom Student bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." - final: false - edges: - "antrag bestaetigen als hochschullehrer": - mode: manual - display-label: "Antrag bestätigen (als verantwortlicher Hochschullehrer)" - source: "antrag" - actors: - - *hochschullehrer - - *pruefungsamt - view-actor: *view-actor-all - form: {} - "korrektur als hochschullehrer": - <<: *korrektur-hochschullehrer - source: "antrag, hochschullehrer" - "korrektur als hochschullehrer, student": - <<: *korrektur-hochschullehrer - source: "antrag, student&hochschullehrer" - "korrektur als hochschullehrer, student&anmeldetag": - <<: *korrektur-hochschullehrer - source: "antrag, student&hochschullehrer, anmeldetag" - "antrag, student": - viewers: - display-label: "Antrag angelegt und vom Student bestätigt" - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - payload-view: *payload-view - messages: - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: negated - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag von einem verantwortlichen Hochschullehrer bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." - - viewers: - - *hochschullehrer - - *betreuer - restriction: - dnf-terms: - - - tag: variable - var: - tag: payload-filled - payload-filled: "anmeldetag" - status: info - content: "Der Antrag muss zunächst noch von einem verantwortlichen Hochschullehrer bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." - final: false - edges: - "antrag bestaetigen als student": - mode: manual - display-label: "Antrag bestätigen (als Student)" - source: "antrag" - actors: - - *student - - *pruefungsamt - view-actor: *view-actor-all - form: {} - "korrektur als student": - <<: *korrektur-student - source: "antrag, student" - "korrektur als student, hochschullehrer": - <<: *korrektur-student - source: "antrag, student&hochschullehrer" - "korrektur als student, hochschullehrer&anmeldetag": - <<: *korrektur-student - source: "antrag, student&hochschullehrer, anmeldetag" - "antrag, student&hochschullehrer": - viewers: - display-label: "Antrag angelegt und von Student und Hochschullehrer bestätigt" - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - payload-view: *payload-view - messages: - - viewers: - - *hochschullehrer - - *betreuer - restriction: null - status: info - content: "Es muss zunächst „Anmeldetag“ eingetragen werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." - final: false - edges: - "antrag bestaetigen als student": - mode: manual - display-label: "Antrag bestätigen (als Student)" - source: "antrag, hochschullehrer" - actors: - - *student - - *pruefungsamt - view-actor: *view-actor-all - form: {} - "antrag bestaetigen als hochschullehrer": - mode: manual - display-label: "Antrag bestätigen (als verantwortlicher Hochschullehrer)" - source: "antrag, student" - actors: - - *hochschullehrer - - *pruefungsamt - view-actor: *view-actor-all - form: {} - "antrag, student&hochschullehrer, anmeldetag": - viewers: - display-label: "Antrag angelegt, von Student und Hochschullehrer bestätigt, Anmeldetag eingetragen" - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - payload-view: *payload-view - messages: [] - final: false - edges: - "anmeldetag ist eingetragen": - mode: automatic - source: "antrag, student&hochschullehrer" - restriction: - dnf-terms: - - - tag: variable - var: - tag: payload-filled - payload-filled: "anmeldetag" - "angemeldet": - viewers: - display-label: "Angemeldet" - viewers: - - *pruefungsamt - - *hochschullehrer - - *betreuer - - *student - payload-view: *payload-view - messages: [] - final: false - edges: - "anmelden, bestaetigt student&hochschullehrer, anmeldetag": - mode: manual - display-label: "Arbeit anmelden (bestätigt vom Student und verantwortlichem Hochschullehrer)" - source: "antrag, student&hochschullehrer, anmeldetag" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: {} - "anmelden, bestaetigt student&hochschullehrer": - mode: manual - display-label: "Arbeit anmelden (bestätigt vom Student und verantwortlichem Hochschullehrer)" - source: "antrag, student&hochschullehrer" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: - "anmeldetag": - - "4": - <<: *anmeldetag-field-optional + view-actor: *view-actor-all + form: *antrag-forms-hochschullehrer + "korrektur als hochschullehrer, student": + <<: *korrektur-hochschullehrer + source: "antrag, student" + "antrag als betreuer": + mode: initial + display-label: "Antrag anlegen (als Betreuer)" + actors: + - tag: authorized + authorized: { "dnf-terms": [[{"tag": "variable", "var": "lecturer" }]] } + view-actor: *view-actor-all + form: &antrag-forms-betreuer + "betreuer": + - "2": + tag: capture-user + - "2.1": + tag: multiple + label: "Zusätzliche Betreuer" + tooltip: null + default: null + min: 0 + range: null + sub: + tag: user + label: "Betreuer" + tooltip: null + default: null optional: false - "anmelden, bestaetigt student": - mode: manual - display-label: "Arbeit anmelden (bestätigt nur vom Student)" - source: "antrag, student" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: - "anmeldetag": - - "4": - <<: *anmeldetag-field-optional - optional: false - "anmelden, bestaetigt hochschullehrer": - mode: manual - display-label: "Arbeit anmelden (bestätigt nur vom Hochschullehrer)" - source: "antrag, hochschullehrer" - actors: - - *pruefungsamt - view-actor: - - *pruefungsamt - form: - "anmeldetag": - - "4": - <<: *anmeldetag-field-optional - optional: false - "datei": + "hochschullehrer": *hochschullehrer-form + "student": *student-form + "anmeldetag": *anmeldetag-form-optional + "sprache": *sprache-form-optional + "titel": *titel-form-optional + "titel, englisch": *entitel-form-optional + "aufgabenstellung": *aufgabenstellung-form + "notizen": *notizen-form + "betreuer als hochschullehrer": &betreuer-hochschullehrer + mode: manual + display-label: "Eigene Rolle zu Betreuer wechseln" + source: "antrag" + actors: + - *hochschullehrer + view-actor: *view-actor-all + form: *antrag-forms-betreuer + "betreuer als hochschullehrer, student": + <<: *betreuer-hochschullehrer + source: "antrag, student" + "betreuer als hochschullehrer, hochschullehrer": + <<: *betreuer-hochschullehrer + source: "antrag, hochschullehrer" + "betreuer als hochschullehrer, student&hochschullehrer": + <<: *betreuer-hochschullehrer + source: "antrag, student&hochschullehrer" + "betreuer als hochschullehrer, student&hochschullehrer&anmeldetag": + <<: *betreuer-hochschullehrer + source: "antrag, student&hochschullehrer, anmeldetag" + "hochschullehrer als betreuer": &hochschullehrer-betreuer + mode: manual + display-label: "Eigene Rolle zu Hochschullehrer wechseln" + source: "antrag" + actors: + - *betreuer + view-actor: *view-actor-all + form: *antrag-forms-hochschullehrer + "hochschullehrer als betreuer, hochschullehrer": + <<: *hochschullehrer-betreuer + source: "antrag, hochschullehrer" + "hochschullehrer als betreuer, student": + <<: *hochschullehrer-betreuer + source: "antrag, student" + "hochschullehrer als betreuer, student&hochschullehrer": + <<: *hochschullehrer-betreuer + source: "antrag, student&hochschullehrer" + "hochschullehrer als betreuer, student&hochschullehrer&anmeldetag": + <<: *hochschullehrer-betreuer + source: "antrag, student&hochschullehrer, anmeldetag" + "korrektur als betreuer": &korrektur-betreuer + mode: manual + display-label: "Antrag anpassen" + source: "antrag" + actors: + - *betreuer + view-actor: *view-actor-all + form: *antrag-forms-betreuer + "korrektur als betreuer, student": + <<: *korrektur-betreuer + source: "antrag, student" + "korrektur als betreuer, hochschullehrer": + <<: *korrektur-betreuer + source: "antrag, hochschullehrer" + "korrektur als betreuer, student&hochschullehrer": + <<: *korrektur-betreuer + source: "antrag, student&hochschullehrer" + "korrektur als betreuer, student&hochschullehrer&anmeldetag": + <<: *korrektur-betreuer + source: "antrag, student&hochschullehrer, anmeldetag" + "korrektur als student": &korrektur-student + mode: manual + display-label: "Antrag anpassen" + source: "antrag" + actors: + - *student + view-actor: *view-actor-all + form: + "sprache": *sprache-form-optional + "titel": *titel-form-optional + "titel, englisch": *entitel-form-optional + "aufgabenstellung": *aufgabenstellung-form + "korrektur als student, hochschullehrer": + <<: *korrektur-student + source: "antrag, hochschullehrer" + +"antrag, hochschullehrer": + viewers: + display-label: "Antrag angelegt und vom Hochschullehrer bestätigt" viewers: - display-label: "Datei hochgeladen" - viewers: - - *pruefungsamt + - *pruefungsamt + - *hochschullehrer + - *betreuer + payload-view: *payload-view + messages: + - viewers: - *hochschullehrer - *betreuer - - *student - payload-view: *payload-view - messages: [] - final: false - edges: {} - "abgegeben": - viewers: - display-label: "Abgabe akzeptiert" - viewers: - - *pruefungsamt + restriction: + dnf-terms: + - - tag: negated + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag vom Student bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." + - viewers: - *hochschullehrer - *betreuer - - *student - payload-view: *payload-view - messages: [] - final: false - edges: {} - "benotet": - viewers: - display-label: "Benotet" - viewers: + restriction: + dnf-terms: + - - tag: variable + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Der Antrag muss zunächst noch vom Student bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." + final: false + edges: + "antrag bestaetigen als hochschullehrer": + mode: manual + display-label: "Antrag bestätigen (als verantwortlicher Hochschullehrer)" + source: "antrag" + actors: + - *hochschullehrer - *pruefungsamt + view-actor: *view-actor-all + form: {} + "korrektur als hochschullehrer": + <<: *korrektur-hochschullehrer + source: "antrag, hochschullehrer" + "korrektur als hochschullehrer, student": + <<: *korrektur-hochschullehrer + source: "antrag, student&hochschullehrer" + "korrektur als hochschullehrer, student&anmeldetag": + <<: *korrektur-hochschullehrer + source: "antrag, student&hochschullehrer, anmeldetag" +"antrag, student": + viewers: + display-label: "Antrag angelegt und vom Student bestätigt" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + payload-view: *payload-view + messages: + - viewers: - *hochschullehrer - *betreuer - - *student - payload-view: *payload-view - messages: [] - final: false - edges: {} - "abgebrochen": - viewers: - display-label: "Abgebrochen" - viewers: - - *pruefungsamt + restriction: + dnf-terms: + - - tag: negated + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Es muss zunächst „Anmeldetag“ eingetragen und der Antrag von einem verantwortlichen Hochschullehrer bestätigt werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." + - viewers: - *hochschullehrer - *betreuer + restriction: + dnf-terms: + - - tag: variable + var: + tag: payload-filled + payload-filled: "anmeldetag" + status: info + content: "Der Antrag muss zunächst noch von einem verantwortlichen Hochschullehrer bestätigt werden, damit er von der Prüfungsverwaltung weiter bearbeitet werden kann." + final: false + edges: + "antrag bestaetigen als student": + mode: manual + display-label: "Antrag bestätigen (als Student)" + source: "antrag" + actors: - *student - payload-view: *payload-view - messages: [] - final: false - edges: {} - "fertig": - viewers: - display-label: "Fertig" - viewers: - *pruefungsamt - payload-view: *payload-view - messages: [] - final: true - edges: {} + view-actor: *view-actor-all + form: {} + "korrektur als student": + <<: *korrektur-student + source: "antrag, student" + "korrektur als student, hochschullehrer": + <<: *korrektur-student + source: "antrag, student&hochschullehrer" + "korrektur als student, hochschullehrer&anmeldetag": + <<: *korrektur-student + source: "antrag, student&hochschullehrer, anmeldetag" +"antrag, student&hochschullehrer": + viewers: + display-label: "Antrag angelegt und von Student und Hochschullehrer bestätigt" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + payload-view: *payload-view + messages: + - viewers: + - *hochschullehrer + - *betreuer + restriction: null + status: info + content: "Es muss zunächst „Anmeldetag“ eingetragen werden, damit der Antrag weiter von der Prüfungsverwaltung bearbeitet werden kann." + final: false + edges: + "antrag bestaetigen als student": + mode: manual + display-label: "Antrag bestätigen (als Student)" + source: "antrag, hochschullehrer" + actors: + - *student + - *pruefungsamt + view-actor: *view-actor-all + form: {} + "antrag bestaetigen als hochschullehrer": + mode: manual + display-label: "Antrag bestätigen (als verantwortlicher Hochschullehrer)" + source: "antrag, student" + actors: + - *hochschullehrer + - *pruefungsamt + view-actor: *view-actor-all + form: {} +"antrag, student&hochschullehrer, anmeldetag": + viewers: + display-label: "Antrag angelegt, von Student und Hochschullehrer bestätigt, Anmeldetag eingetragen" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + payload-view: *payload-view + messages: [] + final: false + edges: + "anmeldetag ist eingetragen": + mode: automatic + source: "antrag, student&hochschullehrer" + restriction: + dnf-terms: + - - tag: variable + var: + tag: payload-filled + payload-filled: "anmeldetag" +"angemeldet": + viewers: + display-label: "Angemeldet" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + payload-view: *payload-view + messages: [] + final: false + edges: + "anmelden, bestaetigt student&hochschullehrer, anmeldetag": + mode: manual + display-label: "Arbeit anmelden (bestätigt vom Student und verantwortlichem Hochschullehrer)" + source: "antrag, student&hochschullehrer, anmeldetag" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} + "anmelden, bestaetigt student&hochschullehrer": + mode: manual + display-label: "Arbeit anmelden (bestätigt vom Student und verantwortlichem Hochschullehrer)" + source: "antrag, student&hochschullehrer" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "anmeldetag": + - "4": + <<: *anmeldetag-field-optional + optional: false + "anmelden, bestaetigt student": + mode: manual + display-label: "Arbeit anmelden (bestätigt nur vom Student)" + source: "antrag, student" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "anmeldetag": + - "4": + <<: *anmeldetag-field-optional + optional: false + "anmelden, bestaetigt hochschullehrer": + mode: manual + display-label: "Arbeit anmelden (bestätigt nur vom Hochschullehrer)" + source: "antrag, hochschullehrer" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: + "anmeldetag": + - "4": + <<: *anmeldetag-field-optional + optional: false +"datei": + viewers: + display-label: "Abgabe hochgeladen" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + payload-view: *payload-view + messages: [] + final: false + edges: + "datei hochladen": + mode: manual + display-label: "Arbeit hochladen" + source: "angemeldet" + actors: + - *pruefungsamt + - *student + view-actor: + - *pruefungsamt + - *student + - *betreuer + - *hochschullehrer + form: + "abgabe": + - "9": + tag: file + label: "Abgabe" + tooltip: null + optional: false + config: + unpack-zips: + default: true + force: false + multiple: true + all-empty-ok: false +"abgegeben": + viewers: + display-label: "Abgabe akzeptiert" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + payload-view: *payload-view + messages: [] + final: false + edges: + "datei akzeptieren": + mode: manual + display-label: "Abgabe akzeptieren" + source: "datei" + actors: + - *pruefungsamt + view-actor: + - *pruefungsamt + form: {} +"benotet": + viewers: + display-label: "Benotet" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + payload-view: *payload-view + messages: [] + final: false + edges: {} +"abgebrochen": + viewers: + display-label: "Abgebrochen" + viewers: + - *pruefungsamt + - *hochschullehrer + - *betreuer + - *student + payload-view: *payload-view + messages: [] + final: false + edges: {} +"fertig": + viewers: + display-label: "Fertig" + viewers: + - *pruefungsamt + payload-view: *payload-view + messages: [] + final: true + edges: {}