Check for an open interval on project switch.
[?]
Aug 27, 2020, 12:42 AM
2J37EVJMX255K3XEJHTZGRPEIRMAQ62JQWOA7JU3YTZUB6PUPWVQCDependencies
- [2]
OUR4PAOTUse local dates for display of intervals. - [3]
SFWL5626Initial release of UI. - [4]
IPG33FAWAdd billing daemon - [5]
BROSTG5KBeginning of modularization of server. - [6]
2G3GNDDUEvent logging is now functioning in postgres. - [7]
GCVQD44VCreate amends endpoint, switch to UUID primary keys - [8]
HMDM3B55Implement core of payments/billing infrastructure. - [9]
G4BS4NNDAdd simple shell script demonstrating how to invite a companion. - [10]
AL37SVTCImplement payments service endpoints. - [11]
B6HWAPDPModularize & update to recent haskoin. - [12]
ZIG57EE6Fix project selection, end log end on project switch. - [13]
5XFJNUAZStart of addition of project infrastructure. - [14]
XTBSG4C7Adding serveJSON combinator to eliminate some boilerplate from handlers. - [15]
EQXRXRZDChanged to use tasty instead of test-framework - [16]
EZQG2APBUpdate task list. - [17]
QU5FW67RAdd project selection to time tracker. - [18]
NEDDHXUKReformat via stylish-haskell - [19]
MGOF7IUFUpdate TASKS list to reflect completed projects. - [20]
Z7KS5XHHVery WIP. Wow. - [21]
7HPY3QPFFix linting errors. (yay hlint!) - [22]
PBD7LZYQPostgres & auth are beginning to function. - [23]
7XN3I3QJAdd 'loggedIntervals' endpoint. - [24]
HO2PFRABClient login now handles response correctly. - [25]
JXG3FCXYUpgrade ps + halogen versions. - [26]
NJNMO72SAdd zcash.com submodule and update client to modern halogen. - [27]
CDHZL3RPAdd a couple of other CLI utilities for interacing with the service. - [28]
EFSXYZPOAutoformat everything with brittany. - [29]
I2KHGVD4Require project permissions for access to most data. - [30]
7DBNV3GVInitial, stack-based impl of time log event reduction. - [31]
73NDXDEZBegin implementation of billing event persistence. - [32]
AWWC6P5ZAdd migration to include payment network with addresses. - [33]
RSF6UAJKBreak out api module for timeline. - [34]
A6HKMINBAttempting to improve JSON handling. - [35]
RPAJLHMTChange to use UUIDs instead of ints for primary keys. - [36]
SCXG6TJWMake log reduction safer in presence of overlapping events. - [37]
O5FVTOM6Undo JSON silliness, enable a couple more routes. - [38]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [39]
QMEYU4MWAdd display for prior intervals. - [*]
BFZN4SUAMake timeline component work. - [*]
IZEVQF62Work in progress replacing sqlite with postgres. - [*]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [*]
ADMKQQGCInitial empty Snap project.
Change contents
- edit in client/src/Aftok/Api/Timeline.purs at line 9
import Data.Array (head) - replacement in client/src/Aftok/Api/Timeline.purs at line 187
Before t -> ["before=" <> t]During (Interval x) -> ["after=" <> x.start, "before=" <> x.end]After t -> ["after=" <> t]Before t -> ["before=" <> t, "limit=100"]During (Interval x) -> ["after=" <> x.start, "before=" <> x.end, "limit=100"]After t -> ["after=" <> t, "limit=100"] - edit in client/src/Aftok/Api/Timeline.purs at line 198[4.6499]
apiLatestEvent :: ProjectId -> Aff (Either TimelineError (Maybe Event))apiLatestEvent pid = doresponse <- get RF.json ("/api/user/projects/" <> pidStr pid <> "/events")liftEffect<<< runExceptT<<< map head<<< map decompose<<< withExceptT LogFailure$ parseDatedResponse response - replacement in client/src/Aftok/Timeline.purs at line 54
import Aftok.Project (Project, Project'(..), ProjectId, pidStr)import Aftok.Project (Project, Project'(..), ProjectId) --, pidStr) - edit in client/src/Aftok/Timeline.purs at line 96
, getLatestEvent :: ProjectId -> m (Either TimelineError (Maybe TL.Event)) - replacement in client/src/Aftok/Timeline.purs at line 164
active <- isJust <$> H.gets (_.active)oldActive <- isJust <$> H.gets (_.active) - replacement in client/src/Aftok/Timeline.purs at line 166
when (active && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject)-- End any active intervals when switching projects.when (oldActive && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) - edit in client/src/Aftok/Timeline.purs at line 170
- replacement in client/src/Aftok/Timeline.purs at line 175
(system.log $ "Error occurred listing intervals") *>(system.log $ "Error occurred listing intervals" <> show err ) *> - replacement in client/src/Aftok/Timeline.purs at line 178
(system.log $ "Got " <> show (length ivals :: Int) <> " intervals for project " <> pidStr (unwrap p).projectId) *>--(system.log $ "Got " <> show (length ivals :: Int) <> " intervals for project " <> pidStr (unwrap p).projectId) *> - edit in client/src/Aftok/Timeline.purs at line 180
- replacement in client/src/Aftok/Timeline.purs at line 185
H.modify_ (_ { selectedProject = Just p, history = hist })latestEventResponse <- lift $ caps.getLatestEvent (unwrap p).projectIdnow <- lift $ system.nowactive <- lift $ case latestEventResponse ofLeft err ->(system.log $ "Error occurred retrieving the latest event: " <> show err) *>pure NothingRight latestEvent -> dolet activeInterval :: TL.Event -> m (Maybe Interval)activeInterval ev = case ev ofTL.StartEvent i ->(system.log $ "Project has an open active interval starting " <> show i) *>(Just <<< interval i <$> system.now)TL.StopEvent _ ->pure Nothingjoin <$> traverse activeInterval latestEvent - edit in client/src/Aftok/Timeline.purs at line 202
H.modify_ (_ { selectedProject = Just p, history = hist, active = active }) - edit in client/src/Aftok/Timeline.purs at line 342
, getLatestEvent: TL.apiLatestEvent - edit in client/src/Aftok/Timeline.purs at line 351
, getLatestEvent: \_ -> Right <$> pure Nothing - replacement in client/src/Aftok/Timeline.purs at line 385
lift <<< system.log $ "Splitting interval " <> show i--lift <<< system.log $ "Splitting interval " <> show i - replacement in client/src/Aftok/Timeline.purs at line 395
lift <<< system.log $ "Split result: " <> show split--lift <<< system.log $ "Split result: " <> show split - replacement in lib/Aftok/Database/PostgreSQL.hs at line 378
pgEval (FindEvents (ProjectId pid) (UserId uid) ival) = dopgEval (FindEvents (ProjectId pid) (UserId uid) rquery limit) = do - replacement in lib/Aftok/Database/PostgreSQL.hs at line 380
letq (Before e) = pquerycase rquery of(Before e) -> pquery - replacement in lib/Aftok/Database/PostgreSQL.hs at line 388
WHERE project_id = ? AND user_id = ? AND event_time <= ? |](pid, uid, fromThyme e)q (During s e) = pqueryWHERE project_id = ? AND user_id = ? AND event_time <= ?ORDER BY event_time DESCLIMIT ?|](pid, uid, fromThyme e, limit)(During s e) -> pquery - replacement in lib/Aftok/Database/PostgreSQL.hs at line 400
AND event_time >= ? AND event_time <= ? |](pid, uid, fromThyme s, fromThyme e)q (After s) = pqueryAND event_time >= ? AND event_time <= ?ORDER BY event_time DESCLIMIT ?|](pid, uid, fromThyme s, fromThyme e, limit)(After s) -> pquery - replacement in lib/Aftok/Database/PostgreSQL.hs at line 411[4.7617]→[4.7617:7689](∅→∅),[4.7689]→[4.20359:20389](∅→∅),[4.16361]→[4.20359:20389](∅→∅),[4.20389]→[4.12005:12014](∅→∅),[4.6342]→[4.12005:12014](∅→∅),[4.12014]→[4.7690:8155](∅→∅)
WHERE project_id = ? AND user_id = ? AND event_time >= ? |](pid, uid, fromThyme s)q ivalpgEval (FindLatestEvents (ProjectId pid) (UserId uid) i) = domode <- askNetworkModepquery(logEntryParser mode)[sql| SELECT credit_to_type,credit_to_network, credit_to_address, credit_to_user_id, credit_to_project_id,event_type, event_time, event_metadataFROM work_eventsWHERE project_id = ?AND user_id = ?ORDER BY event_time DESCLIMIT ?|](pid, uid, i)WHERE project_id = ? AND user_id = ? AND event_time >= ?ORDER BY event_time DESCLIMIT ?|](pid, uid, fromThyme s, limit)(Always) -> pquery(logEntryParser mode)[sql| SELECT credit_to_type,credit_to_network, credit_to_address, credit_to_user_id, credit_to_project_id,event_type, event_time,event_metadataFROM work_eventsWHERE project_id = ? AND user_id = ?ORDER BY event_time DESCLIMIT ?|](pid, uid, limit) - edit in lib/Aftok/Database.hs at line 21
import Data.Word ( Word32 ) - replacement in lib/Aftok/Database.hs at line 61
FindEvents ::ProjectId -> UserId -> Interval' -> DBOp [LogEntry BTCNet]FindLatestEvents ::ProjectId -> UserId -> Int -> DBOp [LogEntry BTCNet]FindEvents ::ProjectId -> UserId -> RangeQuery -> Word32 -> DBOp [LogEntry BTCNet] - replacement in lib/Aftok/Database.hs at line 222[4.29294]→[4.29294:29370](∅→∅),[4.20200]→[4.8854:8899](∅→∅),[4.29370]→[4.8854:8899](∅→∅),[4.8854]→[4.8854:8899](∅→∅)
:: (MonadDB m) => ProjectId -> UserId -> Interval' -> m [LogEntry BTCNet]findEvents p u i = liftdb $ FindEvents p u i:: (MonadDB m) => ProjectId -> UserId -> RangeQuery -> Word32 -> m [LogEntry BTCNet]findEvents p u i l = liftdb $ FindEvents p u i l - edit in lib/Aftok/Database.hs at line 225[4.8233]→[4.8233:8375](∅→∅),[4.8375]→[4.1303:1304](∅→∅),[4.8899]→[4.1303:1304](∅→∅),[4.9207]→[4.1303:1304](∅→∅),[4.1640]→[4.1303:1304](∅→∅)
findLatestEvents :: (MonadDB m) => ProjectId -> UserId -> Int -> m [LogEntry BTCNet]findLatestEvents p u i = liftdb $ FindLatestEvents p u i - replacement in lib/Aftok/Interval.hs at line 9
, Interval'(..), interval', RangeQuery(..), rangeQuery - edit in lib/Aftok/Interval.hs at line 34
makeLenses ''Interval - replacement in lib/Aftok/Interval.hs at line 36[4.1361]→[4.4029:4076](∅→∅),[4.4076]→[4.1410:1529](∅→∅),[4.1410]→[4.1410:1529](∅→∅),[4.1529]→[4.4077:4099](∅→∅),[4.4099]→[4.1530:1553](∅→∅),[4.1887]→[4.1530:1553](∅→∅)
data Interval' = Before { _end' :: C.UTCTime }| During { _start' :: C.UTCTime, _end' :: C.UTCTime }| After { _start' :: C.UTCTime }makeLenses ''IntervalmakeLenses ''Interval'data RangeQuery= Before { _end' :: C.UTCTime }| During { _start' :: C.UTCTime, _end' :: C.UTCTime }| After { _start' :: C.UTCTime }| AlwaysmakeLenses ''RangeQuery - replacement in lib/Aftok/Interval.hs at line 46
interval' :: C.UTCTime -> C.UTCTime -> Interval'interval' s e = if s < e then During s e else During e srangeQuery :: C.UTCTime -> C.UTCTime -> RangeQueryrangeQuery s e = if s < e then During s e else During e s - file move: list_entries.sh → latest_events.sh
- replacement in scripts/latest_events.sh at line 23
"https://$AFTOK_HOST/api/projects/$PID/logEntries?after=2020-01-01T00:00:00Z"[3.311]"https://$AFTOK_HOST/api/projects/$PID/events?after=2020-01-01T00:00:00Z" - file addition: list_events.sh[4.1220]
#!/bin/bashif [ -f ".env" ]; thensource .envfiif [ -z "${AFTOK_HOST}" ]; thenAFTOK_HOST="aftok.com"fiif [ -z "${USER}" ]; thenread -p "Username: " USERechofiif [ -z "${PID}" ]; thenread -p "Project UUID: " PIDechoficurl --verbose --insecure --user $USER \--request GET \"https://$AFTOK_HOST/api/projects/$PID/events?after=2020-01-01T00:00:00Z" - replacement in server/Aftok/Snaplet/WorkLog.hs at line 87
userLogEntries :: S.Handler App App [LogEntry (NetworkId, Address)]userLogEntries = douserEvents :: S.Handler App App [LogEntry (NetworkId, Address)]userEvents = do - replacement in server/Aftok/Snaplet/WorkLog.hs at line 92[4.5069]→[4.59142:59348](∅→∅),[4.59348]→[4.14964:15050](∅→∅),[4.15050]→[4.12987:13024](∅→∅),[4.59425]→[4.12987:13024](∅→∅),[4.8589]→[4.12987:13024](∅→∅),[4.13024]→[4.5385:5386](∅→∅),[4.5385]→[4.5385:5386](∅→∅),[4.5386]→[4.8707:8862](∅→∅)
ival <- case endpoints of(Just s , Just e ) -> pure $ During s e(Nothing, Just e ) -> pure $ Before e(Just s , Nothing) -> pure $ After s(Nothing, Nothing) -> snapError400"You must specify at least one of the \"after\" or \"before\" query parameters"snapEval $ findEvents pid uid ivaluserLatestEntries :: S.Handler App App [LogEntry (NetworkId, Address)]userLatestEntries = douid <- requireUserIdpid <- requireProjectIdlet ival = case endpoints of(Just s , Just e ) -> During s e(Nothing, Just e ) -> Before e(Just s , Nothing) -> After s(Nothing, Nothing) -> Always - replacement in server/Aftok/Snaplet/WorkLog.hs at line 98
snapEval $ findLatestEvents pid uid limitsnapEval $ findEvents pid uid ival limit - replacement in server/Aftok/Snaplet/WorkLog.hs at line 102
workIndex <$> userLogEntriesworkIndex <$> userEvents - replacement in server/Main.hs at line 74
serveJSON (workIndexJSON nmode) $ method GET projectWorkIndexserveJSON (workIndexJSON nmode) (method GET projectWorkIndex) - replacement in server/Main.hs at line 84
userLogEntriesRoute =serveJSON (fmap $ logEntryJSON nmode) $ method GET userLogEntriesuserEventsRoute =serveJSON (fmap $ logEntryJSON nmode) $ method GET userEvents - replacement in server/Main.hs at line 126
, ("user/projects/:projectId/logEntries" , userLogEntriesRoute), ("user/projects/:projectId/events" , userEventsRoute)