packages feed

lambdacms-core 0.0.7.3 → 0.0.8.0

raw patch · 13 files changed

+166/−174 lines, 13 filesnew-uploader

Files

CHANGES.md view
@@ -4,6 +4,9 @@ #### dev * ... +#### 0.0.8.0+* Fixed action logging to also work outside of LambdaCms.Core+ #### 0.0.7.2 * Fixed broken package 
LambdaCms/Core.hs view
@@ -3,12 +3,13 @@ {-# LANGUAGE OverloadedStrings     #-} {-# LANGUAGE TemplateHaskell       #-} {-# LANGUAGE ViewPatterns          #-}+{-# OPTIONS_GHC -fno-warn-orphans  #-}  module LambdaCms.Core     ( module Export     ) where -import           Database.Persist.Sql             (SqlBackend)+import           Database.Persist.Sql             ()  import           LambdaCms.Core.Classes           as Export import           LambdaCms.Core.Foundation        as Export
LambdaCms/Core/Foundation.hs view
@@ -3,29 +3,27 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings     #-} {-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE RecordWildCards       #-} {-# LANGUAGE TemplateHaskell       #-} {-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE ViewPatterns          #-}+{-# OPTIONS_GHC -fno-warn-orphans  #-}  module LambdaCms.Core.Foundation where -import           Control.Applicative        ((<$>)) import           Control.Arrow              ((&&&))-import           Control.Monad              (filterM) import           Data.ByteString            (ByteString) import qualified Data.ByteString.Lazy.Char8 as LB (concat, toStrict)-import           Data.Int import           Data.List                  (find, sortBy) import           Data.Maybe                 (catMaybes, isJust) import           Data.Monoid                ((<>)) import           Data.Ord                   (comparing)-import           Data.Set                   (Set, empty, fromList, intersection)-import qualified Data.Set                   as S (null)+import           Data.Set                   (Set)+import qualified Data.Set                   as S (empty, intersection, null) import           Data.Text                  (Text, concat, intercalate, pack,                                              unpack)-import qualified Data.Text                  as T import           Data.Text.Encoding         (decodeUtf8)-import           Data.Time                  (getCurrentTime, utc)+import           Data.Time                  (getCurrentTime) import           Data.Time.Format.Human import           Data.Traversable           (forM) import           Database.Persist.Sql       (SqlBackend)@@ -40,8 +38,6 @@ import           Network.Mail.Mime import           Network.Wai                (requestMethod) import           Text.Hamlet                (hamletFile)-import           Text.Julius                (juliusFile)-import           Text.Lucius                (luciusFile) import           Yesod import           Yesod.Auth @@ -112,7 +108,7 @@      -- | Gives the default roles a user should have on create     defaultRoles :: HandlerT master IO (Set (Roles master))-    defaultRoles = return empty+    defaultRoles = return S.empty      -- | See if a user is authorized to perform an action.     isAuthorizedTo :: master                     -- Needed to make function injective.@@ -124,7 +120,7 @@     isAuthorizedTo _ (Just _)    Authenticated   = Authorized     isAuthorizedTo _ Nothing     _               = AuthenticationRequired     isAuthorizedTo _ (Just urs) (Roles rrs)    = do-      case (not . S.null $ urs `intersection` rrs) of+      case (not . S.null $ urs `S.intersection` rrs) of         True -> Authorized -- non-empty intersection means authorized         False -> Unauthorized "Access denied." @@ -152,7 +148,7 @@     welcomeWidget :: Maybe (WidgetT master IO ())     welcomeWidget = Just $ do         Entity _ user <- handlerToWidget requireAuth-        renderMessage <- getMessageRender+        messageRenderer <- getMessageRender         $(widgetFile "admin-welcome")      -- | Applies some form of layout to the contents of an admin section page.@@ -348,51 +344,39 @@         (cparts, _) = renderRoute cr         rrs = map ((fst . renderRoute) &&& id) rs         orrs = reverse $ sortBy (comparing (length . fst)) rrs-        cmp (route, _) = route == (take (length route) cparts)+        cmp (route', _) = route' == (take (length route') cparts) routeBestMatch _ _ = Nothing -class LambdaCmsLoggable entity where-    logMessage :: LambdaCmsAdmin master => master -> ByteString -> entity -> Maybe (SomeMessage master)-    logRoute :: LambdaCmsAdmin master => master -> Key entity -> Maybe (Route master)--instance LambdaCmsLoggable User where-    logMessage _ "POST"       = jsm Msg.LogCreatedUser-    logMessage _ "PATCH"      = jsm Msg.LogUpdatedUser-    logMessage _ "DELETE"     = jsm Msg.LogDeletedUser-    logMessage _ "CHPASS"     = jsm Msg.LogChangedPasswordUser-    logMessage _ "RQPASS"     = jsm Msg.LogRequestedPasswordUser-    logMessage _ "DEACTIVATE" = jsm Msg.LogDeactivatedUser-    logMessage _ "ACTIVATE"   = jsm Msg.LogActivatedUser-    logMessage _ _            = const Nothing+class LambdaCmsLoggable master entity where+    logMessage :: master -> ByteString -> entity -> [(Text, Text)] -    logRoute _ userId = Just . coreR . UserAdminR $ UserAdminEditR userId+instance LambdaCmsAdmin master => LambdaCmsLoggable master User where+    logMessage y "POST"       = translateUserLogs y Msg.LogCreatedUser+    logMessage y "PATCH"      = translateUserLogs y Msg.LogUpdatedUser+    logMessage y "DELETE"     = translateUserLogs y Msg.LogDeletedUser+    logMessage y "CHPASS"     = translateUserLogs y Msg.LogChangedPasswordUser+    logMessage y "RQPASS"     = translateUserLogs y Msg.LogRequestedPasswordUser+    logMessage y "DEACTIVATE" = translateUserLogs y Msg.LogDeactivatedUser+    logMessage y "ACTIVATE"   = translateUserLogs y Msg.LogActivatedUser+    logMessage _ _            = const [] -jsm msg = Just . SomeMessage . msg . userName+translateUserLogs :: forall b master.+                     ( LambdaCmsAdmin master+                     , RenderMessage master b+                     ) => master -> (Text -> b) -> User -> [(Text, Text)]+translateUserLogs y msg u = map (id &&& messageFor) $ renderLanguages y+    where messageFor lang = renderMessage y [lang] . msg $ userName u -logAction :: (LambdaCmsAdmin master, LambdaCmsLoggable entity) => Entity entity -> HandlerT master IO ()-logAction (Entity objectId object) = do-    wai <- waiRequest+logUser :: LambdaCmsAdmin master => User -> HandlerT master IO [(Text, Text)]+logUser user = do     y <- getYesod-    authId <- requireAuthId-    timeNow <- liftIO getCurrentTime-    ident <- liftIO generateUUID+    method <- waiRequest >>= return . requestMethod+    return $ logMessage y method user -    let method = requestMethod wai-        langs = renderLanguages y-        mRoute = logRoute y objectId-        mPath = T.intercalate "/" . fst . renderRoute <$> mRoute+logAction :: LambdaCmsAdmin master => [(Text, Text)] -> HandlerT master IO ()+logAction messages = do+    actionLogUserId    <- requireAuthId+    actionLogCreatedAt <- liftIO getCurrentTime+    actionLogIdent     <- liftIO generateUUID -    mapM_ (saveLog y ident method timeNow object mPath authId) langs-    where-        saveLog y ident method time entity mPath userId lang = case logMessage y method entity of-            Just message' -> do-                let message = renderMessage y [lang] message'-                runDB . insert_ $ ActionLog-                                  { actionLogIdent = ident-                                  , actionLogUserId = userId-                                  , actionLogMessage = message-                                  , actionLogLang = lang-                                  , actionLogPath = mPath-                                  , actionLogCreatedAt = time-                                  }-            Nothing -> return ()+    mapM_ (\(actionLogLang, actionLogMessage) -> runDB . insert_ $ ActionLog {..}) messages
LambdaCms/Core/Handler/ActionLog.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE KindSignatures      #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE QuasiQuotes         #-} {-# LANGUAGE RankNTypes          #-}@@ -9,14 +10,12 @@        , getActionLogAdminUserR        ) where -import           Control.Applicative    ((<$>)) import           Data.Int               (Int64) import           Data.List              (intersect) import           Data.Lists             (firstOr)-import           Data.Maybe             (fromJust, maybe)+import           Data.String import           Data.Text import           Data.Time.Clock-import           Data.Time.Clock import           Data.Time.Format.Human import           Database.Esqueleto     ((^.)) import qualified Database.Esqueleto     as E@@ -24,7 +23,6 @@ import qualified LambdaCms.Core.Message as Msg import           Network.Wai import           Text.Read              (readEither)-import           Yesod.Auth             (requireAuthId) import           Yesod.Core import           Yesod.Core.Types @@ -36,10 +34,10 @@                }  instance ToJSON JsonLog where-    toJSON (JsonLog message username userUrl timeAgo) = object [ "message" .= message-                                                               , "username" .= username-                                                               , "userUrl" .= userUrl-                                                               , "timeAgo" .= timeAgo+    toJSON (JsonLog msg username' userUrl' timeAgo') = object [ "message" .= msg+                                                               , "username" .= username'+                                                               , "userUrl" .= userUrl'+                                                               , "timeAgo" .= timeAgo'                                                                ]  resolveApproot :: Yesod master => master -> Request -> ResolvedApproot@@ -50,13 +48,19 @@         ApprootMaster f -> f master         ApprootRequest f -> f master req -logToJsonLog can renderUrl toAgo (Entity _ log, Entity userId user) = do+logToJsonLog :: (LambdaCmsAdmin master, IsString method, Monad m) =>+                (Route master -> method -> Maybe r)+                -> (r -> Text)+                -> (UTCTime -> String)+                -> (Entity ActionLog, Entity User)+                -> m JsonLog+logToJsonLog can renderUrl toAgo (Entity _ log', Entity userId user) = do     let mUserUrl = renderUrl <$> (can (coreR $ UserAdminR $ UserAdminEditR userId) "GET")     return $ JsonLog-             { message = actionLogMessage log+             { message = actionLogMessage log'              , username = userName user              , userUrl = mUserUrl-             , timeAgo = toAgo $ actionLogCreatedAt log+             , timeAgo = toAgo $ actionLogCreatedAt log'              }  getCurrentLang :: CoreHandler Text@@ -69,15 +73,15 @@ getActionLogs mUserId limit offset lang = do     logs <- lift $ runDB             $ E.select-            $ E.from $ \(log `E.InnerJoin` user) -> do-                E.on $ log ^. ActionLogUserId E.==. user ^. UserId-                E.where_ $ log ^. ActionLogLang E.==. E.val lang+            $ E.from $ \(log' `E.InnerJoin` user) -> do+                E.on $ log' ^. ActionLogUserId E.==. user ^. UserId+                E.where_ $ log' ^. ActionLogLang E.==. E.val lang                 maybe (return ()) (E.where_ . (E.==.) (user ^. UserId) . E.val) mUserId                 E.limit limit                 E.offset offset-                E.orderBy [E.desc (log ^. ActionLogCreatedAt)]+                E.orderBy [E.desc (log' ^. ActionLogCreatedAt)] -                return (log, user)+                return (log', user)     return logs  getActionLogAdminJson :: Maybe UserId -> CoreHandler TypedContent
LambdaCms/Core/Handler/User.hs view
@@ -22,27 +22,23 @@ import           LambdaCms.Core.Import import           LambdaCms.Core.Message        (CoreMessage) import qualified LambdaCms.Core.Message        as Msg-import           LambdaCms.I18n import           Yesod                         (Route)-import           Yesod.Auth                    (Creds (..), requireAuthId, setCreds)--import qualified Data.Text                     as T (breakOn, concat, length,-                                                     pack, takeWhile)-import qualified Data.Text.Lazy                as LT (Text)-import           Data.Time.Format+import           Yesod.Auth                    (Creds (..), requireAuthId,+                                                setCreds)  import           Control.Arrow                 ((&&&))-import           Data.Maybe                    (fromJust, fromMaybe, isJust)+import           Data.Maybe                    (fromJust, isJust, fromMaybe) import qualified Data.Set                      as S+import qualified Data.Text                     as T (breakOn, length, pack,+                                                     takeWhile) import           Data.Time.Clock import           Data.Time.Format.Human import           Network.Mail.Mime-import           System.Locale import           Text.Blaze.Html.Renderer.Text (renderHtml)  -- data type for a form to change a user's password data ComparePassword = ComparePassword { originalPassword :: Text-                                       , confirmPassword  :: Text+                                       , _confirmPassword  :: Text                                        } deriving (Show, Eq)  accountSettingsForm :: LambdaCmsAdmin master@@ -198,8 +194,8 @@         FormSuccess (user, roles) -> do             userId <- lift $ runDB $ insert user             lift $ setUserRoles userId (S.fromList roles)-            _ <- sendAccountActivationToken (Entity userId user)-            _ <- lift . logAction $ Entity userId user+            sendAccountActivationToken (Entity userId user)+            lift $ logUser user >>= logAction             lift $ setMessageI Msg.SuccessCreate             redirectUltDest $ UserAdminR UserAdminIndexR         _ -> lift $ do@@ -237,7 +233,7 @@         FormSuccess (updatedUser, updatedRoles) -> do             _ <- lift $ runDB $ update userId [UserName =. userName updatedUser, UserEmail =. userEmail updatedUser]             lift $ setUserRoles userId (S.fromList updatedRoles)-            _ <- lift . logAction $ Entity userId updatedUser+            lift $ logUser user >>= logAction             lift $ setMessageI Msg.SuccessReplace             redirect $ UserAdminR $ UserAdminEditR userId         _ -> lift $ do@@ -263,7 +259,7 @@             case formResult of                 FormSuccess f -> do                     _ <- lift . runDB $ update userId [UserPassword =. Just (originalPassword f)]-                    _ <- lift . logAction $ Entity userId user+                    lift $ logUser user >>= logAction                     lift $ setMessageI Msg.SuccessChgPwd                     redirect $ UserAdminR $ UserAdminEditR userId                 _ -> lift $ do@@ -284,7 +280,7 @@                }     _ <- lift . runDB $ replace userId user     _ <- sendAccountResetToken (Entity userId user)-    _ <- lift . logAction $ Entity userId user+    lift $ logUser user >>= logAction     lift $ setMessageI Msg.PasswordResetTokenSend     redirectUltDest . UserAdminR $ UserAdminEditR userId @@ -296,7 +292,7 @@             let user = user' { userActive = False }              _ <- lift . runDB $ replace userId user-            _ <- lift . logAction $ Entity userId user+            lift $ logUser user >>= logAction             lift $ setMessageI Msg.UserDeactivated         _ -> lift $ setMessageI Msg.UserStillPending     redirectUltDest . UserAdminR $ UserAdminEditR userId@@ -309,7 +305,7 @@             let user = user' { userActive = True }              _ <- lift . runDB $ replace userId user-            _ <- lift . logAction $ Entity userId user+            lift $ logUser user >>= logAction             lift $ setMessageI Msg.UserActivated         _ -> lift $ setMessageI Msg.UserStillPending     redirectUltDest . UserAdminR $ UserAdminEditR userId@@ -331,7 +327,7 @@                  }          _ <- runDB $ replace userId user-        _ <- logAction $ Entity userId user+        logAction =<< logUser user         setMessageI Msg.SuccessDelete     redirectUltDest $ UserAdminR UserAdminIndexR 
LambdaCms/Core/Message.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}  module LambdaCms.Core.Message        ( CoreMessage (..)
README.md view
@@ -1,6 +1,5 @@  - ```                            ,                     _                           /   _, _   /  _/ _,   / ) _  _,@@ -44,7 +43,7 @@  # Getting started -Using this guide you will create a CMS website named `YourApp`.+Using this guide you will create a CMS website named `mysite`. For a real project you want to substitute this name, but for trying out LambdaCms it is recommended to keep it for the convenience of copy-pasting the instructions that follow.@@ -93,31 +92,33 @@ against non-Haskell libraries. One of the following libraries needs to be available: -* `libpq-dev` (Ubuntu) or `postgress` (Homebrew on OSX) for Postgres-* `libmysqlclient-dev` (Ubuntu) or `mysql` (Homebrew on OSX) for MySQL-* `libsqlite3-dev` (Ubuntu) or `sqlite` (Homebrew on OSX) for Sqlite+* For Postgres:+ * Ubuntu: `libpq-dev`+ * Homebrew on OSX: `postgres`+* For Mysql:+  * Ubuntu: `libmysqlclient-dev`+  * Homebrew on OSX: `mysql`+* For Sqlite+  * Ubuntu: `libsqlite3-dev`+  * Homebrew on OSX: `sqlite`  On other platforms these packages might have different names, but are most likely available. -If you are going to use a database other then Sqlite, you also need+If you are going to use a database other than Sqlite, you also need to install that. - ### Create the base application  With the following command you create a "scaffolded" Yesod application. The command is interactive; you need to supply some configuration values.-Pick the database of your choice, and name it `YourApp` (if you want follow this-guide closely).+Pick the database of your choice, and choose a project name      yesod init -After scaffolding move into the project folder.--    cd YourApp+After scaffolding `cd` into the project folder. -If you have chosen a database other then Sqlite, you need to create a+If you have chosen a database other than Sqlite, you need to create a database and a sufficiently priviledged user, and supply the credentials to the `config/setting.yml` file. @@ -133,7 +134,7 @@ thereby automatically using the most recent minor release in that series. -Run the following commands from within `YourApp`'s project folder,+Run the following commands from within your project's root folder, to install the most recent LTS Haskell package set in the `1.x` series.      wget http://www.stackage.org/lts/1/cabal.config@@ -163,23 +164,32 @@  ### Add LambdaCms -At some point the `lambdacms-core` package will be distributed from Hackage,-until then we install it from Github.--    cd ..-    git clone git@github.com:lambdacms/lambdacms-core.git-    cd lambdacms-core-    cabal install-    cd ../YourApp+LambdaCms is on Hackage! Install with: `cabal install lambdacms-core`  In the following sub-sections we explain how to install `lambdacms-core` into the base application.  Much of what we show here can be accomplished in many different ways, in this guide we merely provide a way to get you started. +#### Patching a new Yesod application -#### Modify the `YourApp.cabal` file+To setup a new LambdaCms website the easy way we created patch files to convert+a new Yesod application to a LambdaCms website. Those patches can be found in+[lambdamcs-patches](https://github.com/lambdacms/lambdacms-patches). Either clone+the repository or copy only the required patches to your local environment and+run the following command (replace `/path/to` with the actual path to the patch+file): -First add `lambdacms-core` to the dependencies list of the `YourApp.cabal`+    patch -p1 < /path/to/lambdacms.patch++This patches all files at the same time. Documentation about how to patch files+individually can be found in the `lambdacms-patches`+[README](https://github.com/lambdacms/lambdacms-patches/blob/master/README.md).++To manually add LambdaCms to a Yesod application follow the steps below.++#### Modify the `.cabal` file++First add `lambdacms-core` to the dependencies list of the `.cabal` file (name of the file depends on the name of your project).  Add the follwing to the end of the `build-depends` section:@@ -197,44 +207,47 @@  #### Modify the `config/routes` file -Add the following routes to the `config/routes` file of your application:+Replace **all** of the file's content with:  ```-/admin/auth    AuthR                 Auth        getAuth-/admin/core    CoreAdminR            CoreAdmin   getLambdaCms-/admin         AdminHomeRedirectR    GET-```+/static StaticR Static appStatic -And remove `/auth   AuthR   Auth   getAuth`.+/favicon.ico FaviconR GET+/robots.txt RobotsR GET -#### Modify the `config/settings.yml` file+/ HomeR GET -Add the following line, which sets the email address for an admin user account-that is created (and activated) in case no user exists:+/admin/auth        AuthR                 Auth            getAuth+/admin/core        CoreAdminR            CoreAdmin       getLambdaCms+/admin             AdminHomeRedirectR    GET+``` +#### Modify Settings++There are two files to modify here. One is `config/settings.yml` and the the other is `Settings.hs`.++In `config/settings.yml`, add the following line to the bottom of the file ``` admin: "_env:LAMBDACMS_ADMIN:<your email address>" ``` -#### Modify the `Settings.hs` file--Append the following record to the `AppSettings` data type:+Then, in `Settings.hs`, append the following record to the `AppSettings` data type:  ```haskell     , appAdmin                  :: Text ``` -Add this line to `instance FromJSON AppSettings` (ensure following-the same order as the properties appear in `settings.yml`):+In `instance FromJSON AppSettings`, find this line: +Add the following line just before the line containing `return AppSettings {..}`:+ ```haskell         appAdmin                  <- o .: "admin" ```  #### Modify the `config/models` file -Replace **all** of the file's content with the following `UserRole`-definition:+Replace **all** of the file's content with the following `UserRole` definition:  ``` UserRole@@ -260,10 +273,10 @@ ```haskell import LambdaCms.Core import LambdaCms.Core.Settings (generateUUID)-import qualified Network.Wai.Middleware.MethodOverridePost as MiddlewareMOP+import Network.Wai.Middleware.MethodOverridePost ``` -And add the following function:+Add the following function:  ```haskell getAdminHomeRedirectR :: Handler Html@@ -271,47 +284,33 @@     redirect $ CoreAdminR AdminHomeR ``` -Replace the `makeFoundation` function with the following code, so it will-create the `admin` user as provided in `settings.yml` and run all needed migrations.-This example assumes Postgres is used:+In the `makeFoundation` function, add this line to beginning:  ```haskell-makeFoundation :: AppSettings -> IO App-makeFoundation appSettings' = do-    -- Some basic initializations: HTTP connection manager, logger, and static-    -- subsite.-    appHttpManager' <- newManager-    appLogger' <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger-    appStatic' <--        (if appMutableStatic appSettings' then staticDevel else static)-        (appStaticDir appSettings')+let getLambdaCms = CoreAdmin+``` -    -- We need a log function to create a connection pool. We need a connection-    -- pool to create our foundation. And we need our foundation to get a-    -- logging function. To get out of this loop, we initially create a-    -- temporary foundation without a real connection pool, get a log function-    -- from there, and then create the real foundation.-    let mkFoundation appConnPool' = App { appSettings    = appSettings'-                                        , appStatic      = appStatic'-                                        , appHttpManager = appHttpManager'-                                        , appLogger      = appLogger'-                                        , appConnPool    = appConnPool'-                                        , getLambdaCms   = CoreAdmin-                                        }-        tempFoundation = mkFoundation $ error "connPool forced in tempFoundation"-        logFunc = messageLoggerSource tempFoundation appLogger'+Then, find this code: -    -- Create the database connection pool-    pool <- flip runLoggingT logFunc $ createPostgresqlPool-        (pgConnStr  $ appDatabaseConf appSettings')-        (pgPoolSize $ appDatabaseConf appSettings')+```haskell+    -- Perform database migration using our application's logging settings.+    runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc +    -- Return the foundation+    return $ mkFoundation pool+```++And replace it with:++```haskell+    -- Perform database migration using our application's logging settings.     let theFoundation = mkFoundation pool     runLoggingT         (runSqlPool (mapM_ runMigration [migrateAll, migrateLambdaCmsCore]) pool)-        (messageLoggerSource theFoundation appLogger')+        (messageLoggerSource theFoundation appLogger) -    let admin = appAdmin appSettings'+    -- Create a user if no user exists yet+    let admin = appAdmin appSettings     madmin <- runSqlPool (getBy (UniqueEmail admin)) pool     case madmin of         Nothing -> do@@ -332,10 +331,11 @@                 mapM_ (insert_ . UserRole uid) [minBound .. maxBound]         _ -> return () +    -- Return the foundation     return theFoundation- ``` + In the function `makeApplication` replace this line:  ```haskell@@ -346,7 +346,7 @@ forms work on older browsers):  ```haskell-    return $ logWare $ MiddlewareMOP.methodOverridePost appPlain+    return $ logWare $ methodOverridePost appPlain ```  ## Create the `Roles.hs` file@@ -476,7 +476,7 @@  ### Give it a try -LambdaCms should now be installed into `YourApp`. You can give it a try.+LambdaCms should now be installed. You can give it a try.      yesod devel 
config/models view
@@ -24,7 +24,6 @@     userId UserId     message Text     lang Text-    path Text Maybe     createdAt UTCTime     UniqueLog ident lang     deriving Typeable Show
lambdacms-core.cabal view
@@ -1,5 +1,5 @@ name:               lambdacms-core-version:            0.0.7.3+version:            0.0.8.0 license:            MIT license-file:       LICENSE author:             Cies Breijs, Mats Rietdijk, Rutger van Aalst@@ -15,9 +15,9 @@ build-type:         Simple tested-with:        GHC >= 7.6 cabal-version:      >= 1.18-extra-source-files: README.md+extra-doc-files:    README.md                   , CHANGES.md-                  , templates/*.hamlet+extra-source-files: templates/*.hamlet                   , templates/*.julius                   , templates/*.cassius                   , templates/mail/*.hamlet
templates/admin-layout.julius view
@@ -4,9 +4,13 @@     var formToggles;     formToggles = $('.form-toggle');     formToggles.each(function(index) {-      var glyph;+      var btn, glyph;       glyph = $('<span />').addClass('glyphicon');-      $(this).prepend(glyph);+      btn = $(this);+      if (btn.parent('.form-toggle-wrapper').find('.has-error').length) {+        btn.data('expanded', true);+      }+      btn.prepend(glyph);       toggleForm(this);     });     formToggles.on('click', function() {
templates/admin-welcome.hamlet view
@@ -2,6 +2,6 @@     <div .col-xs-12>         <div .jumbotron>             <h2>_{Msg.WelcomeTitle $ userName user}-            <p>_{Msg.WelcomeIntro $ renderMessage adminTitle}+            <p>_{Msg.WelcomeIntro $ messageRenderer adminTitle}             <p>_{Msg.WelcomeMenu}-            <p>#{preEscapedToMarkup $ renderMessage $ SomeMessage Msg.WelcomeInfo}+            <p>#{preEscapedToMarkup $ messageRenderer $ SomeMessage Msg.WelcomeInfo}
templates/user/edit.hamlet view
@@ -58,7 +58,7 @@                                 -                     <tr>                         <td>_{Msg.AccountStatus}-                        $maybe ut <- userToken user+                        $maybe _ <- userToken user                             <td .text-right .text-warning>_{Msg.AccountPending}                         $nothing                             $if userActive user
templates/user/index.hamlet view
@@ -38,7 +38,7 @@                                         $forall role <- roles                                             <span .label .label-primary>#{show role}                                     <td>#{userEmail user}-                                    $maybe ut <- userToken user+                                    $maybe _ <- userToken user                                         <td .text-right .text-warning>_{Msg.AccountPending}                                     $nothing                                         $if userActive user