forked from filipg/gonito
114 lines
4.3 KiB
Haskell
114 lines
4.3 KiB
Haskell
module Handler.Score where
|
|
|
|
import Import
|
|
|
|
import Handler.Shared
|
|
import Handler.Tables
|
|
|
|
import Control.Monad.Extra
|
|
|
|
import Handler.AchievementUtils
|
|
|
|
import qualified Database.Esqueleto as E
|
|
import Database.Esqueleto ((^.))
|
|
|
|
import qualified Yesod.Table as Table
|
|
|
|
import Data.Text as T
|
|
|
|
getMyScoreR :: Handler Html
|
|
getMyScoreR = do
|
|
entUser <- requireAuth
|
|
doScore entUser
|
|
|
|
getScoreR :: UserId -> Handler Html
|
|
getScoreR userId = do
|
|
user <- runDB $ get404 userId
|
|
doScore (Entity userId user)
|
|
|
|
scoreTable :: Table.Table App (AchievementInfo, (Entity Submission, Bool))
|
|
scoreTable = mempty
|
|
++ Table.text "name" (achievementInfoName . fst)
|
|
++ achievementDescriptionCell fst
|
|
++ timestampCell "deadline" (achievementInfoDeadline . fst)
|
|
++ timestampCell "submitted" (submissionStamp . entityVal . fst . snd)
|
|
++ Table.linked "submission" (submissionDescription . entityVal . fst . snd) (EditSubmissionR . entityKey . fst . snd)
|
|
++ Table.text "status" getStatus
|
|
|
|
extrasTable :: Table.Table App ExtraPoints
|
|
extrasTable = mempty
|
|
++ Table.text "reason" extraPointsDescription
|
|
++ timestampCell "added" extraPointsPosted
|
|
++ Table.int "points" extraPointsPoints
|
|
|
|
getStatus :: (AchievementInfo, (Entity Submission, Bool)) -> Text
|
|
getStatus (_, (_, False)) = ""
|
|
getStatus (aInfo, (_, True)) = T.pack $ show $ achievementInfoPoints aInfo
|
|
|
|
getPoints :: (AchievementInfo, (Entity Submission, Bool)) -> Int
|
|
getPoints (_, (_, False)) = 0
|
|
getPoints (aInfo, (_, True)) = achievementInfoPoints aInfo
|
|
|
|
doScore :: Entity User -> Handler Html
|
|
doScore userEnt@(Entity userId user) = do
|
|
courses <- runDB $ selectList [CourseClosed ==. False] [Asc CourseName]
|
|
|
|
courseUserInfos <- mapM (userScoreForCourse userEnt) courses
|
|
|
|
let courseInfos = Import.filter (\(_, (points, _, _)) -> points > 0) $ Import.zip courses courseUserInfos
|
|
|
|
defaultLayout $ do
|
|
setTitle "Score"
|
|
$(widgetFile "score")
|
|
|
|
|
|
userScoreForCourse :: Entity User -> Entity Course -> Handler (Int, [(AchievementInfo, (Entity Submission, Bool))], [ExtraPoints])
|
|
userScoreForCourse userEnt@(Entity userId user) courseEnt@(Entity courseId course) = do
|
|
achievementEntries <- userAchievementsForCourse userEnt courseId
|
|
let achievementTotal = sum $ Import.map getPoints achievementEntries
|
|
|
|
extraEntries <- userExtraPointsForCourse userId courseId
|
|
let extraTotal = sum $ Import.map extraPointsPoints extraEntries
|
|
|
|
let total = achievementTotal + extraTotal
|
|
|
|
return (total, achievementEntries, extraEntries)
|
|
|
|
userExtraPointsForCourse :: UserId -> CourseId -> Handler [ExtraPoints]
|
|
userExtraPointsForCourse userId courseId = do
|
|
entries <- runDB $ selectList [ExtraPointsUser ==. userId, ExtraPointsCourse ==. courseId] [Asc ExtraPointsPosted]
|
|
return $ Import.map entityVal entries
|
|
|
|
userAchievementsForCourse :: Entity User -> CourseId -> Handler [(AchievementInfo, (Entity Submission, Bool))]
|
|
userAchievementsForCourse (Entity userId user) courseId = do
|
|
entries <- runDB $ E.select
|
|
$ E.from $ \(working_on, achievement, submission) -> do
|
|
E.where_ (working_on ^. WorkingOnAchievement E.==. achievement ^. AchievementId
|
|
E.&&. E.just (submission ^. SubmissionId) E.==. working_on ^. WorkingOnFinalSubmission
|
|
E.&&. working_on ^. WorkingOnUser E.==. E.val userId
|
|
E.&&. achievement ^. AchievementCourse E.==. E.val courseId)
|
|
E.orderBy [E.asc (submission ^. SubmissionStamp)]
|
|
return (achievement, submission)
|
|
|
|
entries' <- mapM (processEntry (Entity userId user)) entries
|
|
|
|
return entries'
|
|
|
|
processEntry :: Entity User -> (Entity Achievement, Entity Submission) -> Handler (AchievementInfo, (Entity Submission, Bool))
|
|
processEntry entUser (entAchievement, entSubmission) = do
|
|
aInfo <- runDB $ getAchievementInfo (Just entUser) entAchievement
|
|
|
|
accepted <- allM (checkSubmissionTag entSubmission) (achievementInfoTags aInfo)
|
|
|
|
return (aInfo, (entSubmission, accepted))
|
|
|
|
|
|
checkSubmissionTag :: Entity Submission -> Entity Tag -> Handler Bool
|
|
checkSubmissionTag (Entity submissionId _) (Entity tagId _) = do
|
|
mSubmissionTag <- runDB $ getBy $ UniqueSubmissionTag submissionId tagId
|
|
return $ case mSubmissionTag of
|
|
Just (Entity _ submissionTag) -> case submissionTagAccepted submissionTag of
|
|
Just b -> b
|
|
Nothing -> False
|
|
Nothing -> False
|