From 9d3e139b529d707248fec359f59041a206206f84 Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Sat, 27 May 2023 12:26:03 +0200 Subject: [PATCH] Parse PermissionLevel (a simple sum data type). --- spago.dhall | 1 + src/App/Messages/AuthenticationDaemon.purs | 25 +++++++------- src/App/PermissionLevel.purs | 39 ++++++++++++++++++++++ src/App/UserPublic.purs | 8 +++-- 4 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 src/App/PermissionLevel.purs diff --git a/spago.dhall b/spago.dhall index 00830b0..66e1ab5 100644 --- a/spago.dhall +++ b/spago.dhall @@ -26,6 +26,7 @@ , "transformers" , "tuples" , "uint" + , "variant" , "web-encoding" , "web-events" , "web-socket" diff --git a/src/App/Messages/AuthenticationDaemon.purs b/src/App/Messages/AuthenticationDaemon.purs index 262cd36..265b522 100644 --- a/src/App/Messages/AuthenticationDaemon.purs +++ b/src/App/Messages/AuthenticationDaemon.purs @@ -18,6 +18,7 @@ import Data.ArrayBuffer.Types (ArrayBuffer) import App.Email as Email import App.Phone as Phone import App.UserPublic as UserPublic +import App.PermissionLevel as PermissionLevel import Effect.Class (liftEffect) import Data.Argonaut.Parser as JSONParser @@ -30,28 +31,25 @@ import App.IPC as IPC Possible requests: - 1 type AddUser = { shared_key :: String, login :: String, password :: String, email :: Maybe String, phone :: Maybe Phone.Phone, profile :: Maybe Hash(String, JSON::Any) } - 2 type ValidateUser = { login :: String, activation_key :: String } - - 3 type GetUser = { user :: Int32 | String } + - 3 type GetUser = { user :: Int | String } - 4 type GetUserByCredentials = { login :: String, password :: String } - 6 type Register = { login :: String, password :: String, email :: Maybe String, phone :: Maybe Phone.Phone , profile :: Maybe Hash(String, JSON::Any) } - 7 type UpdatePassword = { login :: String, old_password :: String, new_password :: String } - 8 type ListUsers = { token :: Maybe String, key :: Maybe String } - - 9 type CheckPermission = { shared_key :: Maybe String, token :: Maybe String, user :: Int32 | String, service :: String, resource :: String } - - 10 type SetPermission = { shared_key :: String, user :: Int32 | String, service :: String, resource :: String, permission :: AuthD::User::PermissionLevel } - - 11 type PasswordRecovery = { user :: Int32 | String, password_renew_key :: String, new_password :: String } - - 12 type AskPasswordRecovery = { user :: Int32 | String, email :: String } + - 9 type CheckPermission = { shared_key :: Maybe String, token :: Maybe String, user :: Int | String, service :: String, resource :: String } + - 10 type SetPermission = { shared_key :: String, user :: Int | String, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel } + - 11 type PasswordRecovery = { user :: Int | String, password_renew_key :: String, new_password :: String } + - 12 type AskPasswordRecovery = { user :: Int | String, email :: String } - 13 type SearchUser = { user :: String } - 14 type EditProfile = { token :: String, new_profile :: Hash(String, JSON::Any) } - - 15 type EditProfileContent = { token :: Maybe String, shared_key :: Maybe String, user :: Int32 | String | Nil, new_profile :: Hash(String, JSON::Any) } + - 15 type EditProfileContent = { token :: Maybe String, shared_key :: Maybe String, user :: Int | String | Nil, new_profile :: Hash(String, JSON::Any) } - 16 type EditContacts = { token :: String, email :: Maybe String, phone :: Maybe Phone.Phone } - - 17 type Delete = { shared_key :: Maybe String, login :: Maybe String, password :: Maybe String, user :: String | Int32 } + - 17 type Delete = { shared_key :: Maybe String, login :: Maybe String, password :: Maybe String, user :: String | Int } - 18 type GetContacts = { token :: String } -- Deletion can be triggered by either an admin or the user. Possible answers: - - 6 type UsersList = { users :: Array(UserPublic.UserPublic) } - - 7 type PermissionCheck = { user :: Int32, service :: String, resource :: String, permission :: AuthD::User::PermissionLevel } - - 8 type PermissionSet = { user :: Int32, service :: String, resource :: String, permission :: AuthD::User::PermissionLevel } - 11 type MatchingUsers = { users :: Array(UserPublic.UserPublic) } -} @@ -66,6 +64,9 @@ type User = { user :: UserPublic.UserPublic } type UserAdded = { user :: UserPublic.UserPublic } type UserEdited = { uid :: Int } type UserValidated = { user :: UserPublic.UserPublic } +type UsersList = { users :: Array UserPublic.UserPublic } +type PermissionCheck = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel } +type PermissionSet = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel } type Password = String type GetToken = { login :: String, password :: String } @@ -172,8 +173,8 @@ decode number string 12 -> error_management codecGotContacts GotContacts _ -> Left UnknownNumber -- 6 type UsersList = { users :: Array(UserPublic.UserPublic) } - -- 7 type PermissionCheck = { user :: Int32, service :: String, resource :: String, permission :: AuthD::User::PermissionLevel } - -- 8 type PermissionSet = { user :: Int32, service :: String, resource :: String, permission :: AuthD::User::PermissionLevel } + -- 7 type PermissionCheck = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel } + -- 8 type PermissionSet = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel } -- 11 type MatchingUsers = { users :: Array(UserPublic.UserPublic) } where -- Signature is required since the compiler's guess is wrong. diff --git a/src/App/PermissionLevel.purs b/src/App/PermissionLevel.purs new file mode 100644 index 0000000..eb55ee4 --- /dev/null +++ b/src/App/PermissionLevel.purs @@ -0,0 +1,39 @@ +-- | TODO: Phone module should include at least some sort of smart +-- | constructors, rejecting invalid phone numbers. +module App.PermissionLevel where + +import Prelude + +import Data.Codec.Argonaut (JsonCodec) +import Data.Codec.Argonaut as CA +import Data.Codec.Argonaut.Variant as CAV +import Data.Variant as V +import Data.Profunctor (dimap) +import Data.Either (Either(..)) +import Type.Proxy (Proxy(..)) + +data PermissionLevel + = None + | Read + | Edit + | Admin + +codec ∷ CA.JsonCodec PermissionLevel +codec = + dimap toVariant fromVariant $ CAV.variantMatch { permission: Right CA.string } + where + toVariant = case _ of + None → V.inj (Proxy ∷ _ "permission") "none" + Read → V.inj (Proxy ∷ _ "permission") "read" + Edit → V.inj (Proxy ∷ _ "permission") "edit" + Admin → V.inj (Proxy ∷ _ "permission") "admin" + + fromVariant = V.match + { permission: + \s -> case s of + "none" -> None + "read" -> Read + "edit" -> Edit + "admin" -> Admin + _ -> None + } diff --git a/src/App/UserPublic.purs b/src/App/UserPublic.purs index f8922b6..ef1426d 100644 --- a/src/App/UserPublic.purs +++ b/src/App/UserPublic.purs @@ -7,9 +7,11 @@ import Data.Codec.Argonaut as CA import Data.Codec.Argonaut.Record as CAR import Data.Newtype (class Newtype) --- | Currently not the real type. Lacks the 'profile' attribute. --- type UserPublic row = { login :: String, uid :: Int | row } -- profile :: JSON any -type UserPublic = { login :: String, uid :: Int } -- profile :: JSON any +-- | Currently not the real type. +-- | Lacks 'profile' and 'date_registration' attributes. +-- type UserPublic row = { login :: String, uid :: Int | row } +-- TODO: add profile :: JSON any, date_registration :: Maybe Time +type UserPublic = { login :: String, uid :: Int } -- | UserPublic.codec can be used to parse and encode public user info, -- | which can be exchanged in different messages.