add avatars
This commit is contained in:
parent
30b7db5714
commit
e80f72d741
@ -186,6 +186,7 @@ instance YesodAuth App where
|
|||||||
, userIsAdmin = False
|
, userIsAdmin = False
|
||||||
, userLocalId = Nothing
|
, userLocalId = Nothing
|
||||||
, userIsAnonymous = False
|
, userIsAnonymous = False
|
||||||
|
, userAvatar = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
-- You can add other plugins like BrowserID, email or OAuth here
|
-- You can add other plugins like BrowserID, email or OAuth here
|
||||||
|
@ -11,7 +11,7 @@ import Handler.ShowChallenge
|
|||||||
|
|
||||||
import Yesod.Form.Bootstrap3
|
import Yesod.Form.Bootstrap3
|
||||||
|
|
||||||
data TimelineItem = TimelineItem UTCTime User Markup
|
data TimelineItem = TimelineItem UTCTime (Entity User) Markup
|
||||||
|
|
||||||
getTime (TimelineItem stamp _ _) = stamp
|
getTime (TimelineItem stamp _ _) = stamp
|
||||||
|
|
||||||
@ -19,8 +19,11 @@ class ToTimelineItem a where
|
|||||||
timelineWhen :: a -> UTCTime
|
timelineWhen :: a -> UTCTime
|
||||||
|
|
||||||
timelineWhoId :: a -> UserId
|
timelineWhoId :: a -> UserId
|
||||||
timelineWho :: a -> Handler User
|
timelineWho :: a -> Handler (Entity User)
|
||||||
timelineWho sItem = runDB $ get404 $ timelineWhoId sItem
|
timelineWho sItem = do
|
||||||
|
let userId = timelineWhoId sItem
|
||||||
|
user <- runDB $ get404 userId
|
||||||
|
return $ Entity userId user
|
||||||
|
|
||||||
timelineWhat :: a -> Handler Markup
|
timelineWhat :: a -> Handler Markup
|
||||||
toTimelineItem :: a -> Handler TimelineItem
|
toTimelineItem :: a -> Handler TimelineItem
|
||||||
|
@ -9,6 +9,12 @@ import Handler.Extract
|
|||||||
|
|
||||||
import Text.Regex.TDFA
|
import Text.Regex.TDFA
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
getYourAccountR :: Handler Html
|
getYourAccountR :: Handler Html
|
||||||
getYourAccountR = do
|
getYourAccountR = do
|
||||||
userId <- requireAuthId
|
userId <- requireAuthId
|
||||||
@ -30,20 +36,21 @@ postYourAccountR = do
|
|||||||
accountData = case result of
|
accountData = case result of
|
||||||
FormSuccess res -> Just res
|
FormSuccess res -> Just res
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
Just (name, localId, sshPubKey) = accountData
|
Just (name, localId, sshPubKey, avatarFile) = accountData
|
||||||
userId <- requireAuthId
|
userId <- requireAuthId
|
||||||
updateUserAccount userId name localId sshPubKey
|
updateUserAccount userId name localId sshPubKey avatarFile
|
||||||
user <- runDB $ get404 userId
|
user <- runDB $ get404 userId
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
aDomId <- newIdent
|
aDomId <- newIdent
|
||||||
setTitle "Your account"
|
setTitle "Your account"
|
||||||
$(widgetFile "your-account")
|
$(widgetFile "your-account")
|
||||||
|
|
||||||
yourAccountForm :: Maybe Text -> Maybe Text -> Maybe Text -> Form (Maybe Text, Maybe Text, Maybe Text)
|
yourAccountForm :: Maybe Text -> Maybe Text -> Maybe Text -> Form (Maybe Text, Maybe Text, Maybe Text, Maybe FileInfo)
|
||||||
yourAccountForm maybeName maybeLocalId maybeSshPubKey = renderBootstrap3 BootstrapBasicForm $ (,,)
|
yourAccountForm maybeName maybeLocalId maybeSshPubKey = renderBootstrap3 BootstrapBasicForm $ (,,,)
|
||||||
<$> aopt textField (bfs MsgAccountName) (Just maybeName)
|
<$> aopt textField (bfs MsgAccountName) (Just maybeName)
|
||||||
<*> aopt textField (bfs MsgId) (Just maybeLocalId)
|
<*> aopt textField (bfs MsgId) (Just maybeLocalId)
|
||||||
<*> aopt textField (bfs MsgSshPubKey) (Just maybeSshPubKey)
|
<*> aopt textField (bfs MsgSshPubKey) (Just maybeSshPubKey)
|
||||||
|
<*> fileAFormOpt (bfs MsgAvatar)
|
||||||
|
|
||||||
localIdRegexp = makeRegexOpts defaultCompOpt{newSyntax=True} defaultExecOpt ("\\`[a-z][-a-z0-9]{0,31}\\'" ::String)
|
localIdRegexp = makeRegexOpts defaultCompOpt{newSyntax=True} defaultExecOpt ("\\`[a-z][-a-z0-9]{0,31}\\'" ::String)
|
||||||
|
|
||||||
@ -58,11 +65,19 @@ isLocalIdAcceptable :: Text -> Bool
|
|||||||
isLocalIdAcceptable localId =
|
isLocalIdAcceptable localId =
|
||||||
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
|
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
|
||||||
|
|
||||||
updateUserAccount :: Key User -> Maybe Text -> Maybe Text -> Maybe Text -> Handler ()
|
updateUserAccount :: Key User -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe FileInfo -> Handler ()
|
||||||
updateUserAccount userId name maybeLocalId maybeSshPubKey = do
|
updateUserAccount userId name maybeLocalId maybeSshPubKey maybeAvatarFile = do
|
||||||
updateJustName userId name
|
updateJustName userId name
|
||||||
|
updateAvatar userId maybeAvatarFile
|
||||||
updateLocalIdAndPubKey userId maybeLocalId maybeSshPubKey
|
updateLocalIdAndPubKey userId maybeLocalId maybeSshPubKey
|
||||||
|
|
||||||
|
|
||||||
|
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 :: Key User -> Maybe Text -> Maybe Text -> Handler ()
|
||||||
updateLocalIdAndPubKey userId (Just localId) maybeSshPubKey = do
|
updateLocalIdAndPubKey userId (Just localId) maybeSshPubKey = do
|
||||||
if isLocalIdAcceptable localId
|
if isLocalIdAcceptable localId
|
||||||
@ -99,3 +114,14 @@ updateLocalIdAndPubKey _ Nothing Nothing = return ()
|
|||||||
|
|
||||||
updateJustName :: Key User -> Maybe Text -> Handler ()
|
updateJustName :: Key User -> Maybe Text -> Handler ()
|
||||||
updateJustName userId name = runDB $ update userId [UserName =. name]
|
updateJustName userId name = runDB $ update userId [UserName =. name]
|
||||||
|
|
||||||
|
|
||||||
|
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"
|
||||||
|
@ -6,6 +6,7 @@ User
|
|||||||
isAdmin Bool default=False
|
isAdmin Bool default=False
|
||||||
localId Text Maybe
|
localId Text Maybe
|
||||||
isAnonymous Bool default=False
|
isAnonymous Bool default=False
|
||||||
|
avatar ByteString Maybe
|
||||||
deriving Typeable
|
deriving Typeable
|
||||||
PublicKey
|
PublicKey
|
||||||
user UserId
|
user UserId
|
||||||
|
@ -26,3 +26,4 @@
|
|||||||
/make-public/#SubmissionId MakePublicR GET
|
/make-public/#SubmissionId MakePublicR GET
|
||||||
|
|
||||||
/account YourAccountR GET POST
|
/account YourAccountR GET POST
|
||||||
|
/avatar/#UserId AvatarR GET
|
||||||
|
@ -123,6 +123,8 @@ library
|
|||||||
, wai-handler-fastcgi
|
, wai-handler-fastcgi
|
||||||
, blaze-markup
|
, blaze-markup
|
||||||
, blaze-html
|
, blaze-html
|
||||||
|
, conduit-extra
|
||||||
|
, resourcet
|
||||||
|
|
||||||
executable gonito
|
executable gonito
|
||||||
if flag(library-only)
|
if flag(library-only)
|
||||||
|
@ -23,3 +23,4 @@ Search: search
|
|||||||
GitCommitSha1: Git commit SHA1 hash
|
GitCommitSha1: Git commit SHA1 hash
|
||||||
CommentText: Write a comment
|
CommentText: Write a comment
|
||||||
Send: Send
|
Send: Send
|
||||||
|
Avatar: avatar
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
$case item
|
$case item
|
||||||
$of TimelineItem when who what
|
$of TimelineItem when (Entity whoId who) what
|
||||||
<div class="row timeline-item">
|
<div class="row timeline-item">
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<div class="timeline-item-thumbnail">
|
<div class="timeline-item-thumbnail">
|
||||||
<img class="img-responsive user-photo" src="/static/images/male-avatar.svg">
|
<img class="img-responsive user-photo" src=@{AvatarR whoId}>
|
||||||
<div class="col-sm-11">
|
<div class="col-sm-11">
|
||||||
<div .timeline-item-panel>
|
<div .timeline-item-panel>
|
||||||
<div class="timeline-item-panel-heading">
|
<div class="timeline-item-panel-heading">
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div id="main" role="main">
|
<div id="main" role="main">
|
||||||
<h2>Your account
|
<h2>Your account
|
||||||
<hr>
|
<hr>
|
||||||
|
<img style="max-width:80px;padding-bottom:30px" src=@{AvatarR userId}>
|
||||||
<form method=post action=@{YourAccountR}#form enctype=#{formEnctype}>
|
<form method=post action=@{YourAccountR}#form enctype=#{formEnctype}>
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
<button .btn .btn-primary type="submit">
|
<button .btn .btn-primary type="submit">
|
||||||
|
Loading…
Reference in New Issue
Block a user