gonito/Handler/YourAccount.hs

128 lines
5.0 KiB
Haskell
Raw Normal View History

2015-09-30 20:15:33 +02:00
module Handler.YourAccount where
import Import
import Yesod.Form.Bootstrap3 (BootstrapFormLayout (..), renderBootstrap3,
2016-02-15 20:36:01 +01:00
withSmallInput, bfs)
2015-09-30 20:15:33 +02:00
import Handler.Shared
import Handler.Extract
import Text.Regex.TDFA
2016-05-03 10:21:40 +02:00
import Data.Conduit
import Data.Conduit.Binary
import Control.Monad.Trans.Resource (runResourceT)
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
2015-09-30 20:15:33 +02:00
getYourAccountR :: Handler Html
getYourAccountR = do
userId <- requireAuthId
user <- runDB $ get404 userId
2015-11-11 22:37:25 +01:00
keyS <- runDB $ selectFirst [PublicKeyUser ==. userId] []
let key = publicKeyPubkey <$> entityVal <$> keyS
(formWidget, formEnctype) <- generateFormPost (yourAccountForm (userName user) (userLocalId user) key)
2015-09-30 20:15:33 +02:00
let submission = Nothing :: Maybe (Import.FileInfo, Text)
handlerName = "getYourAccountR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Your account"
$(widgetFile "your-account")
postYourAccountR :: Handler Html
postYourAccountR = do
((result, formWidget), formEnctype) <- runFormPost (yourAccountForm Nothing Nothing Nothing)
2015-09-30 20:15:33 +02:00
let handlerName = "postYourAccountR" :: Text
accountData = case result of
FormSuccess res -> Just res
_ -> Nothing
2016-05-03 10:21:40 +02:00
Just (name, localId, sshPubKey, avatarFile) = accountData
2015-09-30 20:15:33 +02:00
userId <- requireAuthId
2016-05-03 10:21:40 +02:00
updateUserAccount userId name localId sshPubKey avatarFile
2015-09-30 20:15:33 +02:00
user <- runDB $ get404 userId
defaultLayout $ do
aDomId <- newIdent
setTitle "Your account"
$(widgetFile "your-account")
2016-05-03 10:21:40 +02:00
yourAccountForm :: Maybe Text -> Maybe Text -> Maybe Text -> Form (Maybe Text, Maybe Text, Maybe Text, Maybe FileInfo)
yourAccountForm maybeName maybeLocalId maybeSshPubKey = renderBootstrap3 BootstrapBasicForm $ (,,,)
2016-02-15 20:36:01 +01:00
<$> aopt textField (bfs MsgAccountName) (Just maybeName)
<*> aopt textField (bfs MsgId) (Just maybeLocalId)
<*> aopt textField (bfs MsgSshPubKey) (Just maybeSshPubKey)
2016-05-03 10:21:40 +02:00
<*> fileAFormOpt (bfs MsgAvatar)
localIdRegexp = makeRegexOpts defaultCompOpt{newSyntax=True} defaultExecOpt ("\\`[a-z][-a-z0-9]{0,31}\\'" ::String)
unwantedLocalIds :: [Text]
unwantedLocalIds = ["git",
"gitolite",
"admin",
"root",
"filipg"]
isLocalIdAcceptable :: Text -> Bool
isLocalIdAcceptable localId =
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
2016-05-03 10:21:40 +02:00
updateUserAccount :: Key User -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe FileInfo -> Handler ()
updateUserAccount userId name maybeLocalId maybeSshPubKey maybeAvatarFile = do
updateJustName userId name
2016-05-03 10:21:40 +02:00
updateAvatar userId maybeAvatarFile
updateLocalIdAndPubKey userId maybeLocalId maybeSshPubKey
2016-05-03 10:21:40 +02:00
updateAvatar :: Key User -> Maybe FileInfo -> Handler ()
updateAvatar _ Nothing = return ()
updateAvatar userId (Just avatarFile) = do
fileBytes <- runResourceT $ fileSource avatarFile $$ sinkLbs
runDB $ update userId [UserAvatar =. Just (S.pack . L.unpack $ fileBytes)]
updateLocalIdAndPubKey :: Key User -> Maybe Text -> Maybe Text -> Handler ()
updateLocalIdAndPubKey userId (Just localId) maybeSshPubKey = do
if isLocalIdAcceptable localId
then
do
otherTheSame <- runDB $ selectFirst [UserLocalId ==. (Just localId), UserId !=. userId] []
case otherTheSame of
Just _ -> do
setMessage $ toHtml ("ID already used" :: Text)
Nothing -> do
user <- runDB $ get404 userId
case userLocalId user of
Just prevLocalId -> do
unless (prevLocalId == localId) $ setMessage $ toHtml ("only the administrator can change your ID" :: Text)
2016-03-14 21:12:54 +01:00
Nothing -> do
runDB $ update userId [UserLocalId =. Just localId]
setMessage $ toHtml ("ID set" :: Text)
2015-11-11 22:37:25 +01:00
runDB $ deleteWhere [PublicKeyUser ==. userId]
case maybeSshPubKey of
Just key -> do
runDB $ insert $ PublicKey {
publicKeyUser=userId,
publicKeyPubkey=key }
2016-03-14 21:12:54 +01:00
setMessage $ toHtml ("SSH public key added; now it may take 10 minutes for the keys to be active, please be patient" :: Text)
2015-11-11 22:37:25 +01:00
return ()
Nothing -> return ()
else
setMessage $ toHtml ("unexpected ID (use only lower-case letters, digits and hyphens, start with a letter)" :: Text)
updateLocalIdAndPubKey _ Nothing (Just _) = do
setMessage $ toHtml ("SSH public key cannot be added without an ID" :: Text)
updateLocalIdAndPubKey _ Nothing Nothing = return ()
updateJustName :: Key User -> Maybe Text -> Handler ()
updateJustName userId name = runDB $ update userId [UserName =. name]
2016-05-03 10:21:40 +02:00
getAvatarR :: UserId -> Handler TypedContent
getAvatarR userId = do
user <- runDB $ get404 userId
case userAvatar user of
Just avatarBytes -> do
addHeader "Content-Disposition" "attachment; filename=\"avatar.png\""
sendResponse (typePng, toContent avatarBytes)
Nothing -> do
sendFile typeSvg "static/images/male-avatar.svg"