diff --git a/Language/src/Core/BasicTasks/UserDBTasks.dcl b/Language/src/Core/BasicTasks/UserDBTasks.dcl index 1e6006e3328e6d847c4bc7f0a0937efb99023a58..614f3cc1917b0a86d70b51648fd99bb30f804a02 100644 --- a/Language/src/Core/BasicTasks/UserDBTasks.dcl +++ b/Language/src/Core/BasicTasks/UserDBTasks.dcl @@ -4,7 +4,7 @@ definition module UserDBTasks * of the iTask system. These tasks are useful when work is to be delegated to * other users. */ -import StdMaybe +import StdMaybe, Void from TSt import :: Task from Types import :: UserId @@ -48,9 +48,15 @@ authenticateUser :: !String !String -> Task (Maybe User) /** * Add a new user */ -createUser :: !String !String !String ![String] -> Task User - - +createUser :: !User -> Task User +/** +* Update an existing user +*/ +updateUser :: !User -> Task User +/** +* Delete an existing user +*/ +deleteUser :: !User -> Task User //Interactively choose a user chooseUser :: !question -> Task User | html question diff --git a/Language/src/Core/BasicTasks/UserDBTasks.icl b/Language/src/Core/BasicTasks/UserDBTasks.icl index 99afacb3a037b322ce5f3a464b248ef6f787e789..96221baeaae9b95850a6973325f8eb73c973cc34 100644 --- a/Language/src/Core/BasicTasks/UserDBTasks.icl +++ b/Language/src/Core/BasicTasks/UserDBTasks.icl @@ -14,6 +14,8 @@ from UserDB import qualified getUserNames from UserDB import qualified getRoles from UserDB import qualified authenticateUser from UserDB import qualified createUser +from UserDB import qualified updateUser +from UserDB import qualified deleteUser import InteractionTasks, CoreCombinators @@ -41,9 +43,14 @@ getRoles uids = mkInstantTask "getRoles" (UserDB@getRoles uids) authenticateUser :: !String !String -> Task (Maybe User) authenticateUser username password = mkInstantTask "authenticateUser" (UserDB@authenticateUser username password) -createUser :: !String !String !String ![String] -> Task User -createUser username password displayname roles - = mkInstantTask "createUser" (UserDB@createUser username password displayname roles) +createUser :: !User -> Task User +createUser user = mkInstantTask "createUser" (UserDB@createUser user) + +updateUser :: !User -> Task User +updateUser user = mkInstantTask "updateUser" (UserDB@updateUser user) + +deleteUser :: !User -> Task User +deleteUser user = mkInstantTask "deleteUser" (UserDB@deleteUser user) chooseUser :: !question -> Task User | html question chooseUser question diff --git a/Language/src/Core/TaskCombinators/CommonCombinators.dcl b/Language/src/Core/TaskCombinators/CommonCombinators.dcl index bb5f71a1081a4b3bbbaf21d4ba0b927b36ac1513..383a42d33f4cbbbf236c0c820ba743368818c50c 100644 --- a/Language/src/Core/TaskCombinators/CommonCombinators.dcl +++ b/Language/src/Core/TaskCombinators/CommonCombinators.dcl @@ -27,6 +27,14 @@ eitherTask :: !(Task a) !(Task b) -> Task (Either a b) | iTask a & iTask (>>?) infixl 1 :: !(Task (Maybe a)) !(a -> Task (Maybe b)) -> Task (Maybe b) | iTask a & iTask b (-&?&-) infixr 4 :: !(Task (Maybe a)) !(Task (Maybe b)) -> Task (Maybe (a,b)) | iTask a & iTask b +//Post processing of results +ignoreResult :: !(Task a) -> Task Void | iTask a +transformResult :: !(a -> b) !(Task a) -> Task b | iTask a & iTask b + +//Synonym for (return Void) +stop :: Task Void + + //Task delegation class (@:) infix 3 u :: u !(LabeledTask a) -> Task a | iTask a diff --git a/Language/src/Core/TaskCombinators/CommonCombinators.icl b/Language/src/Core/TaskCombinators/CommonCombinators.icl index 9f6c410041c476d24210ac4246fd973452af7cfa..1065c0d7066c624b19772089717be5af5b1b27f9 100644 --- a/Language/src/Core/TaskCombinators/CommonCombinators.icl +++ b/Language/src/Core/TaskCombinators/CommonCombinators.icl @@ -98,6 +98,16 @@ where combineResult [Left (Just r1),Right (Just r2)] = Just (r1,r2) combineResult _ = Nothing +//Post processing of results +ignoreResult :: !(Task a) -> Task Void | iTask a +ignoreResult task = "ignoreResult" @>> (task >>| return Void) + +transformResult :: !(a -> b) !(Task a) -> Task b | iTask a & iTask b +transformResult fun task = "transformResult" @>> (task >>= \a -> return (fun a)) + +stop :: Task Void +stop = "stop" @>> return Void + // ****************************************************************************************************** // repetition diff --git a/Server/src/AdminWorkflows/UserAdmin.dcl b/Server/src/AdminWorkflows/UserAdmin.dcl new file mode 100644 index 0000000000000000000000000000000000000000..2d4f4fc20b4705687ac5814f5e77c9da598c8326 --- /dev/null +++ b/Server/src/AdminWorkflows/UserAdmin.dcl @@ -0,0 +1,5 @@ +definition module UserAdmin + +import iTasks + +userAdministration :: [Workflow] \ No newline at end of file diff --git a/Server/src/AdminWorkflows/UserAdmin.icl b/Server/src/AdminWorkflows/UserAdmin.icl new file mode 100644 index 0000000000000000000000000000000000000000..fccfc417cc0071adaff24b75df5701594546e714 --- /dev/null +++ b/Server/src/AdminWorkflows/UserAdmin.icl @@ -0,0 +1,33 @@ +implementation module UserAdmin + +import iTasks + +userAdministration :: [Workflow] +userAdministration + = [{Workflow|name = "Admin/Create user", label = "Create user ", roles = ["admin"], mainTask = createUserFlow} + ,{Workflow|name = "Admin/Update user", label = "Update user", roles = ["admin"], mainTask = updateUserFlow} + ,{Workflow|name = "Admin/Delete user", label = "Delete user", roles = ["admin"], mainTask = deleteUserFlow} + ] + +createUserFlow :: Task Void +createUserFlow + = enterInformationA "Enter user information" [ActionCancel] [ActionOk] + >>= \(action,user) -> case action of + ActionCancel = stop + ActionOk = createUser user + >>| showMessage "Successfully added new user" + +updateUserFlow :: Task Void +updateUserFlow + = getUsers + >>= enterChoice "Which user do you want to update?" + >>= updateInformation "Please make your changes" + >>= updateUser + >>| showMessage "Successfully updated user" + +deleteUserFlow :: Task Void +deleteUserFlow + = getUsers + >>= enterChoice "Which user do you want to delete?" + >>= deleteUser + >>| showMessage "Successfully deleted user" \ No newline at end of file diff --git a/Server/src/Framework/Data/UserDB.dcl b/Server/src/Framework/Data/UserDB.dcl index b5809df6fff11041d0d405f793dcd9488fcbc228..bd6d41e062a68ee4e98d5e2235badb35e79509c9 100644 --- a/Server/src/Framework/Data/UserDB.dcl +++ b/Server/src/Framework/Data/UserDB.dcl @@ -85,11 +85,32 @@ authenticateUser :: !String !String !*TSt -> (!Maybe User, !*TSt) /** * Create a new user * -* @param A user name -* @param A password -* @param A display name -* @param A list of roles +* @param A new user +* @param A unique database handle +* * @return A user * @return The database handle */ -createUser :: !String !String !String ![String] !*TSt -> (User,!*TSt) \ No newline at end of file +createUser :: !User !*TSt -> (!User,!*TSt) + +/** +* Update an existing user +* +* @param An existing user +* @param A unique database handle +* +* @return The existing user +* @retrun The database handle +*/ +updateUser :: !User !*TSt -> (!User,!*TSt) + +/** +* Delete an existing user +* +* @param An existing user +* @param A unique database handle +* +* @return The existing user +* @retrun The database handle +*/ +deleteUser :: !User !*TSt -> (!User,!*TSt) \ No newline at end of file diff --git a/Server/src/Framework/Data/UserDB.icl b/Server/src/Framework/Data/UserDB.icl index a5603cbdb79f49ce0b51b2250f985e1fa6961924..565f7a8af951988d6021871f14d79cf778f01cb1 100644 --- a/Server/src/Framework/Data/UserDB.icl +++ b/Server/src/Framework/Data/UserDB.icl @@ -136,17 +136,30 @@ authenticateUser username password tst [user] = (Just user, tst) _ = (Nothing, tst) - -createUser :: !String !String !String ![String] !*TSt -> (User,!*TSt) -createUser username password displayname roles tst +createUser :: !User !*TSt -> (!User,!*TSt) +createUser user tst # (users, tst) = userStore id tst - # user = {userId= maxid users, userName = username, password = password, displayName = displayname, roles = roles} + # user = {User|user & userId= maxid users} # (users, tst) = userStore (\_-> [user:users]) tst = (user,tst) where maxid [] = 1 maxid users = maxList [user.User.userId \\ user <- users] + 1 +updateUser :: !User !*TSt -> (!User,!*TSt) +updateUser user tst + # (users,tst) = userStore (map (update user)) tst + = (user,tst) +where + update new old = if (old.User.userId == new.User.userId) new old + +deleteUser :: !User !*TSt -> (!User,!*TSt) +deleteUser user tst + # (users,tst) = userStore delete tst + = (user,tst) +where + delete users = [u \\ u <- users | u.User.userId <> user.User.userId] + //Helper function which finds a property of a certain user lookupUserProperty :: ![User] !(User -> a) !a !Int -> a lookupUserProperty users selectFunction defaultValue userId diff --git a/Server/src/Framework/Engine.icl b/Server/src/Framework/Engine.icl index 187ac64f35ca8496f090055e25678e42b9dc5c7a..fec7f66ec435a421b49e4d4facd337aea4910ce7 100644 --- a/Server/src/Framework/Engine.icl +++ b/Server/src/Framework/Engine.icl @@ -20,11 +20,13 @@ import RPCHandlers, DocumentHandler import Config, TSt +from UserAdmin import userAdministration + PATH_SEP :== "\\" // The iTasks engine consist of a set of HTTP request handlers engine :: Config [Workflow] -> [(!String -> Bool, HTTPRequest *World -> (!HTTPResponse, !*World))] -engine config flows +engine config userflows = [((==) (config.serverPath +++ "/authenticate"), handleAnonRequest config flows handleAuthenticationRequest) ,((==) (config.serverPath +++ "/deauthenticate"), handleSessionRequest config flows handleDeauthenticationRequest) ,((==) (config.serverPath +++ "/new/list"), handleSessionRequest config flows handleNewListRequest) @@ -42,6 +44,9 @@ engine config flows ,((startsWith) (config.serverPath +++ "/document/preview/link"), handleSessionRequest config flows handleDocumentPreviewLinkRequest) ,(\_ -> True, handleStaticResourceRequest) ] +where + //Always add the workflows for administering the itask system + flows = userflows ++ userAdministration workflow :: String (Task a) -> Workflow | iTask a workflow path task = diff --git a/Server/src/Framework/TSt.dcl b/Server/src/Framework/TSt.dcl index 305f08bd36e0aed68d2c7c6ce148fc586eb5bd5b..62c1c446a31c0323ea882834c9d5949ba220c26e 100644 --- a/Server/src/Framework/TSt.dcl +++ b/Server/src/Framework/TSt.dcl @@ -89,6 +89,7 @@ mkTSt :: String Config HTTPRequest Session ![Workflow] !*Store !*Store !*Store ! /** * Creates an instance of a task definition +* As soon as an instance is created it is immediately evaluated once. * * @param The task * @param Start as toplevel, or as subtask of another task (parent information is read from the task state) diff --git a/Server/src/Framework/TSt.icl b/Server/src/Framework/TSt.icl index 3ce6b07e02327bf813eef27b15d6e6b004192585..9b79c1f0112c5234dacb9b8bcb22526af3ed1dfb 100644 --- a/Server/src/Framework/TSt.icl +++ b/Server/src/Framework/TSt.icl @@ -142,7 +142,6 @@ createTaskInstance task managerProps toplevel tst=:{taskNr,mainTask} # (_,tst) = calculateTaskTree processId tst = (processId,tst) - calculateTaskTree :: !ProcessId !*TSt -> (!TaskTree, !*TSt) calculateTaskTree processId tst # (mbProcess,tst) = getProcess processId tst @@ -154,7 +153,7 @@ calculateTaskTree processId tst # (tree,tst=:{activated}) = buildProcessTree process Nothing tst //When finished, also evaluate the parent tree (and it's parent when it is also finished etc...) | activated && parent <> "" - # (_,tst) = calculateTaskTree parent tst + # (_,tst) = calculateTaskTree parent {tst & activated = True} = (tree, tst) | otherwise = (tree, tst) @@ -288,19 +287,19 @@ mkInteractiveTask :: !String !(*TSt -> *(!a,!*TSt)) -> Task a mkInteractiveTask taskname taskfun = Task {TaskDescription| title = taskname, description = Note ""} Nothing mkInteractiveTask` where mkInteractiveTask` tst=:{TSt|taskNr,taskInfo} - = taskfun {tst & tree = TTInteractiveTask taskInfo (abort "No interface definition given")} + = taskfun {tst & tree = TTInteractiveTask taskInfo (abort "No interface definition given"), activated = True} mkInstantTask :: !String !(*TSt -> *(!a,!*TSt)) -> Task a mkInstantTask taskname taskfun = Task {TaskDescription| title = taskname, description = Note ""} Nothing mkInstantTask` where mkInstantTask` tst=:{TSt|taskNr,taskInfo} - = taskfun {tst & tree = TTFinishedTask taskInfo} //We use a FinishedTask node because the task is finished after one evaluation + = taskfun {tst & tree = TTFinishedTask taskInfo, activated = True} //We use a FinishedTask node because the task is finished after one evaluation mkMonitorTask :: !String !(*TSt -> *(!a,!*TSt)) -> Task a mkMonitorTask taskname taskfun = Task {TaskDescription| title = taskname, description = Note ""} Nothing mkMonitorTask` where mkMonitorTask` tst=:{TSt|taskNr,taskInfo} - = taskfun {tst & tree = TTMonitorTask taskInfo []} + = taskfun {tst & tree = TTMonitorTask taskInfo [], activated = True} mkRpcTask :: !String !RPCExecute !(String -> a) -> Task a | gUpdate{|*|} a mkRpcTask taskname rpce parsefun = Task {TaskDescription| title = taskname, description = Note ""} Nothing mkRpcTask`