Delete rejected applications immediately

This commit is contained in:
Saku Laesvuori 2023-09-28 15:45:02 +03:00
parent eeba024c1f
commit 72b3e25913
Signed by: slaesvuo
GPG Key ID: 257D284A2A1D3A32
6 changed files with 24 additions and 27 deletions

View File

@ -0,0 +1,16 @@
-- migrate:up
delete from "users"
where "rejected" is not null or "seceded" is not null or "toBeDeleted" is not null;
alter table "users"
drop "rejected",
drop "seceded",
drop "toBeDeleted";
-- migrate:down
alter table "users"
add "rejected" timestamp,
add "seceded" timestamp,
add "toBeDeleted" timestamp;

View File

@ -27,7 +27,6 @@ import Data.Maybe (fromJust)
import Data.Morpheus.Server (deriveApp, runApp) import Data.Morpheus.Server (deriveApp, runApp)
import Data.Morpheus.Server.Types (defaultRootResolver, RootResolver(..), Undefined) import Data.Morpheus.Server.Types (defaultRootResolver, RootResolver(..), Undefined)
import Data.Morpheus.Types (Arg(..), GQLType, GQLError, App) import Data.Morpheus.Types (Arg(..), GQLType, GQLError, App)
import Data.Time (nominalDay)
import Database.Persist (Entity, entityVal, entityKey, get, (=.)) import Database.Persist (Entity, entityVal, entityKey, get, (=.))
import Datarekisteri.Core.Types import Datarekisteri.Core.Types
import Datarekisteri.Backend.DB import Datarekisteri.Backend.DB
@ -69,8 +68,7 @@ dbUserToUser user = let id = entityToID user
, homeplace = pure homeplace , homeplace = pure homeplace
, registered = pure dBUserRegistered , registered = pure dBUserRegistered
, accepted = pure dBUserAccepted , accepted = pure dBUserAccepted
, seceded = pure dBUserSeceded , isMember = pure $ isJust dBUserAccepted
, isMember = pure $ isJust dBUserAccepted && not (isJust dBUserSeceded)
, permissions = pure dBUserPermissions , permissions = pure dBUserPermissions
, application = pure application , application = pure application
} }
@ -107,7 +105,6 @@ newUser :: (MonadEmail m, MonadDB m, MonadRandom m, MonadTime m, MonadError GQLE
ApplicationData -> m UserID ApplicationData -> m UserID
newUser (ApplicationData {..}) = do newUser (ApplicationData {..}) = do
time <- currentTime time <- currentTime
verificationExpires <- verificationExpireTime
secret <- genVerificationSecret secret <- genVerificationSecret
passwordHash <- hashPassword password passwordHash <- hashPassword password
permissions <- defaultPermissions permissions <- defaultPermissions
@ -117,12 +114,9 @@ newUser (ApplicationData {..}) = do
let memberData = MemberData { nickname = nickname >>= \x -> if T.null x then Nothing else Just x, ..} let memberData = MemberData { nickname = nickname >>= \x -> if T.null x then Nothing else Just x, ..}
user <- addUser $ DBUser user <- addUser $ DBUser
{ dBUserRegistered = time { dBUserRegistered = time
, dBUserToBeDeleted = Just $ verificationExpires
, dBUserPasswordCrypt = passwordHash , dBUserPasswordCrypt = passwordHash
, dBUserPermissions = permissions , dBUserPermissions = permissions
, dBUserAccepted = Nothing , dBUserAccepted = Nothing
, dBUserSeceded = Nothing
, dBUserRejected = Nothing
, dBUserMemberData = toJSON memberData , dBUserMemberData = toJSON memberData
} }
verification <- addEmailVerification secret verification <- addEmailVerification secret
@ -134,9 +128,6 @@ newUser (ApplicationData {..}) = do
sendVerificationSecret email sendVerificationSecret email
return user return user
verificationExpireTime :: MonadTime m => m Time
verificationExpireTime = addTime (7 * nominalDay) <$> currentTime
genVerificationSecret :: MonadRandom m => m Text genVerificationSecret :: MonadRandom m => m Text
genVerificationSecret = T.intercalate "-" . T.chunksOf 4 . base32 <$> getRandomBytes 10 genVerificationSecret = T.intercalate "-" . T.chunksOf 4 . base32 <$> getRandomBytes 10
@ -216,9 +207,9 @@ rejectApplication user = void $ do
case maybeEmail of case maybeEmail of
Nothing -> throwError $ "No valid application for " <> show user <> "!" Nothing -> throwError $ "No valid application for " <> show user <> "!"
Just email -> do Just email -> do
time <- currentTime applicationDeleted <- deleteApplication user
markAsRejected user time when applicationDeleted $
void $ sendApplicationRejectedEmail $ dBEmailEmail $ entityVal email sendApplicationRejectedEmail $ dBEmailEmail $ entityVal email
resolveQuery :: (MonadRequest m, MonadDB m, MonadError GQLError m, MonadPermissions m) => Query m resolveQuery :: (MonadRequest m, MonadDB m, MonadError GQLError m, MonadPermissions m) => Query m
resolveQuery = Query resolveQuery = Query
@ -281,7 +272,6 @@ data User m = User
, homeplace :: m Text , homeplace :: m Text
, registered :: m Time , registered :: m Time
, accepted :: m (Maybe Time) , accepted :: m (Maybe Time)
, seceded :: m (Maybe Time)
, permissions :: m Text , permissions :: m Text
, isMember :: m Bool , isMember :: m Bool
, application :: m Text , application :: m Text

View File

@ -29,9 +29,6 @@ DBUser sql=users
passwordCrypt PasswordHash passwordCrypt PasswordHash
permissions Text permissions Text
accepted (Maybe Time) accepted (Maybe Time)
rejected (Maybe Time)
seceded (Maybe Time)
toBeDeleted (Maybe Time)
memberData Value sqltype=jsonb memberData Value sqltype=jsonb
deriving (Show) deriving (Show)

View File

@ -89,10 +89,9 @@ hasVerifiedEmail userId = not_ $ isNothing $ subSelect $ do
isApplicant :: SqlExpr (Entity DBUser) -> SqlExpr (Value Bool) isApplicant :: SqlExpr (Entity DBUser) -> SqlExpr (Value Bool)
isApplicant user = isNothing (user ^. DBUserAccepted) isApplicant user = isNothing (user ^. DBUserAccepted)
&&. hasVerifiedEmail (user ^. DBUserId) &&. hasVerifiedEmail (user ^. DBUserId)
&&. isNothing (user ^. DBUserRejected)
isMember :: SqlExpr (Entity DBUser) -> SqlExpr (Value Bool) isMember :: SqlExpr (Entity DBUser) -> SqlExpr (Value Bool)
isMember user = not_ (isNothing (user ^. DBUserAccepted)) &&. isNothing (user ^. DBUserSeceded) isMember user = not_ $ isApplicant user
verifyEmailSecret :: MonadDB m => Text -> m Bool verifyEmailSecret :: MonadDB m => Text -> m Bool
verifyEmailSecret secret = runQuery $ do verifyEmailSecret secret = runQuery $ do
@ -166,9 +165,9 @@ markAsAccepted userID time = runQuery $ update $ \user -> do
set user [DBUserAccepted =. just (val time)] set user [DBUserAccepted =. just (val time)]
where_ $ user ^. DBUserId ==. val (toDBKey userID) &&. isApplicant user where_ $ user ^. DBUserId ==. val (toDBKey userID) &&. isApplicant user
markAsRejected :: MonadDB m => UserID -> Time -> m () deleteApplication :: MonadDB m => UserID -> m Bool
markAsRejected userID time = runQuery $ update $ \user -> do deleteApplication userID = fmap (> 0) $ runQuery $ deleteCount $ do
set user [DBUserRejected =. just (val time)] user <- from $ table @DBUser
where_ $ user ^. DBUserId ==. val (toDBKey userID) &&. isApplicant user where_ $ user ^. DBUserId ==. val (toDBKey userID) &&. isApplicant user
updateUserData :: MonadDB m => UserID -> [Persist.Update DBUser] -> [UserUpdate] -> m UserID updateUserData :: MonadDB m => UserID -> [Persist.Update DBUser] -> [UserUpdate] -> m UserID

View File

@ -33,12 +33,9 @@ addUserMain AddUserOpts {..} = do
passwordHash <- putStr "Password: " >> liftIO (withoutInputEcho getLine) >>= hashPassword passwordHash <- putStr "Password: " >> liftIO (withoutInputEcho getLine) >>= hashPassword
userID <- addUser $ DBUser userID <- addUser $ DBUser
{ dBUserRegistered = time { dBUserRegistered = time
, dBUserToBeDeleted = Nothing
, dBUserPasswordCrypt = passwordHash , dBUserPasswordCrypt = passwordHash
, dBUserPermissions = show addUserPermissions , dBUserPermissions = show addUserPermissions
, dBUserAccepted = Just time , dBUserAccepted = Just time
, dBUserSeceded = Nothing
, dBUserRejected = Nothing
, dBUserMemberData = toJSON $ MemberData , dBUserMemberData = toJSON $ MemberData
{ nickname = addUserNickname { nickname = addUserNickname
, name = addUserName , name = addUserName

View File

@ -50,7 +50,6 @@ type User {
homeplace: String! homeplace: String!
registered: Time! registered: Time!
accepted: Time accepted: Time
seceded: Time
permissions: String! permissions: String!
isMember: Boolean! isMember: Boolean!
application: String! application: String!
@ -76,4 +75,3 @@ type Mutation {
accept(user: UserID!): Unit! accept(user: UserID!): Unit!
reject(user: UserID!): Unit! reject(user: UserID!): Unit!
} }