From b0732ae6c6665ea60f0c61302ba3c55ccc7074e1 Mon Sep 17 00:00:00 2001 From: SJost Date: Tue, 20 Nov 2018 15:48:29 +0300 Subject: [PATCH 1/9] Mino --- src/Handler/Corrections.hs | 5 +++- src/Handler/Utils/Submission.hs | 45 +++++++++++++++++---------------- src/Jobs/Queue.hs | 5 ++-- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/Handler/Corrections.hs b/src/Handler/Corrections.hs index 73f0df665..48d9c5e48 100644 --- a/src/Handler/Corrections.hs +++ b/src/Handler/Corrections.hs @@ -550,8 +550,11 @@ postCorrectionR tid ssh csh shn cid = do uid <- requireAuthId void . runDBJobs . runConduit $ transPipe (lift . lift) fileUploads .| extractRatingsMsg .| sinkSubmission uid (Right sub) True + {-case res of + (Left _) -> addMessageI Success MsgRatingFilesUpdated + (Right RatingNotExpected) -> addMessageI Error MsgRatingNotExpected + (Right other) -> throw other-} - addMessageI Success MsgRatingFilesUpdated redirect $ CSubmissionR tid ssh csh shn cid CorrectionR mr <- getMessageRender diff --git a/src/Handler/Utils/Submission.hs b/src/Handler/Utils/Submission.hs index c1e2648c5..3d405fff8 100644 --- a/src/Handler/Utils/Submission.hs +++ b/src/Handler/Utils/Submission.hs @@ -3,7 +3,7 @@ module Handler.Utils.Submission , assignSubmissions , submissionBlacklist, filterSubmission, extractRatings, extractRatingsMsg , submissionFileSource, submissionFileQuery - , submissionMultiArchive + , submissionMultiArchive , SubmissionSinkException(..) , sinkSubmission, sinkMultiSubmission , submissionMatchesSheet @@ -142,9 +142,9 @@ assignSubmissions sid restriction = do wholeProps = Map.fromList [ ( sheetCorrectorUser, round $ byProportion * fromInteger lcd ) | Entity _ SheetCorrector{ sheetCorrectorLoad = Load{..}, .. } <- corrsProp ] detQueueLength = fromIntegral (Map.size $ Map.filter (\tuts -> all countsToLoad' tuts) subTutor') - sum deficit detQueue = concat . List.genericReplicate (detQueueLength `div` sum wholeProps) . concatMap (uncurry $ flip List.genericReplicate) $ Map.toList wholeProps - + $logDebugS "assignSubmissions" $ "Deterministic Queue: " <> tshow detQueue - + queue <- liftIO . Rand.evalRandIO . execWriterT $ do tell $ map Just detQueue forever $ @@ -162,11 +162,11 @@ assignSubmissions sid restriction = do maximumDeficit :: (MonadState (_a, _b, Map UserId Integer) m, MonadIO m) => m (Maybe UserId) maximumDeficit = do - transposed <- uses _3 invertMap + transposed <- uses _3 invertMap traverse (liftIO . Rand.evalRandIO . Rand.uniform . snd) (Map.lookupMax transposed) subTutor'' <- liftIO . Rand.evalRandIO . Rand.shuffleM $ Map.toList subTutor' - + subTutor <- fmap (view _1) . flip execStateT (Map.empty, queue, deficit) . forM_ subTutor'' $ \(smid, tuts) -> do let restrictTuts @@ -177,7 +177,7 @@ assignSubmissions sid restriction = do Just q' -> do $logDebugS "assignSubmissions" $ tshow smid <> " -> " <> tshow q' <> " (byDeficit)" assignSubmission False smid q' - Nothing + Nothing | Set.null tuts -> do q <- preuse $ _2 . _head . _Just case q of @@ -194,7 +194,7 @@ assignSubmissions sid restriction = do forM_ (Map.toList subTutor) $ \(smid, tutid) -> update smid [ SubmissionRatingBy =. Just tutid , SubmissionRatingAssigned =. Just now ] - + let assignedSubmissions = Map.keysSet subTutor unassigendSubmissions = Map.keysSet subTutor' \\ assignedSubmissions return (assignedSubmissions, unassigendSubmissions) @@ -222,7 +222,7 @@ submissionMultiArchive (Set.toList -> ids) = do ratedSubmissions <- runDBRunner dbrunner $ do submissions <- selectList [ SubmissionId <-. ids ] [] forM submissions $ \s@(Entity submissionId _) -> maybe (invalidArgs ["Invalid submission numbers"]) (return . (, s)) =<< getRating submissionId - + (<* cleanup) . respondSource "application/zip" . transPipe (runDBRunner dbrunner) $ do let fileEntitySource' :: (Rating, Entity Submission) -> Source (YesodDB UniWorX) File @@ -231,7 +231,7 @@ submissionMultiArchive (Set.toList -> ids) = do let directoryName = Text.unpack $ toPathPiece (cID :: CryptoFileNameSubmission) - + fileEntitySource = do submissionFileSource submissionID =$= Conduit.map entityVal yieldM (ratingFile cID rating) @@ -249,7 +249,7 @@ submissionMultiArchive (Set.toList -> ids) = do } fileEntitySource =$= mapC withinDirectory - + mapM_ fileEntitySource' ratedSubmissions =$= produceZip def =$= Conduit.map toFlushBuilder @@ -374,7 +374,7 @@ sinkSubmission userId mExists isUpdate = do | not (null underlyingFiles) = all (~~ file) [ f | (Entity _ f, Entity _ _sf) <- underlyingFiles ] | otherwise = False undoneDeletion = any submissionFileIsDeletion [ sf | (_, Entity _ sf) <- collidingFiles ] - + when anyChanges $ do touchSubmission when (not $ null collidingFiles) $ @@ -394,14 +394,14 @@ sinkSubmission userId mExists isUpdate = do when undoneDeletion $ do touchSubmission lift $ deleteWhere [ SubmissionFileId <-. [ sfId | (_, Entity sfId sf) <- collidingFiles, submissionFileIsDeletion sf ] ] - + Right (submissionId', r'@Rating'{..}) -> do $logDebugS "sinkSubmission" $ tshow submissionId' unless (submissionId' == submissionId) $ do cID <- encrypt submissionId' throwM $ ForeignRating cID - + alreadySeen <- gets $ getAny . sinkSeenRating when alreadySeen $ throwM DuplicateRating tellSt $ mempty{ sinkSeenRating = Any True } @@ -410,19 +410,20 @@ sinkSubmission userId mExists isUpdate = do Submission{..} <- lift $ getJust submissionId - let anyChanges = or $ + let anyChanges = or $ [ submissionRatingPoints /= ratingPoints , submissionRatingComment /= ratingComment ] -- 'ratingTime' is ignored for consistency with 'File's: - -- + -- -- 'fileModified' is simply stored and never inspected while - -- 'submissionChanged' is always set to @now@. + -- 'submissionChanged' is always set to @now@. when anyChanges $ do Sheet{..} <- lift $ getJust submissionSheet - mapM_ throwM $ validateRating sheetType r' - + --TODO: should display errorMessages + mapM_ throwM $ validateRating sheetType r' + touchSubmission lift $ update submissionId [ SubmissionRatingPoints =. ratingPoints @@ -514,7 +515,7 @@ data SubmissionMultiSinkException { _submissionSinkId :: CryptoFileNameSubmission , _submissionSinkFedFile :: Maybe FilePath , _submissionSinkException :: SubmissionSinkException - } + } deriving (Typeable, Show) instance Exception SubmissionMultiSinkException @@ -522,7 +523,7 @@ instance Exception SubmissionMultiSinkException sinkMultiSubmission :: UserId -> Bool {-^ Are these corrections -} -> Sink SubmissionContent (YesodJobDB UniWorX) (Set SubmissionId) - + -- ^ Expects all supplied 'SubmissionContent' to contain an encrypted 'SubmissionId' and replaces the currently saved files for the respective submissions (either corrected files or original ones, depending on arguments) with the supplied 'SubmissionContent'. -- -- Files that don't occur in the 'SubmissionContent' but are in the database are deleted (or marked as deleted in the case of this being a correction). @@ -545,7 +546,7 @@ sinkMultiSubmission userId isUpdate = do Nothing -> do lift $ do cID <- encrypt sId - $(logDebugS) "sinkMultiSubmission" $ "Doing auth checks for " <> toPathPiece cID + $(logDebugS) "sinkMultiSubmission" $ "Doing auth checks for " <> toPathPiece cID Submission{..} <- get404 sId Sheet{..} <- get404 submissionSheet Course{..} <- get404 sheetCourse @@ -595,7 +596,7 @@ sinkMultiSubmission userId isUpdate = do handleHCError _ e = throwM e handleCryptoID :: CryptoIDError -> _ (Maybe a) handleCryptoID _ = return Nothing - + submissionMatchesSheet :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> DB SubmissionId submissionMatchesSheet tid ssh csh shn cid = do diff --git a/src/Jobs/Queue.hs b/src/Jobs/Queue.hs index 001471544..851b2bf77 100644 --- a/src/Jobs/Queue.hs +++ b/src/Jobs/Queue.hs @@ -46,7 +46,7 @@ writeJobCtlBlock cmd = do return var lift $ writeJobCtl cmd let - removeResVar = HashMap.update (NonEmpty.nonEmpty . NonEmpty.filter (/= resVar)) cmd + removeResVar = HashMap.update (NonEmpty.nonEmpty . NonEmpty.filter (/= resVar)) cmd mExc <- liftIO . atomically $ takeTMVar resVar <* modifyTVar' getResVar removeResVar maybe (return ()) throwM mExc @@ -77,7 +77,8 @@ type YesodJobDB site = ReaderT (YesodPersistBackend site) (WriterT (Set QueuedJo queueDBJob :: Job -> ReaderT (YesodPersistBackend UniWorX) (WriterT (Set QueuedJobId) (HandlerT UniWorX IO)) () queueDBJob job = mapReaderT lift (queueJobUnsafe job) >>= tell . Set.singleton -runDBJobs :: (MonadHandler m, HandlerSite m ~ UniWorX) => ReaderT (YesodPersistBackend UniWorX) (WriterT (Set QueuedJobId) (HandlerT UniWorX IO)) a -> m a +runDBJobs :: (MonadHandler m, HandlerSite m ~ UniWorX) + => ReaderT (YesodPersistBackend UniWorX) (WriterT (Set QueuedJobId) (HandlerT UniWorX IO)) a -> m a runDBJobs act = do (ret, jIds) <- liftHandlerT . runDB $ mapReaderT runWriterT act forM_ jIds $ writeJobCtl . JobCtlPerform From 03fa874e05895294398e951febc06f9e0f7005aa Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Tue, 27 Nov 2018 15:38:07 +0100 Subject: [PATCH 2/9] Account for jitter in determining whether CronLastExec is acceptable --- src/Cron.hs | 10 ++++++---- src/Jobs.hs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Cron.hs b/src/Cron.hs index 600eb873c..53a7a01b3 100644 --- a/src/Cron.hs +++ b/src/Cron.hs @@ -150,10 +150,11 @@ genMatch p m st (CronMatchUnion aGen bGen) = merge (genMatch p m st aGen) (genMa nextCronMatch :: TZ -- ^ Timezone of the `Cron`-Entry -> Maybe UTCTime -- ^ Time of last execution of the job + -> NominalDiffTime -- ^ Scheduling precision -> UTCTime -- ^ Current time, used only for `CronCalendar` -> Cron -> CronNextMatch UTCTime -nextCronMatch tz mPrev now c@Cron{..} = case notAfter of +nextCronMatch tz mPrev prec now c@Cron{..} = case notAfter of MatchAsap -> MatchNone MatchAt ts | MatchAt ts' <- nextMatch @@ -183,7 +184,7 @@ nextCronMatch tz mPrev now c@Cron{..} = case notAfter of Just prevT -> case cronRepeat of CronRepeatOnChange - | not $ matchesCron tz Nothing prevT c + | not $ matchesCron tz Nothing prec prevT c -> let cutoffTime = addUTCTime cronRateLimit prevT in case execRef now False cronInitial of @@ -240,13 +241,14 @@ nextCronMatch tz mPrev now c@Cron{..} = case notAfter of matchesCron :: TZ -- ^ Timezone of the `Cron`-Entry -> Maybe UTCTime -- ^ Previous execution of the job + -> NominalDiffTime -- ^ Scheduling precision -> UTCTime -- ^ "Current" time -> Cron -> Bool -- ^ @matchesCron tz prev prec now c@ determines whether the given `Cron` -- specification @c@ should match @now@, under the assumption that the next -- check will occur no earlier than @now + prec@. -matchesCron tz mPrev now cron = case nextCronMatch tz mPrev now cron of +matchesCron tz mPrev prec now cron = case nextCronMatch tz mPrev prec now cron of MatchAsap -> True MatchNone -> False - MatchAt ts -> ts <= now + MatchAt ts -> ts <= addUTCTime prec now diff --git a/src/Jobs.hs b/src/Jobs.hs index 50bb56e5d..45a5f74f6 100644 --- a/src/Jobs.hs +++ b/src/Jobs.hs @@ -207,7 +207,7 @@ execCrontab = evalStateT go HashMap.empty | otherwise = Just (jobCtl, t) where - t = nextCronMatch appTZ (getMax <$> HashMap.lookup jobCtl lastTimes) now cron + t = nextCronMatch appTZ (getMax <$> HashMap.lookup jobCtl lastTimes) acc now cron waitUntil :: (Eq a, MonadResourceBase m, MonadLogger m) => TMVar a -> a -> UTCTime -> m Bool waitUntil crontabTV crontab nextTime = runResourceT $ do From 77d03348e83e8cc1e377b466f315a9f83b9fa1e3 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Tue, 27 Nov 2018 16:03:48 +0100 Subject: [PATCH 3/9] Fix tests --- src/Foundation.hs | 2 +- test/CronSpec.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Foundation.hs b/src/Foundation.hs index 4960f292b..4289cdaad 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -678,10 +678,10 @@ instance Yesod UniWorX where encrypted plaintextJson plaintext = do canDecrypt <- (== Authorized) <$> evalAccess AdminErrMsgR True shouldEncrypt <- getsYesod $ appEncryptErrors . appSettings - errKey <- getsYesod appErrorMsgKey if | shouldEncrypt , not canDecrypt -> do + errKey <- getsYesod appErrorMsgKey nonce <- liftIO SecretBox.newNonce let ciphertext = SecretBox.secretbox errKey nonce . Lazy.ByteString.toStrict $ encode plaintextJson encoded = decodeUtf8 . Base64.encode $ Saltine.encode nonce <> ciphertext diff --git a/test/CronSpec.hs b/test/CronSpec.hs index ee9abe812..79265811c 100644 --- a/test/CronSpec.hs +++ b/test/CronSpec.hs @@ -21,7 +21,7 @@ sampleCron :: Natural -> Cron -> [UTCTime] sampleCron n = go n baseTime Nothing where go 0 _ _ _ = [] - go (pred -> n') t mPrev cron = case nextCronMatch utcTZ mPrev t cron of + go (pred -> n') t mPrev cron = case nextCronMatch utcTZ mPrev 0 t cron of MatchAsap -> t : go n' t (Just t) cron MatchAt t' -> t' : go n' t' (Just t') cron MatchNone -> [] From 431eb45a94b3b5beac101820e5b5a2c8564eaf89 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Tue, 27 Nov 2018 19:11:28 +0100 Subject: [PATCH 4/9] Log to file during tests --- .gitignore | 3 ++- config/settings.yml | 8 +++--- config/test-settings.yml | 15 +++++------ src/Application.hs | 54 +++++++++++++++++++++++++++---------- src/Foundation.hs | 8 +++--- src/Model/Migration.hs | 6 ++--- src/Settings.hs | 16 +++++++++-- test/Database.hs | 2 ++ test/Handler/ProfileSpec.hs | 4 +-- test/TestImport.hs | 3 ++- 10 files changed, 81 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index bce03bdeb..b85a1c848 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ src/Handler/Course.SnapCustom.hs /instance .stack-work-* .directory -tags \ No newline at end of file +tags +test.log \ No newline at end of file diff --git a/config/settings.yml b/config/settings.yml index 60c1f2c33..f3243a773 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -29,9 +29,11 @@ notification-expiration: 259201 session-timeout: 7200 log-settings: - log-detailed: "_env:DETAILED_LOGGING:false" - log-all: "_env:LOG_ALL:false" - log-minimum-level: "_env:LOGLEVEL:warn" + detailed: "_env:DETAILED_LOGGING:false" + all: "_env:LOG_ALL:false" + minimum-level: "_env:LOGLEVEL:warn" + destination: "_env:LOGDEST:stderr" + # Debugging auth-dummy-login: "_env:DUMMY_LOGIN:false" diff --git a/config/test-settings.yml b/config/test-settings.yml index c6e5bf360..23f59aed5 100644 --- a/config/test-settings.yml +++ b/config/test-settings.yml @@ -1,11 +1,10 @@ database: - # NOTE: By design, this setting prevents the PGDATABASE environment variable - # from affecting test runs, so that we don't accidentally affect the - # production database during testing. If you're not concerned about that and - # would like to have environment variable overrides, you could instead use - # something like: - # - # database: "_env:PGDATABASE:uniworx_test" - database: uniworx_test + database: "_env:PGDATABASE_TEST:uniworx_test" + +log-settings: + detailed: true + all: true + minimum-level: "debug" + destination: "test.log" auth-dummy-login: true diff --git a/src/Application.hs b/src/Application.hs index e1fbfa575..b1f17147b 100644 --- a/src/Application.hs +++ b/src/Application.hs @@ -30,8 +30,9 @@ import Network.Wai.Middleware.RequestLogger (Destination (Logger), IPAddrSource (..), OutputFormat (..), destination, mkRequestLogger, outputFormat) -import System.Log.FastLogger (defaultBufSize, newStderrLoggerSet, - toLogStr) +import System.Log.FastLogger ( defaultBufSize, newStderrLoggerSet, newStdoutLoggerSet, newFileLoggerSet + , toLogStr, rmLoggerSet + ) import qualified Data.Map.Strict as Map @@ -61,7 +62,7 @@ import qualified Yesod.Core.Types as Yesod (Logger(..)) import qualified Data.HashMap.Strict as HashMap -import Control.Lens ((&)) +import Control.Lens import Data.Proxy @@ -100,10 +101,30 @@ makeFoundation appSettings@AppSettings{..} = do -- Some basic initializations: HTTP connection manager, logger, and static -- subsite. appHttpManager <- newManager - appLogger <- liftIO $ do - tgetter <- newTimeCache "%Y-%m-%d %T %z" - loggerSet <- newStderrLoggerSet defaultBufSize - return $ Yesod.Logger loggerSet tgetter + appLogSettings <- liftIO $ newTVarIO appInitialLogSettings + + let + mkLogger LogSettings{..} = do + tgetter <- newTimeCache "%Y-%m-%d %T %z" + loggerSet <- case logDestination of + LogDestStderr -> newStderrLoggerSet defaultBufSize + LogDestStdout -> newStdoutLoggerSet defaultBufSize + LogDestFile{..} -> newFileLoggerSet defaultBufSize logDestFile + return $ Yesod.Logger loggerSet tgetter + mkLogger' = liftIO $ do + initialSettings <- readTVarIO appLogSettings + tVar <- newTVarIO =<< mkLogger initialSettings + let updateLogger prevSettings = do + newSettings <- atomically $ do + newSettings <- readTVar appLogSettings + guard $ newSettings /= prevSettings + return newSettings + oldLogger <- atomically . swapTVar tVar =<< mkLogger newSettings + rmLoggerSet $ loggerSet oldLogger + updateLogger newSettings + (tVar, ) <$> fork (updateLogger initialSettings) + appLogger <- over _2 fst <$> allocate mkLogger' (\(tVar, tId) -> killThread tId >> (readTVarIO tVar >>= rmLoggerSet . loggerSet)) + appStatic <- liftIO $ bool static staticDevel appMutableStatic appStaticDir appInstanceID <- liftIO $ maybe UUID.nextRandom (either readInstanceIDFile return) appInitialInstanceID @@ -111,8 +132,6 @@ makeFoundation appSettings@AppSettings{..} = do appJobCtl <- liftIO $ newTVarIO Map.empty appCronThread <- liftIO newEmptyTMVarIO - appLogSettings <- liftIO $ newTVarIO appInitialLogSettings - -- 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 @@ -128,7 +147,9 @@ makeFoundation appSettings@AppSettings{..} = do (error "cryptoIDKey forced in tempFoundation") (error "sessionKey forced in tempFoundation") (error "errorMsgKey forced in tempFoundation") - logFunc = messageLoggerSource tempFoundation appLogger + logFunc loc src lvl str = do + f <- messageLoggerSource tempFoundation <$> readTVarIO (snd appLogger) + f loc src lvl str flip runLoggingT logFunc $ do $logDebugS "InstanceID" $ UUID.toText appInstanceID @@ -228,12 +249,13 @@ makeLogWare app = do let mkLogWare ls@LogSettings{..} = do + logger <- readTVarIO . snd $ appLogger app logWare <- mkRequestLogger def { outputFormat = bool (Apache . bool FromSocket FromHeader . appIpFromHeader $ appSettings app) (Detailed True) logDetailed - , destination = Logger . loggerSet $ appLogger app + , destination = Logger $ loggerSet logger } atomically . modifyTVar' logWareMap $ HashMap.insert ls logWare return logWare @@ -255,9 +277,11 @@ warpSettings foundation = defaultSettings & setPort (appPort $ appSettings foundation) & setHost (appHost $ appSettings foundation) & setOnException (\_req e -> - when (defaultShouldDisplayException e) $ messageLoggerSource + when (defaultShouldDisplayException e) $ do + logger <- readTVarIO . snd $ appLogger foundation + messageLoggerSource foundation - (appLogger foundation) + logger $(qLocation >>= liftLoc) "yesod" LevelError @@ -322,7 +346,9 @@ getApplicationRepl = do return (getPort wsettings, foundation, app1) shutdownApp :: MonadIO m => UniWorX -> m () -shutdownApp = stopJobCtl +shutdownApp app = do + stopJobCtl app + release . fst $ appLogger app --------------------------------------------- diff --git a/src/Foundation.hs b/src/Foundation.hs index 4289cdaad..9b899765f 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -104,7 +104,7 @@ data UniWorX = UniWorX , appConnPool :: ConnectionPool -- ^ Database connection pool. , appSmtpPool :: Maybe SMTPPool , appHttpManager :: Manager - , appLogger :: Logger + , appLogger :: (ReleaseKey, TVar Logger) , appLogSettings :: TVar LogSettings , appCryptoIDKey :: CryptoIDKey , appInstanceID :: InstanceId @@ -757,7 +757,7 @@ instance Yesod UniWorX where LogSettings{..} <- readTVarIO $ appLogSettings app return $ logAll || level >= logMinimumLevel - makeLogger = return . appLogger + makeLogger = readTVarIO . snd . appLogger siteLayout :: Maybe Html -- ^ Optionally override `pageHeading` @@ -1694,7 +1694,9 @@ instance HasHttpManager UniWorX where getHttpManager = appHttpManager unsafeHandler :: UniWorX -> Handler a -> IO a -unsafeHandler = Unsafe.fakeHandlerGetLogger appLogger +unsafeHandler f h = do + logger <- makeLogger f + Unsafe.fakeHandlerGetLogger (const logger) f h instance YesodMail UniWorX where diff --git a/src/Model/Migration.hs b/src/Model/Migration.hs index e38e55bb5..e84be6b9c 100644 --- a/src/Model/Migration.hs +++ b/src/Model/Migration.hs @@ -50,9 +50,9 @@ share [mkPersist sqlSettings, mkMigrate "migrateDBVersioning"] deriving Show Eq Ord |] -migrateAll :: MonadIO m => ReaderT SqlBackend m () +migrateAll :: (MonadLogger m, MonadBaseControl IO m, MonadIO m) => ReaderT SqlBackend m () migrateAll = do - runMigration $ do + mapM_ ($logInfoS "Migration") <=< runMigrationSilent $ do -- Manual migrations to go to InitialVersion below: migrateEnableExtension "citext" @@ -69,7 +69,7 @@ migrateAll = do -- Map.foldlWithKey traverses migrations in ascending order of AppliedMigrationKey Map.foldlWithKey doCustomMigration (return ()) missingMigrations - runMigration migrateAll' + mapM_ ($logInfoS "Migration") =<< runMigrationSilent migrateAll' {- Confusion about quotes, from the PostgreSQL Manual: diff --git a/src/Settings.hs b/src/Settings.hs index b05ae3c5d..9b4e48541 100644 --- a/src/Settings.hs +++ b/src/Settings.hs @@ -114,11 +114,16 @@ data AppSettings = AppSettings data LogSettings = LogSettings { logAll, logDetailed :: Bool , logMinimumLevel :: LogLevel + , logDestination :: LogDestination } deriving (Show, Read, Generic, Eq, Ord) +data LogDestination = LogDestStderr | LogDestStdout | LogDestFile { logDestFile :: !FilePath } + deriving (Show, Read, Generic, Eq, Ord) + deriving instance Generic LogLevel instance Hashable LogLevel instance Hashable LogSettings +instance Hashable LogDestination data UserDefaultConf = UserDefaultConf { userDefaultTheme :: Theme @@ -178,12 +183,19 @@ data SmtpAuthConf = SmtpAuthConf } deriving (Show) deriveJSON defaultOptions - { fieldLabelModifier = intercalate "-" . map toLower . splitCamel + { constructorTagModifier = camelToPathPiece' 2 + , fieldLabelModifier = camelToPathPiece' 2 + , sumEncoding = UntaggedValue + , unwrapUnaryRecords = True + } ''LogDestination + +deriveJSON defaultOptions + { fieldLabelModifier = camelToPathPiece' 1 } ''LogSettings deriveFromJSON defaultOptions ''Ldap.Scope deriveFromJSON defaultOptions - { fieldLabelModifier = intercalate "-" . map toLower . drop 2 . splitCamel + { fieldLabelModifier = camelToPathPiece' 2 } ''UserDefaultConf instance FromJSON LdapConf where diff --git a/test/Database.hs b/test/Database.hs index 8359210ce..0308a3dfa 100755 --- a/test/Database.hs +++ b/test/Database.hs @@ -12,6 +12,7 @@ import Data.Pool (destroyAllResources) import Database.Persist.Postgresql import Control.Monad.Logger +import Control.Monad.Trans.Resource import System.Console.GetOpt import System.Exit (exitWith, ExitCode(..)) @@ -50,6 +51,7 @@ main = do DBTruncate -> db $ do foundation <- getYesod stopJobCtl foundation + release . fst $ appLogger foundation liftIO . destroyAllResources $ appConnPool foundation truncateDb DBMigrate -> db $ return () diff --git a/test/Handler/ProfileSpec.hs b/test/Handler/ProfileSpec.hs index aaf7a0da5..5d34a831d 100644 --- a/test/Handler/ProfileSpec.hs +++ b/test/Handler/ProfileSpec.hs @@ -7,7 +7,6 @@ import TestImport import qualified Data.CaseInsensitive as CI import Yesod.Core.Handler (toTextUrl) -import Yesod.Core.Unsafe (fakeHandlerGetLogger) spec :: Spec spec = withApp $ do @@ -15,8 +14,7 @@ spec = withApp $ do it "asserts no access to my-account for anonymous users" $ do get ProfileR - app <- getTestYesod - loginText <- fakeHandlerGetLogger appLogger app (toTextUrl $ AuthR LoginR) + loginText <- runHandler . toTextUrl $ AuthR LoginR assertHeader "Location" $ encodeUtf8 loginText diff --git a/test/TestImport.hs b/test/TestImport.hs index 1ef954051..207a563fe 100644 --- a/test/TestImport.hs +++ b/test/TestImport.hs @@ -44,7 +44,8 @@ runDBWithApp app query = liftIO $ runSqlPersistMPool query (appConnPool app) runHandler :: Handler a -> YesodExample UniWorX a runHandler handler = do app <- getTestYesod - fakeHandlerGetLogger appLogger app handler + logger <- liftIO . readTVarIO . snd $ appLogger app + fakeHandlerGetLogger (const logger) app handler withApp :: YSpec UniWorX -> Spec From 1085dc1df1159e6bc107887e793e9e0e024db492 Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Tue, 27 Nov 2018 22:04:40 +0100 Subject: [PATCH 5/9] page actions more prominent --- templates/default-layout.lucius | 5 +++-- templates/widgets/pageactionprime.hamlet | 27 ++++++++++++------------ templates/widgets/pageactionprime.lucius | 17 ++++----------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/templates/default-layout.lucius b/templates/default-layout.lucius index 1cdd12452..8deb58679 100644 --- a/templates/default-layout.lucius +++ b/templates/default-layout.lucius @@ -5,8 +5,9 @@ --color-success: #23d160; --color-info: #c4c4c4; --color-lightblack: #1A2A36; - --color-lightwhite: #FCFFFA; + --color-lightwhite: #fcfffa; --color-grey: #B1B5C0; + --color-grey-light: #f4f5f6; --color-font: #34303a; --color-fontsec: #5b5861; @@ -515,7 +516,7 @@ section { padding: 0 0 12px; margin: 0 0 12px; border-bottom: 1px solid #d3d3d3; - + } section:last-of-type { diff --git a/templates/widgets/pageactionprime.hamlet b/templates/widgets/pageactionprime.hamlet index 13aff9d10..624ec8e51 100644 --- a/templates/widgets/pageactionprime.hamlet +++ b/templates/widgets/pageactionprime.hamlet @@ -1,17 +1,16 @@ $newline never $if hasPageActions
-