aboutsummaryrefslogtreecommitdiff
path: root/lib/Server/Frontend/Tracker.hs
blob: a6c3c46b899ea31912e7cf58cab4010a1a116157 (plain)
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
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE QuasiQuotes    #-}

module Server.Frontend.Tracker (getTrackerViewR, getTrackersR, postTrackersR, postTrackerDeleteR) where
import           Data.Coerce                     (coerce)
import           Data.Function                   ((&))
import           Data.Functor                    ((<&>))
import qualified Data.Map                        as M
import           Data.Text                       (Text)
import qualified Data.Text                       as T
import           Data.Time                       (getCurrentTime)
import qualified Data.UUID                       as UUID
import           Database.Esqueleto.Experimental hiding ((<&>))
import           Persist
import           Server.Frontend.Routes          (FrontendMessage (..), Handler,
                                                  Route (..), Widget)
import           Yesod                           hiding (delete, update, (=.),
                                                  (==.))

import           OwnTracks.Status


getTrackersR :: Handler Html
getTrackersR = do
  trackers <- runDB $ select do
      (t :& p) <- from $
        (table @Tracker) `LeftOuterJoin` (table @Ping)
        `on` \(t :& p) -> just (t ^. TrackerId) ==. p ?. PingTrackerId
      pure (t, p)
    & fmap associateJoin

  createWidget <- trackerCreateWidget

  defaultLayout [whamlet|
    <h1> Trackers
    <section>
      <ul>
        $forall (trackerId, (Tracker{..}, status)) <- M.toList trackers
          <li><a href="@{TrackerViewR trackerName}">#{trackerName}</a>
    <section>
      ^{createWidget}
  |]

trackerCreateForm
  :: Html
  -> MForm Handler (FormResult Tracker, Widget)
trackerCreateForm = renderDivs $ Tracker
  <$> areq textField (fieldSettingsLabel MsgTrackerName) Nothing
  <*> pure False
  <*> areq textField (fieldSettingsLabel MsgTrackerAgent) Nothing
  <*> pure Nothing

trackerCreateWidget :: Handler Html
trackerCreateWidget = do
  (widget, enctype) <- generateFormPost trackerCreateForm
  defaultLayout [whamlet|
  <h2> _{MsgCreateTracker}
  <form method=post action="@{TrackersR}" enctype=#{enctype}>
    ^{widget}
    <button>_{MsgSubmit}
  |]

postTrackersR :: Handler Html
postTrackersR = do
  ((result, widget), enctype) <- runFormPost trackerCreateForm
  case result of
    FormSuccess ann -> do
      runDB do
        insert ann
      redirect TrackersR
    _ -> defaultLayout
        [whamlet|
            <p>_{MsgInvalidInput}.
            <form method=post action=@{TrackersR} enctype=#{enctype}>
                ^{widget}
                <button>_{MsgSubmit}
        |]

getTrackerViewR :: Text -> Handler Html
getTrackerViewR name =
  runDB (selectOne do
    tracker <- from (table @Tracker)
    where_ (tracker ^. TrackerName ==. val name)
    pure tracker)
  >>= \case
    Nothing -> notFound
    Just (Entity trackerId Tracker{..}) -> do

      (maybeStatus, maybePing) <- runDB $ do
        status <- selectOne do
          status <- from (table @TrackerStatus)
          where_ (status ^. TrackerStatusTracker ==. val trackerId)
          orderBy [desc $ status ^. TrackerStatusTimestamp]
          pure status
        ping <- selectOne do
          ping <- from (table @Ping)
          where_ (ping ^. PingTrackerId ==. val trackerId)
          orderBy [desc $ ping ^. PingTimestamp]
          pure ping
        pure (status, ping)

      -- TODO: leaflet map; auto updates?
      defaultLayout [whamlet|
        <h1> _{MsgTracker name}
        <section>
          <h1> _{MsgTracker name}
          <p>
            Agent: #{trackerAgent} <br>
            UUID: #{trackerId}
          <p>
            <form action=@{TrackerDeleteR trackerName} method="post">
              <button> _{Msgdelete}
        <section>
          <h2> _{MsgLastTrackerStatus}
          $maybe Entity _ TrackerStatus{..} <- maybeStatus
            LocationPermission: #{show $ statusLocationPermission trackerStatusStatus} <br>
            BatteryOptimisations: #{show $ statusBatteryOptimizations trackerStatusStatus} <br>
            Phone in power save mode: #{show $ statusPhonePowerSaveMode trackerStatusStatus}
          $nothing
            <em>Status unknown
        <section>
          <h2> _{MsgLastTrackerPosition}
          $maybe Entity _ Ping{..} <- maybePing
            Position: #{show pingGeopos} <br>
            Timestamp: #{show pingTimestamp} <br>
            $maybe ticketId <- pingTicket
              Ticket: <a href="@{TicketViewR (coerce ticketId)}">#{UUID.toText (coerce ticketId)}</a>
            $nothing
              Ticket: (no assigned ticket)
          $nothing
            (none)
        |]


postTrackerDeleteR :: Text -> Handler Html
postTrackerDeleteR name = do
  runDB $ delete do
    tracker <- from (table @Tracker)
    where_ (tracker ^. TrackerName ==. val name)
  redirect TrackersR