Add error reporting to signup form.
[?]
Jan 31, 2021, 2:08 AM
U7YAT2ZK6GMS7KVFFEQTDRFX6GIN7HVHNWGKIFDGJGE2G2IXSF6QCDependencies
- [2]
UD5T5B7AUpdate email invitation workflow. - [3]
APOATM4XAdd getProjectDetail call to project API - [4]
RV7ZIULZUpdate overview to have access to the real project detail capability. - [5]
QMEYU4MWAdd display for prior intervals. - [6]
7HPY3QPFFix linting errors. (yay hlint!) - [7]
NAFJ6RB3Minor module reorg. - [8]
Z5KNL332Add skeleton of project overview HTML. - [9]
A6HKMINBAttempting to improve JSON handling. - [10]
OV5AKJHARemove unused LogInterval type. - [11]
2G3GNDDUEvent logging is now functioning in postgres. - [12]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [13]
2XQD6KKKAdd invitation logic and clean up DBProg error handling. - [14]
EFSXYZPOAutoformat everything with brittany. - [15]
Z7CQXTU7Update login scripts, add script for XHR login interface. - [16]
QU5FW67RAdd project selection to time tracker. - [17]
O2BZOX7MAdd signup form, captcha check. - [18]
NEDDHXUKReformat via stylish-haskell - [19]
B4MTB6UOPersist project across pages. - [20]
POX3UAMTEnabling logging of time to contributor/project accounts - [21]
PBD7LZYQPostgres & auth are beginning to function. - [22]
5R2Z7FSXInitial rendering for signup controls. - [23]
PPW6ROC5Render project data - [24]
GCVQD44VCreate amends endpoint, switch to UUID primary keys - [25]
GLQSD33YUse mock capability for overview init. - [26]
N4NDAZYTInitial implementation of payouts. - [27]
PT4276XCAdd logout functionality. - [28]
7TQPQW3NBegin adding parsing for project detail. - [29]
UWMGUJOWAutoformat sources. - [30]
O5FVTOM6Undo JSON silliness, enable a couple more routes. - [31]
BROSTG5KBeginning of modularization of server. - [32]
WRPIYG3EUse project listing functionality to check for whether we have a cookie. - [33]
CDHZL3RPAdd a couple of other CLI utilities for interacing with the service. - [34]
OUR4PAOTUse local dates for display of intervals. - [35]
ENNZIQJGUse live signup API for client. - [36]
X3ES7NUAFine. I'll use ormolu. At least it doesn't break the code. - [37]
5SBSBFLSBind log directories to local paths for development. - [38]
XTBSG4C7Adding serveJSON combinator to eliminate some boilerplate from handlers. - [39]
IPG33FAWAdd billing daemon - [40]
G4BS4NNDAdd simple shell script demonstrating how to invite a companion. - [41]
MU6WOCCJUpdate auctions to permit zcash as a funding currency. - [42]
BFZN4SUAMake timeline component work. - [43]
M4PWY5RUPreliminary work to add support for Zcash payments. - [44]
QAC2QJ32Add project overview page to client. - [45]
GMYPBCWEMake docker-compose work. - [46]
JXG3FCXYUpgrade ps + halogen versions. - [47]
NJNMO72SAdd zcash.com submodule and update client to modern halogen. - [48]
2OIPAQCBMerge branch 'master' of github.com:nuttycom/ananke - [49]
J6S23MDGUse server timestamps for interval start and end. - [50]
RPAJLHMTChange to use UUIDs instead of ints for primary keys. - [51]
HALRDT2FAdded initial auction create route. - [52]
DFOBMSAOInitial work on payments API - [53]
3GLHIR4FAdd migrate script for prod system. - [54]
4QX5E5ACInitial compilation of payouts function succeeds. - [55]
Y35QCWYWMinor improvement in WorkIndex type to eliminate duplicated information. - [56]
GKGVYBZGAdded JSON serialization to TimeLog - [57]
NVOCQVASInitial failing tests. - [58]
NAS4BFL4Trivial stylish-haskell reformat. - [59]
QH4UB73NFormat with purty. - [60]
SFWL5626Initial release of UI. - [61]
2J37EVJMCheck for an open interval on project switch. - [62]
IZEVQF62Work in progress replacing sqlite with postgres. - [63]
B6HWAPDPModularize & update to recent haskoin. - [64]
RSF6UAJKBreak out api module for timeline. - [65]
4354Y4PEAdd endpoint to list project contributors. - [66]
HMDM3B55Implement core of payments/billing infrastructure. - [67]
I2KHGVD4Require project permissions for access to most data. - [68]
XA7SOE6JDockerize reactclient. - [69]
A2J7B4SCInitial impl of depreciation function. - [70]
IR75ZMX3Return actual events for interval ends, not just timestamps. - [71]
AAALU5A2Fix client routing - [72]
7KZP4RHZSwitch from Data.Time to Data.Thyme - [73]
KEP5WUFJConvert project to stack-based build. - [74]
SAESJLLYInitial experiments in hash routing. - [*]
RB2ETNIFAdd skeletal PureScript client project. - [*]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [*]
U256ZALIAdd captcha check to register route. - [*]
ADMKQQGCInitial empty Snap project.
Change contents
- replacement in client/src/Aftok/Api/Account.purs at line 93
pure UsernameCheckOKresult <- get RF.ignore ("/api/validate_username?username=" <> uname)pure$ case result ofLeft err -> UsernameCheckTakenRight r| r.status == StatusCode 200 -> UsernameCheckOKRight r -> UsernameCheckTaken - replacement in client/src/Aftok/Api/Account.purs at line 104[5.1318]→[5.521:644](∅→∅),[5.521]→[5.521:644](∅→∅),[5.644]→[5.1319:1401](∅→∅),[5.1401]→[5.718:832](∅→∅),[5.718]→[5.718:832](∅→∅)
case result ofLeft err -> dolog ("ZAddr validation failed: " <> printError err)pure ZAddrCheckInvalidRight r| r.status == StatusCode 200 -> dopure ZAddrCheckValidRight r -> dolog ("ZAddr was determined to be invalid: " <> r.statusText)pure ZAddrCheckInvalidpure$ case result ofLeft err -> ZAddrCheckInvalidRight r| r.status == StatusCode 200 -> ZAddrCheckValidRight r -> ZAddrCheckInvalid - edit in client/src/Aftok/Api/Json.purs at line 58
type Decode a= Json -> Either String a - replacement in client/src/Aftok/Api/Json.purs at line 62
decodeDatedJson :: forall t. Traversable t => DecodeJson (t String) => Json -> ExceptT String Effect (t DateTime)decodeDatedJson json = dodecoded <- except $ decodeJson jsondecodeDatedJson :: forall t. Traversable t => Decode (t String) -> Json -> ExceptT String Effect (t DateTime)decodeDatedJson decode json = dodecoded <- except $ decode json - replacement in client/src/Aftok/Api/Json.purs at line 70
DecodeJson (t String) =>Decode (t String) -> - replacement in client/src/Aftok/Api/Json.purs at line 73
parseDatedResponse = case _ ofparseDatedResponse decode = case _ of - replacement in client/src/Aftok/Api/Json.purs at line 77
StatusCode 200 -> withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson r.bodyStatusCode 200 -> withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson decode r.body - replacement in client/src/Aftok/Api/Json.purs at line 83
DecodeJson (t String) =>Decode (t String) -> - replacement in client/src/Aftok/Api/Json.purs at line 86
parseDatedResponseMay = case _ ofparseDatedResponseMay decode = case _ of - replacement in client/src/Aftok/Api/Json.purs at line 91
StatusCode 200 -> withExceptT (ParseFailure r.body) $ Just <<< map fromDateTime <$> decodeDatedJson r.bodyStatusCode 200 ->withExceptT (ParseFailure r.body)$ Just<<< map fromDateTime<$> decodeDatedJson decode r.body - replacement in client/src/Aftok/Api/Project.purs at line 7
-- import Data.Argonaut.Core (Json)import Data.Argonaut.Core (Json) - edit in client/src/Aftok/Api/Project.purs at line 9
-- import Data.Bifunctor (lmap) - replacement in client/src/Aftok/Api/Project.purs at line 17
import Data.Rational (Rational, (%))import Data.Ratio (Ratio, (%)) - edit in client/src/Aftok/Api/Project.purs at line 19
import Data.Tuple (Tuple(..)) - edit in client/src/Aftok/Api/Project.purs at line 24
import Foreign.Object (Object) - replacement in client/src/Aftok/Api/Project.purs at line 33
( APIError )import Aftok.Api.Json( decompose(APIError)import Aftok.Api.Json( Decode, decompose - edit in client/src/Aftok/Api/Project.purs at line 81
parseProject :: ProjectId -> Object Json -> Either String (Project' String)parseProject projectId pjson = doprojectName <- pjson .: "projectName"inceptionDate <- pjson .: "inceptionDate"initiator <- pjson .: "initiator"depf <- pjson .: "depf"pure $ Project' { projectId, projectName, inceptionDate, initiator, depf } - replacement in client/src/Aftok/Api/Project.purs at line 92
project <- x .: "project"pjson <- x .: "project" - replacement in client/src/Aftok/Api/Project.purs at line 94
projectName <- project .: "projectName"inceptionDate <- project .: "inceptionDate"initiator <- project .: "initiator"depf <- project .: "depf"pure $ Project' { projectId, projectName, inceptionDate, initiator, depf }parseProject projectId pjson - replacement in client/src/Aftok/Api/Project.purs at line 102
, revShare :: Rational, revShare :: Ratio Number - replacement in client/src/Aftok/Api/Project.purs at line 115
traverse f (Contributor' p) =Contributor' <<< (\b -> p { joinedOn = b }) <$> f (p.joinedOn)traverse f (Contributor' p) = Contributor' <<< (\b -> p { joinedOn = b }) <$> f (p.joinedOn) - replacement in client/src/Aftok/Api/Project.purs at line 125
revShareObj <- x .: "revenueShare"revShareObj <- x .: "revenureShare" - replacement in client/src/Aftok/Api/Project.purs at line 128
let revShare = num % denletrevShare = num % den - replacement in client/src/Aftok/Api/Project.purs at line 138
projectDetail ::forall date.Project' date ->M.Map UserId (Contributor' date) ->projectDetail ::forall date.Project' date ->M.Map UserId (Contributor' date) -> - replacement in client/src/Aftok/Api/Project.purs at line 143
projectDetail project contributors =ProjectDetail' { project, contributors }projectDetail project contributors = ProjectDetail' { project, contributors } - replacement in client/src/Aftok/Api/Project.purs at line 145
type ProjectDetail = ProjectDetail' DateTimetype ProjectDetail= ProjectDetail' DateTime - replacement in client/src/Aftok/Api/Project.purs at line 158
traverse f (ProjectDetail' p) =projectDetail <$> traverse f p.project<*> (map unwrap $ traverse f (Compose p.contributors))traverse f (ProjectDetail' p) =projectDetail <$> traverse f p.project<*> (map unwrap $ traverse f (Compose p.contributors)) - replacement in client/src/Aftok/Api/Project.purs at line 163[5.4060]→[5.3469:3546](∅→∅),[5.3546]→[5.4125:4203](∅→∅),[5.4125]→[5.4125:4203](∅→∅),[5.4203]→[5.3547:3639](∅→∅)
instance decodeJsonProjectDetail :: DecodeJson (ProjectDetail' String) wheredecodeJson json = dox <- decodeJson jsonproject <- x .: "project"contributors <- x .: "contributors"pure $ ProjectDetail' { project, contributors }parseProjectDetail :: ProjectId -> Decode (ProjectDetail' String)parseProjectDetail pid json = dox <- decodeJson jsonproject <- parseProject pid =<< x .: "project"(contribList :: Array (Contributor' String)) <- x .: "contributors"letcontributors = M.fromFoldable $ map (\c@(Contributor' xs) -> Tuple xs.userId c) contribListpure $ ProjectDetail' { project, contributors } - replacement in client/src/Aftok/Api/Project.purs at line 175
EC.liftEffectEC.liftEffect - replacement in client/src/Aftok/Api/Project.purs at line 179
$ parseDatedResponse response$ parseDatedResponse decodeJson response - replacement in client/src/Aftok/Api/Project.purs at line 183
response <- get RF.json ("/api/user/projects/" <> pidStr pid <> "/detail")let parsed :: ExceptT APIError Effect (Maybe (ProjectDetail' Instant))parsed = parseDatedResponseMay responseEC.liftEffectresponse <- get RF.json ("/api/projects/" <> pidStr pid <> "/detail")letparsed :: ExceptT APIError Effect (Maybe (ProjectDetail' Instant))parsed = parseDatedResponseMay (parseProjectDetail pid) responseEC.liftEffect - edit in client/src/Aftok/Api/Project.purs at line 191[3.2250]→[5.5618:5619](∅→∅),[5.4185]→[5.5618:5619](∅→∅),[5.5618]→[5.5618:5619](∅→∅),[5.5619]→[5.4186:4187](∅→∅)
- edit in client/src/Aftok/Api/Recaptcha.js at line 10[5.3248]
exports.recaptchaRenderInternal = siteKey => elemId => () => {grecaptcha.render(document.getElementById(elemId),{ 'sitekey': siteKey });} - replacement in client/src/Aftok/Api/Recaptcha.purs at line 5
import Prelude (bind, (==), ($), pure)import Prelude (bind, (==), ($), pure, Unit) - edit in client/src/Aftok/Api/Recaptcha.purs at line 16
recaptchaRender :: String -> String -> Effect UnitrecaptchaRender = recaptchaRenderInternal - edit in client/src/Aftok/Api/Recaptcha.purs at line 20[5.3807]
foreign import recaptchaRenderInternal :: String -> String -> Effect Unit - replacement in client/src/Aftok/Api/Timeline.purs at line 191
kev <- withExceptT LogFailure $ parseDatedResponse responsekev <- withExceptT LogFailure $ parseDatedResponse decodeJson response - replacement in client/src/Aftok/Api/Timeline.purs at line 203
kev <- withExceptT LogFailure $ parseDatedResponse responsekev <- withExceptT LogFailure $ parseDatedResponse decodeJson response - replacement in client/src/Aftok/Api/Timeline.purs at line 247
$ parseDatedResponse response$ parseDatedResponse decodeJson response - replacement in client/src/Aftok/Api/Timeline.purs at line 257
$ parseDatedResponse response[5.5660]$ parseDatedResponse decodeJson response - edit in client/src/Aftok/Api/Types.purs at line 18
- replacement in client/src/Aftok/Overview.purs at line 20
import Data.Rational as Rimport Data.Ratio as R - replacement in client/src/Aftok/Overview.purs at line 63[4.71]→[5.873:899](∅→∅),[5.315]→[5.873:899](∅→∅),[5.849]→[5.873:899](∅→∅),[5.6486]→[5.873:899](∅→∅),[5.899]→[5.4228:4288](∅→∅)
import Aftok.Api.Project(Project, Project'(..), ProjectDetail, ProjectDetail'(..)import Aftok.Api.Project( Project, Project'(..), ProjectDetail, ProjectDetail'(..) - replacement in client/src/Aftok/Overview.purs at line 133
[ P.classes (ClassName <$> [ "container", "pt-6" ]) ][ HH.h1[ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ][ HH.text "Project Overview" ], HH.p[ P.classes (ClassName <$> [ "col-md-5", "text-muted", "text-center", "mx-auto" ]) ][ HH.text "Your project details" ], HH.div_[ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))[ P.classes (ClassName <$> [ "container", "pt-6" ]) ][ HH.h1[ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ][ HH.text "Project Overview" ], HH.p[ P.classes (ClassName <$> [ "col-md-5", "text-muted", "text-center", "mx-auto" ]) ][ HH.text "Your project details" ], HH.div_[ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))], HH.div[ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ](U.fromMaybe $ projectDetail <$> st.projectDetail) - edit in client/src/Aftok/Overview.purs at line 152[5.4674]→[5.1614:1731](∅→∅),[5.1614]→[5.1614:1731](∅→∅),[5.1731]→[5.1443:1504](∅→∅),[5.1504]→[5.1790:1800](∅→∅),[5.1790]→[5.1790:1800](∅→∅)
, HH.div[ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ](U.fromMaybe $ projectDetail <$> st.projectDetail)] - replacement in client/src/Aftok/Overview.purs at line 156
let (Project' project) = detail.projectlet(Project' project) = detail.project - replacement in client/src/Aftok/Overview.purs at line 161[5.2061]→[5.2061:2247](∅→∅),[5.2247]→[5.1505:1546](∅→∅),[5.1546]→[5.2315:2498](∅→∅),[5.2315]→[5.2315:2498](∅→∅)
[ P.id_ "projectOverview", P.classes (ClassName <$> ["pt-3"]) ][ HH.div-- header[ P.classes (ClassName <$> ["row", "pt-3", "font-weight-bold" ]) ][ colmd2 (Just "Project Name"), colmd2 (Just "Undepreciated Period"), colmd2 (Just "Depreciation Duration"), colmd2 (Just "Originator"), colmd2 (Just "Origination Date")[ P.id_ "projectOverview", P.classes (ClassName <$> [ "pt-3" ]) ][ HH.div-- header[ P.classes (ClassName <$> [ "row", "pt-3", "font-weight-bold" ]) ][ colmd2 (Just "Project Name"), colmd2 (Just "Undepreciated Period"), colmd2 (Just "Depreciation Duration"), colmd2 (Just "Originator"), colmd2 (Just "Origination Date")], HH.div[ P.classes (ClassName <$> [ "row", "pt-3" ]) ]( [ colmd2 (Just project.projectName) ]<> depreciationCols project.depf<> [ colmd2 ((\(Contributor' p) -> p.handle) <$> M.lookup project.initiator detail.contributors), colmd2 (Just $ dateStr (date project.inceptionDate))]) - edit in client/src/Aftok/Overview.purs at line 180[5.3910]→[5.2499:2516](∅→∅),[5.2516]→[5.1547:1655](∅→∅),[5.1655]→[3.2252:2296](∅→∅),[3.2296]→[5.4720:4825](∅→∅),[5.4720]→[5.4720:4825](∅→∅),[5.4825]→[5.1656:1722](∅→∅),[5.2822]→[5.1656:1722](∅→∅),[5.1722]→[5.2878:2902](∅→∅),[5.2878]→[5.2878:2902](∅→∅)
, HH.div[ P.classes (ClassName <$> ["row", "pt-3"]) ]([ colmd2 (Just project.projectName) ] <>depreciationCols project.depf <>[ colmd2 ((\(Contributor' p) -> p.handle) <$> M.lookup project.initiator detail.contributors), colmd2 (Just $ dateStr (date project.inceptionDate))])] - replacement in client/src/Aftok/Overview.purs at line 181
[ P.id_ "contributors" ]([ HH.div-- header[ P.classes (ClassName <$> ["row", "pt-3", "font-weight-bold" ]) ][ colmd2 (Just "Contributor"), colmd2 (Just "Joined"), colmd2 (Just "Contributed Hours"), colmd2 (Just "Current Revenue Share")]] <>(contributorCols <$> (L.toUnfoldable $ M.values detail.contributors)))[ P.id_ "contributors" ]( [ HH.div-- header[ P.classes (ClassName <$> [ "row", "pt-3", "font-weight-bold" ]) ][ colmd2 (Just "Contributor"), colmd2 (Just "Joined"), colmd2 (Just "Contributed Hours"), colmd2 (Just "Current Revenue Share")]]<> (contributorCols <$> (L.toUnfoldable $ M.values detail.contributors))) - replacement in client/src/Aftok/Overview.purs at line 203[5.4911]→[5.4911:5086](∅→∅),[5.5086]→[5.2571:2647](∅→∅),[5.2571]→[5.2571:2647](∅→∅),[5.2647]→[5.5087:5120](∅→∅),[5.5120]→[5.2682:2734](∅→∅),[5.2682]→[5.2682:2734](∅→∅),[5.2734]→[5.5121:5175](∅→∅),[5.5175]→[5.2794:2829](∅→∅),[5.2794]→[5.2794:2829](∅→∅),[5.2829]→[5.11322:11330](∅→∅),[5.3157]→[5.11322:11330](∅→∅),[5.3910]→[5.11322:11330](∅→∅)
contributorCols (Contributor' pud) =let pct = maybe "N/A" (\f -> F.toString (f * F.fromInt 100)) (F.fromNumber (R.toNumber pud.revShare) :: Maybe (F.Fixed F.P10000))in HH.div[ P.classes (ClassName <$> ["row", "pt-3", "pb-2" ]) ][ colmd2 (Just pud.handle), colmd2 (Just $ dateStr (date pud.joinedOn)), colmd2 (Just $ show (unwrap pud.timeDevoted)), colmd2 (Just $ pct <> "%")]contributorCols (Contributor' pud) =letshareFrac = R.numerator pud.revShare `div` R.denominator pud.revSharepct = maybe "N/A" (\f -> F.toString (f * F.fromInt 100)) (F.fromNumber shareFrac :: Maybe (F.Fixed F.P10000))inHH.div[ P.classes (ClassName <$> [ "row", "pt-3", "pb-2" ]) ][ colmd2 (Just pud.handle), colmd2 (Just $ dateStr (date pud.joinedOn)), colmd2 (Just $ show (unwrap pud.timeDevoted)), colmd2 (Just $ pct <> "%")] - replacement in client/src/Aftok/Overview.purs at line 218
colmd2 xs = HH.div [ P.classes (ClassName <$> ["col-md-2"]) ] (U.fromMaybe $ HH.text <$> xs)colmd2 xs = HH.div [ P.classes (ClassName <$> [ "col-md-2" ]) ] (U.fromMaybe $ HH.text <$> xs) - replacement in client/src/Aftok/Overview.purs at line 220[5.5940]→[5.5940:10364](∅→∅),[5.10364]→[5.3920:3921](∅→∅),[5.11330]→[5.3920:3921](∅→∅),[5.3920]→[5.3920:3921](∅→∅)
-- </section>-- <!-- Map payouts -->-- <div class="row font-weight-bold">-- <div class="col-md-2">-- </div>-- <div class="col-md-4">-- Payments-- </div>-- <div class="col-md-6">---- </div>-- </div>-- <div class="row">-- <div class="col-md-2">-- </div>-- <div class="col-md-2">-- Oct 20 2020-- </div>-- <div class="col-md-2">-- 100 zec-- </div>-- <div class="col-md-2">-- Acme PaidUsRight-- </div>-- <div class="col-md-4">-- </div>-- </div>-- <!-- map payout creditTos-->-- <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Freuline Fred-- </div>-- <div class="col-md-2">-- 2.4 zec-- </div>-- <div class="col-md-2">-- 2.4 %-- </div>-- <div class="col-md-2">-- </div>-- </div>-- <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Goobie Works A Lot-- </div>-- <div class="col-md-2">-- 50 zec-- </div>-- <div class="col-md-2">-- 50 %-- </div>-- <div class="col-md-2">-- </div>-- </div> <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Average Fella-- </div>-- <div class="col-md-2">-- 25 zec-- </div>-- <div class="col-md-2">-- 25 %-- </div>-- <div class="col-md-2">-- </div>-- </div> <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Cool Kid-- </div>-- <div class="col-md-2">-- 24.6 zec-- </div>-- <div class="col-md-2">-- 24.6 %-- </div>-- <div class="col-md-2">-- </div>-- </div>---- </section>------ <!-- New Project form-->-- <section id="addProject">---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Project Name</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="projectName" name="projectName" />-- </div>-- </div>---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Undepreciated Period ( Months )</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="undepreciatedPeriod" name="undepreciatedPeriod" />-- </div>-- </div>---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Depreciation Duration ( Months )</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="depreciationDuration" name="depreciationDuration" />-- </div>-- </div>---- <div class="row pt-3 pb-3">-- <div class="col-md-2">-- </div>-- <div class="col-md-10">-- <button class="btn btn-sm btn-primary lift ml-auto">Add Project</button>-- </div>-- </div>---- </section>-- </section>-- <!-- Map payouts -->-- <div class="row font-weight-bold">-- <div class="col-md-2">-- </div>-- <div class="col-md-4">-- Payments-- </div>-- <div class="col-md-6">---- </div>-- </div>-- <div class="row">-- <div class="col-md-2">-- </div>-- <div class="col-md-2">-- Oct 20 2020-- </div>-- <div class="col-md-2">-- 100 zec-- </div>-- <div class="col-md-2">-- Acme PaidUsRight-- </div>-- <div class="col-md-4">-- </div>-- </div>-- <!-- map payout creditTos-->-- <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Freuline Fred-- </div>-- <div class="col-md-2">-- 2.4 zec-- </div>-- <div class="col-md-2">-- 2.4 %-- </div>-- <div class="col-md-2">-- </div>-- </div>-- <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Goobie Works A Lot-- </div>-- <div class="col-md-2">-- 50 zec-- </div>-- <div class="col-md-2">-- 50 %-- </div>-- <div class="col-md-2">-- </div>-- </div> <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Average Fella-- </div>-- <div class="col-md-2">-- 25 zec-- </div>-- <div class="col-md-2">-- 25 %-- </div>-- <div class="col-md-2">-- </div>-- </div> <div class="row pt-3">-- <div class="col-md-4">-- </div>-- <div class="col-md-2">-- Cool Kid-- </div>-- <div class="col-md-2">-- 24.6 zec-- </div>-- <div class="col-md-2">-- 24.6 %-- </div>-- <div class="col-md-2">-- </div>-- </div>---- </section>------ <!-- New Project form-->-- <section id="addProject">---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Project Name</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="projectName" name="projectName" />-- </div>-- </div>---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Undepreciated Period ( Months )</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="undepreciatedPeriod" name="undepreciatedPeriod" />-- </div>-- </div>---- <div class="row pt-3">-- <div class="col-md-4">-- <span class="float-right">Depreciation Duration ( Months )</span>-- </div>-- <div class="col-md-4">-- <input type="text" id="depreciationDuration" name="depreciationDuration" />-- </div>-- </div>---- <div class="row pt-3 pb-3">-- <div class="col-md-2">-- </div>-- <div class="col-md-10">-- <button class="btn btn-sm btn-primary lift ml-auto">Add Project</button>-- </div>-- </div>---- </section> - replacement in client/src/Aftok/Overview.purs at line 367
detail <- lift $ caps.getProjectDetail pidcase detail ofLeft err -> lift $ system.error (show err)Right d -> H.modify_ (_ { projectDetail = d })detail <- lift $ caps.getProjectDetail pidcase detail ofLeft err -> lift $ system.error (show err)Right d -> H.modify_ (_ { projectDetail = d }) - replacement in client/src/Aftok/Overview.purs at line 379[5.10399]→[5.950:1066](∅→∅),[5.1066]→[4.346:394](∅→∅),[4.394]→[5.1104:1255](∅→∅),[5.1104]→[5.1104:1255](∅→∅),[5.1255]→[3.2297:2372](∅→∅),[3.2372]→[5.1255:1267](∅→∅),[5.5512]→[5.1255:1267](∅→∅),[5.1255]→[5.1255:1267](∅→∅),[5.1267]→[5.5513:5619](∅→∅),[5.5619]→[5.1436:1460](∅→∅),[5.1436]→[5.1436:1460](∅→∅),[5.1460]→[5.5620:5690](∅→∅),[5.5690]→[5.1546:1568](∅→∅),[5.1546]→[5.1546:1568](∅→∅)
{ getProjectDetail: \pid -> dot <- liftEffect nowDateTimeuid <- UserId <$> liftEffect genUUIDpure <<< Right <<< Just $ ProjectDetail'{ project: Project'{ projectId: pid, projectName: "Fake Project", inceptionDate: t, initiator: uid, depf: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 }}, contributors: M.singleton uid $ Contributor'{ userId: uid, handle: "Joe", joinedOn: t, timeDevoted: Hours 100.0, revShare: 55 R.% 100}}{ getProjectDetail:\pid -> dot <- liftEffect nowDateTimeuid <- UserId <$> liftEffect genUUIDpure <<< Right <<< Just$ ProjectDetail'{ project:Project'{ projectId: pid, projectName: "Fake Project", inceptionDate: t, initiator: uid, depf: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 }}, contributors:M.singleton uid$ Contributor'{ userId: uid, handle: "Joe", joinedOn: t, timeDevoted: Hours 100.0, revShare: 55.0 R.% 100.0}} - edit in client/src/Aftok/Signup.purs at line 9
import Data.Map as Mimport Data.Tuple (Tuple(..)) - edit in client/src/Aftok/Signup.purs at line 22
import Web.UIEvent.MouseEvent as ME - edit in client/src/Aftok/Signup.purs at line 43
data SignupField= UsernameField| PasswordField| ConfirmField| EmailField| ZAddrField| CaptchaField| ErrFieldderive instance signupFieldEq :: Eq SignupFieldderive instance signupFieldOrd :: Ord SignupField - replacement in client/src/Aftok/Signup.purs at line 70
, signupErrors :: Array SignupError, signupErrors :: M.Map SignupField SignupError - edit in client/src/Aftok/Signup.purs at line 80
| Signin ME.MouseEvent - replacement in client/src/Aftok/Signup.purs at line 122
, signupErrors: [], signupErrors: M.empty - replacement in client/src/Aftok/Signup.purs at line 138
[ HH.text "You can use either an email address or zcash payment address for account recovery." ][ HH.text "You can use either an email address or shielded zcash address for account recovery." ] - replacement in client/src/Aftok/Signup.purs at line 150
[ HH.label [ P.for "username" ] [ HH.text "Username" ], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> [ "form-control" ]), P.id_ "username", P.placeholder "Choose a handle (username)", P.required true, P.autofocus true, P.value (fromMaybe "" st.username), E.onValueInput (Just <<< SetUsername)]]$ [ HH.label [ P.for "username" ] [ HH.text "Username" ], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> [ "form-control" ]), P.id_ "username", P.placeholder "Choose a handle (username)", P.required true, P.autofocus true, P.value (fromMaybe "" st.username), E.onValueInput (Just <<< SetUsername)]]<> signupErrors UsernameField st - replacement in client/src/Aftok/Signup.purs at line 165
[ HH.label [ P.for "password" ] [ HH.text "Password" ], HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> [ "form-control" ]), P.id_ "password", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.password), E.onValueInput (Just <<< SetPassword)], HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> [ "form-control" ]), P.id_ "passwordConfirm", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.passwordConfirm), E.onValueInput (Just <<< ConfirmPassword)]]$ [ HH.label [ P.for "password" ] [ HH.text "Password" ], HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> [ "form-control" ]), P.id_ "password", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.password), E.onValueInput (Just <<< SetPassword)]]<> signupErrors PasswordField st<> [ HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> [ "form-control" ]), P.id_ "passwordConfirm", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.passwordConfirm), E.onValueInput (Just <<< ConfirmPassword)]]<> signupErrors ConfirmField st - replacement in client/src/Aftok/Signup.purs at line 220
Acc.UsernameCheckOK -> pure unitAcc.UsernameCheckTaken -> H.modify_ (_ { signupErrors = [ UsernameTaken ] })Acc.UsernameCheckOK -> H.modify_ (\st -> st { signupErrors = M.delete UsernameField st.signupErrors })Acc.UsernameCheckTaken -> H.modify_ (\st -> st { signupErrors = M.insert UsernameField UsernameTaken st.signupErrors }) - replacement in client/src/Aftok/Signup.purs at line 225
when (any (notEq pass) confirm) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))if (any (notEq pass) confirm) then(H.modify_ (\st -> st { signupErrors = M.insert ConfirmField PasswordMismatch st.signupErrors }))else(H.modify_ (\st -> st { signupErrors = M.delete ConfirmField st.signupErrors })) - replacement in client/src/Aftok/Signup.purs at line 231
password <- H.gets (_.password)when (any (notEq confirm) password) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))pass <- H.gets (_.password)if (any (notEq confirm) pass) then(H.modify_ (\st -> st { signupErrors = M.insert ConfirmField PasswordMismatch st.signupErrors }))else(H.modify_ (\st -> st { signupErrors = M.delete ConfirmField st.signupErrors })) - replacement in client/src/Aftok/Signup.purs at line 238
SetRecoveryZAddr addr -> dolift $ system.log "Switching to signin..."zres <- lift $ caps.checkZAddr addrH.modify_ (_ { recoveryZAddr = Just addr })case zres ofAcc.ZAddrCheckValid -> pure unitAcc.ZAddrCheckInvalid -> H.modify_ (_ { signupErrors = [ ZAddrInvalid ] })Signin ev -> dolift $ system.log "Switching to signin..."lift $ system.preventDefault (ME.toEvent ev)H.raise SigninNavSetRecoveryZAddr addr ->--lift $ system.log "Switching to signin..."when (addr /= "")$ dozres <- lift $ caps.checkZAddr addrH.modify_ (_ { recoveryZAddr = Just addr })case zres ofAcc.ZAddrCheckValid -> H.modify_ (\st -> st { signupErrors = M.delete ZAddrField st.signupErrors })Acc.ZAddrCheckInvalid -> H.modify_ (\st -> st { signupErrors = M.insert ZAddrField ZAddrInvalid st.signupErrors }) - replacement in client/src/Aftok/Signup.purs at line 258
lift $ system.log "Sending signup request..."--lift $ system.log "Sending signup request..." - replacement in client/src/Aftok/Signup.purs at line 271
lift $ system.log "Got signup HTTP error."H.modify_ (_ { signupErrors = errors })leterrMap = M.fromFoldable $ map (\e -> Tuple (errField e) e) errors--lift $ system.log "Got signup HTTP error."H.modify_ (_ { signupErrors = errMap }) - replacement in client/src/Aftok/Signup.purs at line 277
lift <<< system.log $ "Got signup response " <> show response--lift <<< system.log $ "Got signup response " <> show response - replacement in client/src/Aftok/Signup.purs at line 280
Acc.CaptchaInvalid -> H.modify_ (_ { signupErrors = [ CaptchaError ] })Acc.ZAddrInvalid -> H.modify_ (_ { signupErrors = [ ZAddrInvalid ] })Acc.UsernameTaken -> H.modify_ (_ { signupErrors = [ UsernameTaken ] })Acc.ServiceError c m -> H.modify_ (_ { signupErrors = [ APIError { status: c, message: m } ] })Acc.CaptchaInvalid -> H.modify_ (_ { signupErrors = M.singleton CaptchaField CaptchaError })Acc.ZAddrInvalid -> H.modify_ (_ { signupErrors = M.singleton ZAddrField ZAddrInvalid })Acc.UsernameTaken -> H.modify_ (_ { signupErrors = M.singleton UsernameField UsernameTaken })Acc.ServiceError c m -> H.modify_ (_ { signupErrors = M.singleton ErrField (APIError { status: c, message: m }) })errField :: SignupError -> SignupFielderrField = case _ ofUsernameRequired -> UsernameFieldUsernameTaken -> UsernameFieldPasswordRequired -> PasswordFieldConfirmRequired -> ConfirmFieldPasswordMismatch -> ConfirmFieldEmailRequired -> EmailFieldZAddrRequired -> ZAddrFieldZAddrInvalid -> ZAddrFieldCaptchaError -> CaptchaFieldAPIError _ -> ErrFieldsignupErrors :: forall i a. SignupField -> SignupState -> Array (HH.HTML i a)signupErrors field st = case M.lookup field st.signupErrors of(Just UsernameRequired) -> err "Username is required"(Just UsernameTaken) -> err "Username is already taken"(Just PasswordRequired) -> err "Password is required"(Just ConfirmRequired) -> err "Confirm your password"(Just PasswordMismatch) -> err "Passwords do not match"(Just EmailRequired) -> err "Email address is required"(Just ZAddrRequired) -> err "Zcash address is required"(Just ZAddrInvalid) -> err "Not a valid Zcash address"(Just CaptchaError) -> err "Captcha failed; please try again"_ -> []whereerr str = [ HH.div_ [ HH.span [ P.classes (ClassName <$> [ "badge", "badge-danger-soft" ]) ] [ HH.text str ] ] ] - replacement in client/src/Aftok/Signup.purs at line 328
[ HH.text "Email" ]$ [ HH.text "Email" ] - replacement in client/src/Aftok/Signup.purs at line 350[5.7363]→[5.7363:7426](∅→∅),[5.7426]→[5.24447:24744](∅→∅),[5.24744]→[5.7708:7716](∅→∅),[5.7708]→[5.7708:7716](∅→∅)
[ HH.label [ P.for "email" ] [ HH.text "Email Address" ], HH.input[ P.type_ P.InputEmail, P.classes (ClassName <$> [ "form-control" ]), P.id_ "email", P.placeholder "name@address.com", P.value (fromMaybe "" st.recoveryEmail), E.onValueInput (Just <<< SetRecoveryEmail)]]$ [ HH.label [ P.for "email" ] [ HH.text "Email Address" ], HH.input[ P.type_ P.InputEmail, P.classes (ClassName <$> [ "form-control" ]), P.id_ "email", P.placeholder "name@address.com", P.value (fromMaybe "" st.recoveryEmail), E.onValueInput (Just <<< SetRecoveryEmail)]]<> signupErrors EmailField st - replacement in client/src/Aftok/Signup.purs at line 364[5.7779]→[5.24757:25082](∅→∅),[5.25082]→[5.7975:7987](∅→∅),[5.7975]→[5.7975:7987](∅→∅),[5.7987]→[5.25083:25381](∅→∅),[5.1342]→[5.8072:8084](∅→∅),[5.25381]→[5.8072:8084](∅→∅),[5.8072]→[5.8072:8084](∅→∅),[5.8389]→[5.8389:8397](∅→∅)
[ HH.label[ P.for "zaddr" ][ HH.text "Zcash Shielded Address", HH.a[ P.attr (AttrName "data-toggle") "modal", P.href "#modalAboutZAddr"][ HH.img [ P.src "/assets/img/icons/duotone-icons/Code/Info-circle.svg" ]]], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> [ "form-control" ]), P.id_ "email", P.placeholder "Enter a Zcash shielded address", P.value (fromMaybe "" st.recoveryZAddr), E.onValueInput (Just <<< SetRecoveryZAddr)]]$ [ HH.label[ P.for "zaddr" ][ HH.text "Zcash Shielded Address", HH.a[ P.attr (AttrName "data-toggle") "modal", P.href "#modalAboutZAddr"][ HH.img [ P.src "/assets/img/icons/duotone-icons/Code/Info-circle.svg" ]]], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> [ "form-control" ]), P.id_ "email", P.placeholder "Enter a Zcash shielded address", P.value (fromMaybe "" st.recoveryZAddr), E.onValueInput (Just <<< SetRecoveryZAddr)]]<> signupErrors ZAddrField st - replacement in client/src/Aftok/Signup.purs at line 387
{ checkUsername: \_ -> pure Acc.UsernameCheckOK{ checkUsername: Acc.checkUsername - replacement in client/src/Aftok/Timeline.purs at line 169
[ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))[ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p)) - edit in client/src/Aftok/Types.purs at line 86
derive instance userIdEq :: Eq UserIdderive instance userIdOrd :: Ord UserId - edit in client/src/Aftok/Types.purs at line 91
derive instance userIdEq :: Eq UserIdderive instance userIdOrd :: Ord UserId - replacement in client/src/Aftok/Types.purs at line 95
uuidStr <- decodeJson jsonuuidStr <- decodeJson json - edit in client/src/Aftok/Types.purs at line 102
- edit in client/src/Aftok/Types.purs at line 104
- replacement in client/src/Aftok/Types.purs at line 109
uuidStr <- decodeJson jsonuuidStr <- decodeJson json - edit in client/src/Aftok/Types.purs at line 112
- edit in client/src/Aftok/Types.purs at line 121
- replacement in client/src/Main.purs at line 44
overview = Overview.mockCapabilityoverview = Overview.apiCapability - replacement in client/src/Main.purs at line 170
pure $ case result ofAcc.LoginForbidden -> VLoginAcc.LoginError _ -> VLogin_ -> case other of"timeline" -> VTimeline_ -> VOverviewpure$ case result ofAcc.LoginForbidden -> VLoginAcc.LoginError _ -> VLogin_ -> case other of"timeline" -> VTimeline_ -> VOverview - replacement in client/src/Main.purs at line 178
SignupAction (Signup.SignupComplete _) -> navigate VTimelineSignupAction (Signup.SignupComplete _) -> navigate VOverview - replacement in client/src/Main.purs at line 180
LoginAction (Login.LoginComplete _) -> navigate VTimelineLoginAction (Login.LoginComplete _) -> navigate VOverview - replacement in client/src/Main.purs at line 225
[ HH.text "Aftok" ][ HH.a [ P.href "/" ] [ HH.text "Aftok" ] ] - edit in docker-compose.yml at line 31
target: /opt/aftok/client/dist-volumeaftok-reactclient:image: aftok/aftok-reactclient:latestcontainer_name: aftok-reactcliententrypoint: /opt/aftok/aftok-client-cp.sh buildvolumes:- type: volumesource: v_aftok-reactclient - edit in docker-compose.yml at line 65[5.2106]→[5.1667:1757](∅→∅),[5.1667]→[5.1667:1757](∅→∅),[5.1757]→[5.2788:2812](∅→∅),[5.2788]→[5.2788:2812](∅→∅)
- type: volumesource: v_aftok-reactclienttarget: /opt/static/app2read_only: true - edit in docker-compose.yml at line 111
v_aftok-reactclient: - replacement in lib/Aftok/Billing.hs at line 10
import Data.Thyme.Clock as Cimport Data.Thyme.Time as Timport Data.UUIDimport qualified Data.Thyme.Clock as Cimport qualified Data.Thyme.Time as Timport Data.UUID (UUID) - replacement in lib/Aftok/Billing.hs at line 62
_gracePeriod :: Days,_requestExpiryPeriod :: NominalDiffTime,_gracePeriod :: T.Days,_requestExpiryPeriod :: T.NominalDiffTime, - replacement in lib/Aftok/Billing.hs at line 87
_startTime :: UTCTime,_endTime :: Maybe UTCTime_startTime :: C.UTCTime,_endTime :: Maybe C.UTCTime - replacement in lib/Aftok/Database/PostgreSQL/Events.hs at line 26
KeyedLogEntry(KeyedLogEntry),KeyedLogEntry (KeyedLogEntry), - replacement in lib/Aftok/Database/PostgreSQL/Events.hs at line 54
import Aftok.TimeLog (WorkIndex,LogEntry(LogEntry),LogEvent(..),EventId(..),EventAmendment(..),AmendmentId(..),eventMeta,_ModTime,_EventId,_AmendmentId,creditTo,eventTime,event,workIndex,eventName,nameEvent,import Aftok.TimeLog( AmendmentId (..),EventAmendment (..),EventId (..),LogEntry (LogEntry),LogEvent (..),WorkIndex,_AmendmentId,_EventId,_ModTime,creditTo,event,eventMeta,eventName,eventTime,nameEvent,workIndex, - edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 11
findUserProjectDetail, - edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 27
utcParser, - edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 33
import qualified Data.Thyme.Clock as C - edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 67
findUserProjectDetail :: UserId -> ProjectId -> DBM (Maybe (User, C.UTCTime))findUserProjectDetail (UserId uid) (ProjectId pid) = doheadMay<$> pquery((,) <$> userParser <*> utcParser)[sql| SELECT u.handle, u.recovery_email, u.recovery_zaddr, p.joined_atFROM users uJOIN project_companions p on p.user_id = u.idWHERE u.id = ? AND p.project_id = ? |](uid, pid) - edit in lib/Aftok/Database/PostgreSQL.hs at line 57
(FindUserProjectDetail uid pid) -> Q.findUserProjectDetail uid pid - edit in lib/Aftok/Database.hs at line 30
HasLogEntry, - edit in lib/Aftok/Database.hs at line 33
HasLogEntry, - replacement in lib/Aftok/Database.hs at line 57
data KeyedLogEntry = KeyedLogEntry {_workId :: !EventId,_logEntry :: !LogEntry}data KeyedLogEntry= KeyedLogEntry{ _workId :: !EventId,_logEntry :: !LogEntry} - edit in lib/Aftok/Database.hs at line 77
FindUserProjectDetail :: UserId -> ProjectId -> DBOp (Maybe (User, C.UTCTime)) - edit in lib/Aftok/Database.hs at line 164
findUserProjectDetail :: (MonadDB m) => UserId -> ProjectId -> MaybeT m (User, C.UTCTime)findUserProjectDetail uid pid = MaybeT . liftdb $ FindUserProjectDetail uid pid - replacement in lib/Aftok/Database.hs at line 273
in if uid' == uidthen liftdb actelse raiseOpForbidden uid UserNotEventLogger actin if uid' == uidthen liftdb actelse raiseOpForbidden uid UserNotEventLogger act - replacement in lib/Aftok/Payments/Util.hs at line 31
m TL.FractionalPayoutsm TL.WorkShares - replacement in lib/Aftok/Payments/Util.hs at line 52
TL.FractionalPayouts ->TL.WorkShares -> - replacement in lib/Aftok/Payments/Util.hs at line 59
let scaled frac = note AmountInvalid $ cscale amt fracpayoutFractions <- except $ traverse scaled (payouts ^. TL._Payouts)fromListWith (<>) . join <$> traverse (uncurry (getPayoutAmounts t currency mp)) (assocs payoutFractions)let scaled ws = note AmountInvalid $ cscale amt (ws ^. TL.wsShare)payoutFractions <- except $ traverse scaled (payouts ^. TL.creditToShares)fromListWith (<>) . join<$> traverse (uncurry (getPayoutAmounts t currency mp)) (assocs payoutFractions) - replacement in lib/Aftok/TimeLog/Serialization.hs at line 21
LinearDepreciation (Months up) (Months dp) ->LinearDepreciation undep dep -> - replacement in lib/Aftok/TimeLog/Serialization.hs at line 24
"arguments" .= object ["undep" .= up, "dep" .= dp]"arguments" .= object ["undep" .= undep, "dep" .= dep] - replacement in lib/Aftok/TimeLog/Serialization.hs at line 34
let undep = Months <$> (args .: "undep")dep = Months <$> (args .: "dep")let undep = (args .: "undep")dep = (args .: "dep") - replacement in lib/Aftok/TimeLog.hs at line 6
( LogEntry (..),HasLogEntry (..),( module Aftok.TimeLog, - edit in lib/Aftok/TimeLog.hs at line 11[5.50569]→[5.50569:50588](∅→∅),[5.50588]→[5.19051:19082](∅→∅),[5.19082]→[5.50588:50893](∅→∅),[5.50588]→[5.50588:50893](∅→∅),[5.50893]→[5.90213:90236](∅→∅),[5.90236]→[5.50893:50930](∅→∅),[5.50893]→[5.50893:50930](∅→∅)
LogEvent (..),_StartWork,_StopWork,eventName,nameEvent,eventTime,WorkIndex (WorkIndex),_WorkIndex,workIndex,DepF,toDepF,EventId (EventId),_EventId,ModTime (ModTime),_ModTime,EventAmendment (..),AmendmentId (AmendmentId),_AmendmentId,Payouts (..),_Payouts,FractionalPayouts,payouts,linearDepreciation, - replacement in lib/Aftok/TimeLog.hs at line 16
import Control.Lensimport Data.AdditiveGroup ()( CreditTo (..),DepreciationFunction (..),_CreditToAccount,_CreditToProject,_CreditToUser,)import Control.Lens ((.~), (^.), makeClassy, makeLenses, makePrisms, view) - replacement in lib/Aftok/TimeLog.hs at line 24
import Data.AffineSpaceimport Data.Foldable as Fimport Data.AffineSpace ((.-.))import qualified Data.Foldable as F - replacement in lib/Aftok/TimeLog.hs at line 27
import Data.Thyme.Clock as Cimport qualified Data.Thyme.Clock as Cimport qualified Data.Thyme.Time as C - replacement in lib/Aftok/TimeLog.hs at line 99
newtype Payouts a = Payouts (Map CreditTo a)data WorkShare a= WorkShare{ _wsLogged :: NDT,_wsDepreciated :: NDT,_wsShare :: a} - replacement in lib/Aftok/TimeLog.hs at line 106[5.5110]→[5.6021:6042](∅→∅),[5.31997]→[5.6021:6042](∅→∅),[5.52472]→[5.6021:6042](∅→∅),[5.6021]→[5.6021:6042](∅→∅)
makePrisms ''PayoutsmakeLenses ''WorkShare - replacement in lib/Aftok/TimeLog.hs at line 108
type FractionalPayouts = Payouts Rationaldata WorkShares= WorkShares{ _loggedTotal :: NDT,_creditToShares :: Map CreditTo (WorkShare Rational)}makeLenses ''WorkShares - replacement in lib/Aftok/TimeLog.hs at line 126
-- - produce the total, depreciated length of work to be credited to an address.workCredit :: (Foldable f, HasLogEntry le) => DepF -> C.UTCTime -> f (Interval le) -> NDTworkCredit df ptime ivals = getSum $ F.foldMap (Sum . df ptime . fmap (view $ event . eventTime)) ivals-- - produce the total length and depreciated length of work to be credited to an recipient.workCredit :: (Foldable f, HasLogEntry le) => DepF -> C.UTCTime -> f (Interval le) -> (NDT, NDT)workCredit depf ptime ivals =bimap getSum getSum $ F.foldMap ((Sum . ilen &&& Sum . depf ptime) . fmap (view $ event . eventTime)) ivals - replacement in lib/Aftok/TimeLog.hs at line 135
payouts :: forall le. (HasLogEntry le) => DepF -> C.UTCTime -> WorkIndex le -> FractionalPayoutspayouts :: forall le. (HasLogEntry le) => DepF -> C.UTCTime -> WorkIndex le -> WorkShares - replacement in lib/Aftok/TimeLog.hs at line 137
let addIntervalDiff :: (Foldable f) => NDT -> f (Interval le) -> (NDT, NDT)let addIntervalDiff :: (Foldable f) => NDT -> f (Interval le) -> (NDT, WorkShare ()) - replacement in lib/Aftok/TimeLog.hs at line 139
(^+^ total) &&& id $ workCredit dep ptime ivalslet (logged, depreciated) = workCredit dep ptime ivalsin (total ^+^ depreciated, WorkShare logged depreciated ()) - replacement in lib/Aftok/TimeLog.hs at line 142
in Payouts $ fmap ((/ toSeconds totalTime) . toSeconds) keyTimeswithShareFraction t = t & wsShare .~ (C.toSeconds (t ^. wsDepreciated) / C.toSeconds totalTime)in WorkShares totalTime (fmap withShareFraction keyTimes) - replacement in lib/Aftok/TimeLog.hs at line 203
-- | The number of initial months during which no depreciation occursMonths ->-- | The number of months over which each logged interval will be depreciatedMonths ->-- | The number of initial days during which no depreciation occursC.Days ->-- | The number of days over which each logged interval will be depreciatedC.Days -> - replacement in lib/Aftok/TimeLog.hs at line 210
let monthsLength :: Months -> NDTmonthsLength (Months i) = fromSeconds $ 60 * 60 * 24 * 30 * ilet daysLength :: C.Days -> NDTdaysLength d = C.fromSeconds $ 60 * 60 * 24 * d - replacement in lib/Aftok/TimeLog.hs at line 213
maxDepreciable = monthsLength undepLength ^+^ monthsLength depLengthmaxDepreciable = daysLength undepLength ^+^ daysLength depLength - replacement in lib/Aftok/TimeLog.hs at line 216
if dt < monthsLength undepLengthif dt < daysLength undepLength - replacement in lib/Aftok/TimeLog.hs at line 219
toSeconds (max zeroV (maxDepreciable ^-^ dt))/ toSeconds maxDepreciableC.toSeconds (max zeroV (maxDepreciable ^-^ dt))/ C.toSeconds maxDepreciable - replacement in lib/Aftok/Types.hs at line 10
import Data.Eq (Eq)import Data.Ord (Ord)import Data.Text (Text)import qualified Data.Thyme.Time as C - edit in lib/Aftok/Types.hs at line 12
import Text.Show (Show)import Prelude (Integer) - replacement in lib/Aftok/Types.hs at line 63
data DepreciationFunction = LinearDepreciation Months Monthsdata DepreciationFunction = LinearDepreciation C.Days C.Days - edit in lib/Aftok/Types.hs at line 65
newtype Months = Months Integerderiving (Eq, Show) - file move: list_project_contributors.sh → get_project_detail.sh
- replacement in scripts/get_project_detail.sh at line 24
"https://$AFTOK_HOST/api/projects/$PID/contributors"[5.1213]"https://$AFTOK_HOST/api/projects/$PID/detail" - edit in server/Aftok/Snaplet/Projects.hs at line 3
{-# LANGUAGE TupleSections #-}{-# LANGUAGE TypeApplications #-} - replacement in server/Aftok/Snaplet/Projects.hs at line 11
listContributorsHandler,projectDetailGetHandler, - edit in server/Aftok/Snaplet/Projects.hs at line 14
payoutsHandler,payoutsJSON, - edit in server/Aftok/Snaplet/Projects.hs at line 17
projectDetailJSON, - replacement in server/Aftok/Snaplet/Projects.hs at line 23
import Aftok.Json (idValue, identifiedJSON, obj, v1)import Aftok.Json (creditToJSON, idValue, identifiedJSON, obj, v1) - edit in server/Aftok/Snaplet/Projects.hs at line 28
import Aftok.TimeLog( WorkShare,WorkShares,creditToShares,payouts,toDepF,wsLogged,wsShare,) - replacement in server/Aftok/Snaplet/Projects.hs at line 40
import Control.Lens ((^.), _1, _2, to)import Control.Lens ((^.), _1, _2, makeLenses, to) - edit in server/Aftok/Snaplet/Projects.hs at line 45
import qualified Data.Map.Strict as M - edit in server/Aftok/Snaplet/Projects.hs at line 54
import Time.Types (Hours (..)) - replacement in server/Aftok/Snaplet/Projects.hs at line 59
parseJSON (Object v) =parseJSON (A.Object v) = - edit in server/Aftok/Snaplet/Projects.hs at line 63
data Contributor= Contributor{ _userId :: UserId,_handle :: UserName,_joinedOn :: C.UTCTime,_timeDevoted :: Hours,_revenueShare :: Rational}makeLenses ''Contributordata ProjectDetail= ProjectDetail{ _pdProject :: Project,_pdContributors :: M.Map UserId Contributor}makeLenses ''ProjectDetail - replacement in server/Aftok/Snaplet/Projects.hs at line 103
contributorJSON :: (UserId, UserName, C.UTCTime) -> ValuecontributorJSON (uid, uname, t) =object[ "user_id" .= idValue _UserId uid,"username" .= (uname ^. _UserName),"joined_at" .= t]projectDetailGetHandler :: S.Handler App App ProjectDetailprojectDetailGetHandler = douid <- requireUserIdpid <- requireProjectIdproject <-fromMaybeT(snapError 404 $ "Project not found for id " <> show pid)(mapMaybeT snapEval $ findUserProject uid pid)widx <- snapEval $ readWorkIndex pid uidptime <- liftIO $ C.getCurrentTimelet p = payouts (toDepF $ project ^. depf) ptime widxtoContributorRecord = \case(CreditToUser uid', ws) -> do(user, joinedOn') <-fromMaybeT(snapError 500 $ "No user record found for logged-in user.")(mapMaybeT snapEval $ findUserProjectDetail uid pid)pure . Just . (uid',) $Contributor{ _userId = uid',_handle = user ^. username,_joinedOn = joinedOn',_timeDevoted = Hours . (`div` 360) . round . C.toSeconds' $ ws ^. wsLogged,_revenueShare = ws ^. wsShare}_ -> pure NothingcontributorRecords <-fmap (M.fromList . catMaybes). traverse toContributorRecord$ M.assocs (p ^. creditToShares)pure $ProjectDetail{ _pdProject = project,_pdContributors = contributorRecords} - replacement in server/Aftok/Snaplet/Projects.hs at line 139
listContributorsHandler :: S.Handler App App [(UserId, UserName, C.UTCTime)]listContributorsHandler = dopayoutsHandler :: S.Handler App App WorkSharespayoutsHandler = do - replacement in server/Aftok/Snaplet/Projects.hs at line 143
snapEval $ listProjectContributors pid uidproject <-fromMaybeT(snapError 400 $ "Project not found for id " <> show pid)(mapMaybeT snapEval $ findUserProject uid pid)widx <- snapEval $ readWorkIndex pid uidptime <- liftIO $ C.getCurrentTimepure $ payouts (toDepF $ project ^. depf) ptime widx - edit in server/Aftok/Snaplet/Projects.hs at line 209
depfToJSON :: DepreciationFunction -> ValuedepfToJSON = \caseLinearDepreciation undep dep ->object[ "type" .= ("LinearDepreciation" :: Text),"arguments" .= object ["undep" .= undep, "dep" .= dep]] - replacement in server/Aftok/Snaplet/Projects.hs at line 218
projectJSON :: Project -> ValueprojectJSON :: Project -> A.Object - replacement in server/Aftok/Snaplet/Projects.hs at line 220
v1 $obj[ "projectName" .= (p ^. projectName),"inceptionDate" .= (p ^. inceptionDate),"initiator" .= (p ^. initiator . _UserId)]obj[ "projectName" .= (p ^. projectName),"inceptionDate" .= (p ^. inceptionDate),"initiator" .= (p ^. initiator . _UserId),"depf" .= depfToJSON (p ^. depf)] - replacement in server/Aftok/Snaplet/Projects.hs at line 228
qdbProjectJSON = identifiedJSON "project" (_1 . _ProjectId) (_2 . to projectJSON)[5.27815]qdbProjectJSON = identifiedJSON "project" (_1 . _ProjectId) (_2 . to (v1 . projectJSON))contributorJSON :: Contributor -> ValuecontributorJSON c =object[ "userId" .= idValue _UserId (c ^. userId),"username" .= (c ^. handle . _UserName),"joinedOn" .= (c ^. joinedOn),"timeDevoted" .= (c ^. timeDevoted . (to fromEnum)),"revenureShare".= object[ "numerator" .= (c ^. revenueShare . (to numerator)),"denominator" .= (c ^. revenueShare . (to denominator))]]projectDetailJSON :: ProjectDetail -> A.ObjectprojectDetailJSON detail =obj[ "project" .= Object (projectJSON $ detail ^. pdProject),"contributors" .= (M.elems $ fmap contributorJSON (detail ^. pdContributors))]payoutsJSON :: WorkShares -> A.ObjectpayoutsJSON ws =let payoutsRec :: (CreditTo, WorkShare Rational) -> ValuepayoutsRec (c, r) =object[ "creditTo" .= creditToJSON c,"payoutRatio" .= (r ^. wsShare),"payoutPercentage" .= (fromRational @Double (r ^. wsShare) * 100)]in obj $ ["payouts" .= fmap payoutsRec (M.assocs (ws ^. creditToShares))] - edit in server/Aftok/Snaplet/Users.hs at line 8
checkUsernameHandler, - replacement in server/Aftok/Snaplet/Users.hs at line 19
import Aftok.Database (acceptInvitation, createUser, findCurrentInvitation)import Aftok.Database( acceptInvitation,createUser,findCurrentInvitation,findUserByName,) - edit in server/Aftok/Snaplet/Users.hs at line 128
checkUsernameHandler :: S.Handler App App ()checkUsernameHandler = doparams <- S.getParamsuname <-maybe(snapError 400 "username parameter is required")(either (const $ snapError 400 "username must be valid UTF-8") (pure . UserName) . decodeUtf8')(listToMaybe =<< M.lookup "username" params)found <- snapEval (runMaybeT $ findUserByName uname)case found ofNothing -> pure ()Just _ -> snapError 400 "username is already taken" - edit in server/Aftok/Snaplet/WorkLog.hs at line 14
import Aftok.Project - edit in server/Aftok/Snaplet/WorkLog.hs at line 21
FractionalPayouts, - edit in server/Aftok/Snaplet/WorkLog.hs at line 24
Payouts (..), - edit in server/Aftok/Snaplet/WorkLog.hs at line 29
payouts,toDepF, - edit in server/Aftok/Snaplet/WorkLog.hs at line 33
UserId, - edit in server/Aftok/Snaplet/WorkLog.hs at line 34
UserId, - edit in server/Aftok/Snaplet/WorkLog.hs at line 38
import Aftok.Util (fromMaybeT) - edit in server/Aftok/Snaplet/WorkLog.hs at line 39
import Control.Monad.Trans.Maybe (mapMaybeT) - edit in server/Aftok/Snaplet/WorkLog.hs at line 110[5.4950]→[5.15166:15167](∅→∅),[5.15945]→[5.15166:15167](∅→∅),[5.29601]→[5.15166:15167](∅→∅),[5.15166]→[5.15166:15167](∅→∅),[5.15167]→[5.104286:104340](∅→∅),[5.18701]→[5.10183:10203](∅→∅),[5.36147]→[5.10183:10203](∅→∅),[5.104340]→[5.10183:10203](∅→∅),[5.1704]→[5.10183:10203](∅→∅),[5.10203]→[5.72174:72411](∅→∅),[5.8682]→[5.3065:3102](∅→∅),[5.13259]→[5.3065:3102](∅→∅),[5.59528]→[5.3065:3102](∅→∅),[5.72411]→[5.3065:3102](∅→∅),[5.3780]→[5.3065:3102](∅→∅),[5.3102]→[5.13260:13315](∅→∅)
payoutsHandler :: S.Handler App App FractionalPayoutspayoutsHandler = douid <- requireUserIdpid <- requireProjectIdproject <-fromMaybeT(snapError 400 $ "Project not found for id " <> show pid)(mapMaybeT snapEval $ findUserProject uid pid)widx <- snapEval $ readWorkIndex pid uidptime <- liftIO $ C.getCurrentTimepure $ payouts (toDepF $ project ^. depf) ptime widx - edit in server/Aftok/Snaplet/WorkLog.hs at line 162
payoutsJSON :: FractionalPayouts -> ValuepayoutsJSON (Payouts m) =v1 $let payoutsRec :: (CreditTo, Rational) -> ValuepayoutsRec (c, r) =object ["creditTo" .= creditToJSON c,"payoutRatio" .= r,"payoutPercentage" .= (fromRational @Double r * 100)]in obj $ ["payouts" .= fmap payoutsRec (MS.assocs m)] - edit in server/Aftok/Snaplet/WorkLog.hs at line 181
- edit in server/Main.hs at line 80
checkUsernameRoute = void $ method GET checkUsernameHandler - replacement in server/Main.hs at line 85
listContributorsRoute =serveJSON (fmap contributorJSON) $ method GET listContributorsHandlerprojectDetailRoute =serveJSON (v1 . projectDetailJSON) $ method GET projectDetailGetHandler - edit in server/Main.hs at line 134
("validate_username", checkUsernameRoute), -- check_username.sh - replacement in server/Main.hs at line 146
("projects/:projectId/contributors", listContributorsRoute), -- list_project_contributors.sh("projects/:projectId/detail", projectDetailRoute), -- list_project_contributors.sh