-
Notifications
You must be signed in to change notification settings - Fork 1
/
Common.hs
141 lines (122 loc) · 4.82 KB
/
Common.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module Common where
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Database.Esqueleto as E
import Import
import Yesod.Form.Bootstrap3 (bfs)
bootstrapLabel :: Text -> FieldSettings site
bootstrapLabel x = bfs (x :: Text)
textAreaHeight :: Int -> FieldSettings site -> FieldSettings site
textAreaHeight n s = s{fsAttrs = ("style", css) : fsAttrs s}
where
css = "height: " ++ pack (show n) ++ "em"
getCubeCards :: CubeId -> Handler [Text]
getCubeCards cuid = do
cs <- runDB $ selectList [CubeEntryCube ==. cuid] []
return $ map (unCardKey . view cubeEntryCard . entityVal) cs
getPicks :: DraftId -> Handler [Pick]
getPicks draftId =
runDB $
map entityVal <$> selectList [PickDraft ==. draftId] [Asc PickNumber]
getDraft :: DraftId -> Handler Draft
getDraft did = do
Just draft <- runDB $ get did
return draft
type PicksInfoConstraint =
E.SqlExpr (Entity Pick) ->
E.SqlExpr (Entity Card) ->
E.SqlExpr (E.Value Bool)
getPicksAndInfo :: DraftId -> Maybe PicksInfoConstraint -> Handler [(Pick, Card)]
getPicksAndInfo did mbconst = map munge <$> runDB query
where
munge (x, y) = (entityVal x, entityVal y)
query = E.select $
E.distinct $
E.from $ \(pick `E.InnerJoin` cubeEntry `E.InnerJoin` card) -> do
E.on $ cubeEntry E.^. CubeEntryCard E.==. card E.^. CardId
E.on $ cubeEntry E.^. CubeEntryCard E.==. pick E.^. PickCard
E.where_ $ pick E.^. PickDraft E.==. E.val did
forM_ mbconst $ \f -> E.where_ (f pick card)
E.orderBy [E.asc (pick E.^. PickNumber)]
return (pick, card)
pickOrder :: [a] -> [a]
pickOrder drafters = concat . repeat $ drafters ++ reverse drafters
getNextDrafter :: Entity Draft -> Handler (Maybe UserId)
getNextDrafter (Entity did d) =
runDB $ do
mpick <- selectFirst [PickDraft ==. did] [Desc PickNumber, LimitTo 1]
let nextpick = fromIntegral $ maybe 0 (succ . view pickNumber) (entityVal <$> mpick)
(rd, nextseat) = pickNumToRC d nextpick
if fromIntegral rd >= d ^. draftRounds
then return Nothing
else do
s <- getBy (UniqueDraftSeat did (fromIntegral nextseat))
return (view draftParticipantDrafter . entityVal <$> s)
pickNumToRC :: Draft -> Int -> (Int, Int)
pickNumToRC draft i = (r, c)
where
n = fromIntegral $ draft ^. draftParticipants
r = i `div` n
dir
| isLeftToRightRow draft r = id
| otherwise = (pred n -)
c = dir (i `mod` n)
rcToPickNum :: Draft -> (Int, Int) -> Int
rcToPickNum draft (r, c) = r * n + dir c
where
n = fromIntegral $ draft ^. draftParticipants
dir
| isLeftToRightRow draft r = id
| otherwise = flip subtract (pred n)
isLeftToRightRow :: Draft -> Int -> Bool
isLeftToRightRow = const even
getParticipants :: DraftId -> Handler [Entity User]
getParticipants did = runDB query
where
query = E.select $
E.from $ \(dp `E.InnerJoin` user) -> do
E.on $ dp E.^. DraftParticipantDrafter E.==. user E.^. UserId
E.where_ $ dp E.^. DraftParticipantDraft E.==. E.val did
E.orderBy [E.asc (dp E.^. DraftParticipantSeat)]
return user
getPickAllowedCards :: DraftId -> Draft -> Handler [Text]
getPickAllowedCards did draft = do
cubeCards <- getCubeCards (draft ^. draftCube)
picks <- map (unCardKey . view pickCard) <$> getPicks did
return (Set.toList (Set.fromList cubeCards Set.\\ Set.fromList picks))
maybeLast :: [a] -> Maybe a
maybeLast [] = Nothing
maybeLast [x] = Just x
maybeLast (_ : xs) = maybeLast xs
getDraftWatcher :: DraftId -> Handler (TVar (Maybe Pick))
getDraftWatcher did = do
mlast <- maybeLast <$> getPicks did
watchers <- appDraftWatchers <$> getYesod
atomically $ do
mwatcher <- Map.lookup did <$> readTVar watchers
case mwatcher of
Nothing -> do
watcher <- newTVar mlast
modifyTVar watchers (Map.insert did watcher)
return watcher
Just watcher -> do
moldPick <- readTVar watcher
when ((_pickNumber <$> moldPick) <= (_pickNumber <$> mlast)) $
writeTVar watcher mlast
return watcher
waitForPick :: TVar (Maybe Pick) -> Int -> STM Int
waitForPick watcher seenPicks = do
savedPicks <- maybe 0 (succ . _pickNumber) <$> readTVar watcher
if savedPicks > seenPicks
then return savedPicks
else mzero
isCommissioner :: DraftId -> Handler Bool
isCommissioner draftId = do
muid <- maybeAuthId
case muid of
Nothing -> return False
Just uid -> runDB $ do
mdraft <- get draftId
case mdraft of
Nothing -> return False
Just draft -> return $ _draftCreator draft == uid