Implement core of payments/billing infrastructure.

[?]
Jan 22, 2017, 5:42 AM
HMDM3B557TO5RYP2IGFFC2C2VN6HYZTDQ47CJY2O37BW55DSMFZAC

Dependencies

  • [2] Q5X5RYQL stylish-haskell reformatting
  • [3] 4QX5E5AC Initial compilation of payouts function succeeds.
  • [4] 73NDXDEZ Begin implementation of billing event persistence.
  • [5] NTPC7KJE Trivial changes, feature scratchpad.
  • [6] DFOBMSAO Initial work on payments API
  • [7] Z7KS5XHH Very WIP. Wow.
  • [8] SLL7262C Make depreciation functions more flexible.
  • [9] 6L5BK5EH Use generic SMTP rather than Sendmail-specific mail client.
  • [10] NLZ3JXLO Fix formatting with stylish-haskell.
  • [11] V2VDN77H Enable postgres configuration via environment variable for Heroku.
  • [12] OBFPJS2G Project successfully builds and tests under nix.
  • [13] Y35QCWYW Minor improvement in WorkIndex type to eliminate duplicated information.
  • [14] KEP5WUFJ Convert project to stack-based build.
  • [15] NAS4BFL4 Trivial stylish-haskell reformat.
  • [16] LD4GLVSF More database stuff.
  • [17] 5OI44E4E Add authentication to auction search.
  • [18] 5DRIWGLU Improving TimeLog specs
  • [19] 7HPY3QPF Fix linting errors. (yay hlint!)
  • [20] WZUHEZSB Start of migration back toward snap.
  • [21] WO2MINIF Auctions now compile!
  • [22] 7KZP4RHZ Switch from Data.Time to Data.Thyme
  • [23] HALRDT2F Added initial auction create route.
  • [24] FXJQACES Ensure that auction is not ended at the time of bid
  • [25] QMRKFEPG Refactor QDB to use a free monad algebra instead.
  • [26] WFZDMVUX Rename ADB -> QDB
  • [27] O227CEAV Adds storage of original event JSON for some DBOp constructors.
  • [28] BXGLKYRX Added primitive user registration handler.
  • [29] 5XFJNUAZ Start of addition of project infrastructure.
  • [30] TNR3TEHK Switch to Postgres + snaplet arch compiles.
  • [31] O722AOKE Add route to allow crediting of events to users/projects.
  • [32] PBD7LZYQ Postgres & auth are beginning to function.
  • [33] BROSTG5K Beginning of modularization of server.
  • [34] KNSI575V Cleanup of EventLog types.
  • [35] EZQG2APB Update task list.
  • [36] RPAJLHMT Change to use UUIDs instead of ints for primary keys.
  • [37] 3QVT6MA6 Add database support for event amend operations.
  • [38] A6HKMINB Attempting to improve JSON handling.
  • [39] ZP62WC47 Begin conversion to build with stack.
  • [40] O5FVTOM6 Undo JSON silliness, enable a couple more routes.
  • [41] UILI6PIL The route-based logStart/logStop is nicer.
  • [42] 2G3GNDDU Event logging is now functioning in postgres.
  • [43] EKY7U7SK Finish conversion to stack.
  • [44] Z3MK2PJ5 Add GET handler for retrieving auction data.
  • [45] RN7EI6IN Update database layer to use CreditTo
  • [46] VJPT6HDR Fix remaining type errors after addition of login handler.
  • [47] XTBSG4C7 Adding serveJSON combinator to eliminate some boilerplate from handlers.
  • [48] M4KM76DG Merge branch 'stackify'
  • [49] POX3UAMT Enabling logging of time to contributor/project accounts
  • [50] BWN72T44 Don't accept work timestamp from an external source.
  • [51] GCVQD44V Create amends endpoint, switch to UUID primary keys
  • [52] LHJ2HFXV Add property test for auction algorithm.
  • [53] FD7SV5I6 Fix handling of event_t columns.
  • [54] NEDDHXUK Reformat via stylish-haskell
  • [55] UUR6SMCA Add start of specs for auctions.
  • [56] EKI57EJR Add alternative implementation of auction winner determination.
  • [57] ASF3UPJL Add auction creation and bid handlers
  • [58] 4IQVQL4T Added client for payouts endpoint.
  • [59] 5ZSKPQ3K Add created_at and auction_start timestamps to auction
  • [60] 64C6AWH6 Rename Ananke -> Quixotic, project reboot.
  • [61] Y3LIJ5US Add handler for CreatePaymentRequest
  • [62] TCOAKCGG Completed conversion to snap.
  • [63] 7VGYLTMU Clean up schema version handling.
  • [64] MB5SHULB Add route for accepting an invitation with an existing account
  • [65] QADKFHAR Adds CreatePayment handler implementation.
  • [66] I2KHGVD4 Require project permissions for access to most data.
  • [67] 2XQD6KKK Add invitation logic and clean up DBProg error handling.
  • [68] IZEVQF62 Work in progress replacing sqlite with postgres.
  • [69] WAIX6AGN Add event serialization for PaymentRequest & Payment
  • [70] 4U7F3CPI THE GREAT RENAMING OF THINGS!
  • [*] W35DDBFY Factor common JSON conversions up into client lib module.
  • [*] NVOCQVAS Initial failing tests.
  • [*] LCBJULKE Fix swapped default and key in QConfig.
  • [*] ADMKQQGC Initial empty Snap project.
  • [*] AXKKXBWN Initial attempt at writing down my ideas for a company based on trust.

Change contents

  • edit in aftok.cabal at line 32
    [3.194]
    [3.1]
    Aftok.Payments.Types
  • replacement in aftok.cabal at line 40
    [3.1607][3.245:280](),[3.280][3.229:266](),[3.266][3.280:316](),[3.280][3.280:316](),[3.316][3.267:303](),[3.303][3.50:86](),[3.50][3.50:86](),[3.86][3.75:75](),[3.75][3.387:422](),[3.86][3.387:422](),[3.86][3.387:422](),[3.387][3.387:422]()
    base >= 4.8.0
    , bippy == 0.1.0.0
    , classy-prelude == 0.12.*
    , aeson >= 0.11.2
    , attoparsec == 0.13.*
    , base64-bytestring == 1.0.*
    [3.1607]
    [3.3072]
    base
    , bippy
    , classy-prelude
    , aeson
    , attoparsec
    , base64-bytestring
  • replacement in aftok.cabal at line 50
    [3.14][3.423:458](),[3.1161][3.423:458]()
    , containers >= 0.5.6
    [3.14]
    [3.2624]
    , containers
  • replacement in aftok.cabal at line 52
    [3.2656][3.459:494](),[3.494][3.87:122]()
    , either >= 4.4.1
    , errors == 2.1.*
    [3.2656]
    [3.35]
    , cryptonite
    , either
    , errors
  • replacement in aftok.cabal at line 56
    [3.46][3.542:589](),[3.589][3.304:337](),[3.337][3.589:636](),[3.589][3.589:636](),[3.636][3.2794:2841](),[3.2794][3.2794:2841](),[3.2841][3.637:685]()
    , groups >= 0.4 && < 0.5
    , haskoin-core >= 0.4
    , heaps >= 0.3.1 && < 0.4
    , hourglass >= 0.2.6 && < 0.3
    , HsOpenSSL >= 0.11 && < 0.12
    [3.46]
    [3.47]
    , groups
    , haskoin-core
    , heaps
    , hourglass
  • replacement in aftok.cabal at line 61
    [3.68][3.123:157]()
    , lens >= 4.11
    [3.68]
    [3.1]
    , lens
  • replacement in aftok.cabal at line 63
    [3.11][3.781:815](),[3.77][3.781:815](),[3.206][3.781:815](),[3.206][3.781:815](),[3.781][3.781:815](),[3.815][3.338:375]()
    , old-locale >= 1.0
    , postgresql-simple >= 0.5.2.0
    [3.11]
    [3.15]
    , network-uri
    , old-locale
    , postgresql-simple
  • replacement in aftok.cabal at line 67
    [3.30][3.862:909](),[3.242][3.862:909](),[3.242][3.862:909](),[3.375][3.862:909](),[3.862][3.862:909]()
    , safe >= 0.3.9 && < 0.4
    [3.30]
    [3.1511]
    , safe
  • replacement in aftok.cabal at line 71
    [3.1599][3.910:1051]()
    , text >= 1.2.1 && < 1.3
    , thyme >= 0.3.5 && < 0.4
    , uuid >= 1.3.10 && < 1.4
    [3.1599]
    [3.704]
    , text
    , thyme
    , uuid
  • replacement in aftok.cabal at line 76
    [3.2906][3.1052:1085]()
    , wreq >= 0.4
    [3.2906]
    [3.1311]
    , wreq
  • replacement in aftok.cabal at line 97
    [3.2188][3.1086:1115]()
    , hspec >= 2.1.7
    [3.2188]
    [3.1]
    , hspec
  • replacement in aftok.cabal at line 102
    [3.75][3.1116:1143](),[3.1651][3.1116:1143]()
    , QuickCheck >= 2.8
    [3.1651]
    [3.1675]
    , QuickCheck
  • replacement in aftok.cabal at line 144
    [3.17][3.1178:1219](),[3.161][3.1178:1219]()
    , HStringTemplate >= 0.8.3
    [3.17]
    [3.3150]
    , HStringTemplate
  • replacement in aftok.cabal at line 146
    [3.3169][3.1220:1247]()
    , HsOpenSSL
    [3.3169]
    [3.41]
    --, HsOpenSSL
  • replacement in aftok.cabal at line 149
    [3.17][3.1248:1348](),[3.52][3.1248:1348]()
    , mtl >= 2.2 && < 3
    , MonadCatchIO-transformers >= 0.3 && < 0.4
    [3.17]
    [3.18]
    , mtl
    --, MonadCatchIO-transformers
  • replacement in aftok.cabal at line 154
    [3.7376][3.7298:7326](),[3.7326][3.52:95](),[3.95][3.1388:1584](),[3.1388][3.1388:1584]()
    , resource-pool-catchio
    , smtp-mail >= 0.1.4.5
    , snap >= 0.14
    , snap-core >= 0.9 && < 0.11
    , snap-server >= 0.9 && < 0.11
    , snaplet-postgresql-simple >= 0.6 && < 0.11
    [3.7376]
    [3.7327]
    --, resource-pool-catchio
    , smtp-mail
    , snap
    , snap-core
    , snap-server
    , snaplet-postgresql-simple
  • edit in lib/Aftok/Billables.hs at line 2
    [3.794]
    [3.794]
    {-# LANGUAGE DeriveFunctor #-}
    {-# LANGUAGE DeriveFoldable #-}
    {-# LANGUAGE DeriveTraversable #-}
  • edit in lib/Aftok/Billables.hs at line 11
    [2.59]
    [3.914]
    import Data.Thyme.Clock as C
    import Data.UUID
  • edit in lib/Aftok/Billables.hs at line 18
    [2.185][2.185:212]()
    import Data.UUID
  • edit in lib/Aftok/Billables.hs at line 44
    [3.689][3.689:742](),[3.742][2.385:454](),[2.454][3.1340:1365](),[3.1340][3.1340:1365](),[3.1365][2.455:508](),[2.508][3.1412:1441](),[3.1412][3.1412:1441](),[3.1441][3.762:837](),[3.837][3.1463:1464](),[3.1463][3.1463:1464]()
    data Billable' (p :: *) (u :: *) (c :: *) = Billable
    { _project :: p
    , _creator :: u
    , _name :: Text
    , _description :: Text
    , _recurrence :: Recurrence
    , _amount :: c
    , _gracePeriod :: Days
    }
    makeLenses ''Billable'
    type Billable = Billable' ProjectId UserId Satoshi
  • edit in lib/Aftok/Billables.hs at line 58
    [3.1729]
    [3.1729]
    data Billable' p u c = Billable
    { _project :: p
    , _creator :: u
    , _name :: Text
    , _description :: Text
    , _recurrence :: Recurrence
    , _amount :: c
    , _gracePeriod :: Days
    , _requestExpiryPeriod :: Maybe C.NominalDiffTime
    }
    makeLenses ''Billable'
  • edit in lib/Aftok/Billables.hs at line 71
    [3.1730]
    [3.964]
    type Billable = Billable' ProjectId UserId Satoshi
  • edit in lib/Aftok/Billables.hs at line 75
    [3.62]
    [3.1029]
    data Subscription' b = Subscription
    { _billable :: b
    , _startTime :: C.UTCTime
    , _endTime :: Maybe C.UTCTime
    } deriving (Functor, Foldable, Traversable)
    makeLenses ''Subscription'
  • edit in lib/Aftok/Billables.hs at line 83
    [3.1030]
    type Subscription = Subscription' BillableId
  • edit in lib/Aftok/Database/PostgreSQL.hs at line 10
    [3.74][3.1106:1165](),[2.581][3.1106:1165](),[3.1106][3.1106:1165]()
    import qualified Data.ByteString.Char8 as B
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 26
    [3.1147][3.1147:1207]()
    import qualified Aftok.Billables as BI
    [3.1147]
    [3.1614]
    import qualified Aftok.Billables as B
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 32
    [2.935][2.935:1008]()
    subscriptionJSON)
    [2.935]
    [3.173]
    createSubscriptionJSON)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 48
    [3.1216][3.1216:1290](),[3.1290][3.1340:1423](),[3.1423][3.83:84](),[3.83][3.83:84](),[3.84][3.1290:1373](),[3.1290][3.1290:1373]()
    uidParser :: FieldParser UserId
    uidParser f v = UserId <$> fromField f v
    pidParser :: FieldParser P.ProjectId
    pidParser f v = P.ProjectId <$> fromField f v
    secondsParser :: FieldParser Seconds
    secondsParser f v = Seconds <$> fromField f v
    [3.1216]
    [3.1373]
    uidParser :: RowParser UserId
    uidParser = UserId <$> field
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 51
    [3.1374][3.1374:1461]()
    usernameParser :: FieldParser UserName
    usernameParser f v = UserName <$> fromField f v
    [3.1374]
    [3.1461]
    pidParser :: RowParser P.ProjectId
    pidParser = P.ProjectId <$> field
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 54
    [3.1462][3.2028:2103]()
    emailParser :: FieldParser Email
    emailParser f v = Email <$> fromField f v
    [3.1462]
    [3.2103]
    subscriptionIdParser :: RowParser B.SubscriptionId
    subscriptionIdParser = B.SubscriptionId <$> field
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 60
    [3.1952][3.1952:2363]()
    let err = ConversionFailed { errSQLType = "text"
    , errSQLTableOid = tableOid f
    , errSQLField = maybe "" B.unpack (name f)
    , errHaskellType = "BtcAddr"
    , errMessage = "could not deserialize value to a valid BTC address"
    }
    maybe (conversionError err) pure addrMay
    [3.1952]
    [3.1545]
    let err = returnError ConversionFailed f "could not deserialize value to a valid BTC address"
    maybe err pure addrMay
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 63
    [3.1546][3.477:510](),[3.510][3.4:62]()
    btcParser :: FieldParser Satoshi
    btcParser f v = (Satoshi . fromInteger) <$> fromField f v
    [3.1546]
    [3.57]
    btcParser :: RowParser Satoshi
    btcParser = (Satoshi . fromInteger) <$> field
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 66
    [3.58][3.58:93](),[3.93][3.1868:1910]()
    utcParser :: FieldParser C.UTCTime
    utcParser f v = toThyme <$> fromField f v
    [3.58]
    [3.66]
    utcParser :: RowParser C.UTCTime
    utcParser = toThyme <$> field
  • edit in lib/Aftok/Database/PostgreSQL.hs at line 72
    [3.114][3.1424:1533](),[3.1533][2.1083:1188](),[2.1188][3.1632:1692](),[3.1632][3.1632:1692](),[3.1692][2.1189:1325](),[2.1325][3.1810:1832](),[3.1810][3.1810:1832]()
    recurrenceParser :: RowParser BI.Recurrence
    recurrenceParser =
    let prec :: Text -> RowParser BI.Recurrence
    prec "annually" = nullField *> pure BI.Annually
    prec "monthly" = BI.Monthly <$> field
    prec "semimonthly" = nullField *> pure BI.SemiMonthly
    prec "weekly" = BI.Weekly <$> field
    prec "onetime" = nullField *> pure BI.OneTime
    prec _ = empty
    in field >>= prec
  • edit in lib/Aftok/Database/PostgreSQL.hs at line 78
    [3.2025]
    [3.271]
    nominalDiffTimeParser :: FieldParser NominalDiffTime
    nominalDiffTimeParser f v =
    C.fromSeconds' <$> fromField f v
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 90
    [3.2201][3.2201:2409]()
    parser "credit_to_user" = CreditToUser <$> (nullField *> fieldWith uidParser <* nullField)
    parser "credit_to_project" = CreditToProject <$> (nullField *> nullField *> fieldWith pidParser)
    [3.2201]
    [3.2409]
    parser "credit_to_user" = CreditToUser <$> (nullField *> uidParser <* nullField)
    parser "credit_to_project" = CreditToProject <$> (nullField *> nullField *> pidParser)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 102
    [3.402][3.336:403](),[3.1731][3.336:403](),[3.1967][3.336:403](),[3.336][3.336:403]()
    <*> (fieldWith eventTypeParser <*> fieldWith utcParser)
    [3.402]
    [3.403]
    <*> (fieldWith eventTypeParser <*> utcParser)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 107
    [3.1988][3.352:383](),[3.489][3.352:383](),[3.383][3.1989:2020]()
    (,,) <$> fieldWith pidParser
    <*> fieldWith uidParser
    [3.1988]
    [3.95]
    (,,) <$> pidParser
    <*> uidParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 113
    [3.2039][3.2657:2873]()
    A.Auction <$> fieldWith pidParser
    <*> fieldWith uidParser
    <*> fieldWith utcParser
    <*> fieldWith btcParser
    <*> fieldWith utcParser
    <*> fieldWith utcParser
    [3.2039]
    [3.2729]
    A.Auction <$> pidParser
    <*> uidParser
    <*> utcParser
    <*> btcParser
    <*> utcParser
    <*> utcParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 122
    [3.2052][3.2904:3036]()
    A.Bid <$> fieldWith uidParser
    <*> fieldWith secondsParser
    <*> fieldWith btcParser
    <*> fieldWith utcParser
    [3.2052]
    [3.2828]
    A.Bid <$> uidParser
    <*> (Seconds <$> field)
    <*> btcParser
    <*> utcParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 129
    [3.2160][3.922:958](),[3.922][3.922:958]()
    User <$> fieldWith usernameParser
    [3.2160]
    [3.3132]
    User <$> (UserName <$> field)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 135
    [3.2177][3.2177:2207]()
    (,) <$> fieldWith uidParser
    [3.2177]
    [3.1094]
    (,) <$> uidParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 141
    [3.3097][3.3097:3169]()
    <*> fieldWith utcParser
    <*> fieldWith uidParser
    [3.3097]
    [3.3169]
    <*> utcParser
    <*> uidParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 147
    [3.2298][3.3254:3412]()
    P.Invitation <$> fieldWith pidParser
    <*> fieldWith uidParser
    <*> fieldWith emailParser
    <*> fieldWith utcParser
    [3.2298]
    [3.3412]
    P.Invitation <$> pidParser
    <*> uidParser
    <*> fmap Email field
    <*> utcParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 155
    [3.2318][3.2318:2348]()
    (,) <$> fieldWith pidParser
    [3.2318]
    [3.1337]
    (,) <$> pidParser
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 158
    [3.3459][3.3459:3499]()
    billableParser :: RowParser BI.Billable
    [3.3459]
    [3.3499]
    billableParser :: RowParser B.Billable
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 160
    [3.3516][3.3516:3748]()
    BI.Billable <$> fieldWith pidParser
    <*> fieldWith uidParser
    <*> field
    <*> field
    <*> recurrenceParser
    <*> fieldWith btcParser
    <*> (Days <$> field)
    [3.3516]
    [3.293]
    B.Billable <$> pidParser
    <*> uidParser
    <*> field
    <*> field
    <*> recurrenceParser
    <*> btcParser
    <*> (Days <$> field)
    <*> fieldWith (optionalField nominalDiffTimeParser)
    recurrenceParser :: RowParser B.Recurrence
    recurrenceParser =
    let prec :: Text -> RowParser B.Recurrence
    prec "annually" = nullField *> pure B.Annually
    prec "monthly" = B.Monthly <$> field
    prec "semimonthly" = nullField *> pure B.SemiMonthly
    prec "weekly" = B.Weekly <$> field
    prec "onetime" = nullField *> pure B.OneTime
    prec _ = empty
    in field >>= prec
    subscriptionParser :: RowParser B.Subscription
    subscriptionParser =
    B.Subscription <$> (B.BillableId <$> field)
    <*> (toThyme <$> field)
    <*> ((fmap toThyme) <$> field)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 211
    [3.264][2.1414:1456](),[2.1456][3.307:384](),[3.307][3.307:384]()
    storeEvent (CreateSubscription uid bid) =
    Just $ storeEventJSON uid "create_subscription" (subscriptionJSON uid bid)
    [3.264]
    [3.384]
    storeEvent (CreateSubscription uid s) =
    Just $ storeEventJSON uid "create_subscription" (createSubscriptionJSON uid s)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 233
    [3.426][3.4053:4161]()
    updateCache :: DBOp a -> QDBM a
    updateCache (CreateEvent (P.ProjectId pid) (UserId uid) (LogEntry c e m)) =
    [3.426]
    [3.4161]
    pgEval :: DBOp a -> QDBM a
    pgEval (CreateEvent (P.ProjectId pid) (UserId uid) (LogEntry c e m)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 260
    [3.3406][3.5260:5300]()
    updateCache (FindEvent (EventId eid)) =
    [3.3406]
    [3.5300]
    pgEval (FindEvent (EventId eid)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 268
    [3.1084][3.5556:5619]()
    updateCache (FindEvents (P.ProjectId pid) (UserId uid) ival) =
    [3.1084]
    [3.5619]
    pgEval (FindEvents (P.ProjectId pid) (UserId uid) ival) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 284
    [3.1952][3.6356:6415]()
    updateCache (AmendEvent (EventId eid) (TimeChange mt t)) =
    [3.1952]
    [3.6415]
    pgEval (AmendEvent (EventId eid) (TimeChange mt t)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 291
    [3.2904][3.6610:6673]()
    updateCache (AmendEvent (EventId eid) (CreditToChange mt c)) =
    [3.2904]
    [3.6673]
    pgEval (AmendEvent (EventId eid) (CreditToChange mt c)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 314
    [3.4598][3.7588:7651]()
    updateCache (AmendEvent (EventId eid) (MetadataChange mt v)) =
    [3.4598]
    [3.7651]
    pgEval (AmendEvent (EventId eid) (MetadataChange mt v)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 321
    [3.4862][3.7843:7894]()
    updateCache (ReadWorkIndex (P.ProjectId pid)) = do
    [3.4862]
    [3.7894]
    pgEval (ReadWorkIndex (P.ProjectId pid)) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 327
    [3.5183][3.8078:8112]()
    updateCache (CreateAuction auc) =
    [3.5183]
    [3.8112]
    pgEval (CreateAuction auc) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 337
    [3.5425][3.8415:8449]()
    updateCache (FindAuction aucId) =
    [3.5425]
    [3.8449]
    pgEval (FindAuction aucId) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 342
    [3.5525][3.8633:8683]()
    updateCache (CreateBid (A.AuctionId aucId) bid) =
    [3.5525]
    [3.8683]
    pgEval (CreateBid (A.AuctionId aucId) bid) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 353
    [3.668][3.9008:9039]()
    updateCache (ReadBids aucId) =
    [3.668]
    [3.9039]
    pgEval (ReadBids aucId) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 358
    [3.705][3.9181:9214]()
    updateCache (CreateUser user') =
    [3.705]
    [3.9214]
    pgEval (CreateUser user') =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 368
    [3.1369][3.9517:9555]()
    updateCache (FindUser (UserId uid)) =
    [3.1369]
    [3.9555]
    pgEval (FindUser (UserId uid)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 373
    [3.3219][3.9664:9708]()
    updateCache (FindUserByName (UserName h)) =
    [3.3219]
    [3.9708]
    pgEval (FindUserByName (UserName h)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 378
    [3.9826][3.9826:9905]()
    updateCache (CreateInvitation (P.ProjectId pid) (UserId uid) (Email e) t) = do
    [3.9826]
    [3.9905]
    pgEval (CreateInvitation (P.ProjectId pid) (UserId uid) (Email e) t) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 386
    [3.10161][3.10161:10195]()
    updateCache (FindInvitation ic) =
    [3.10161]
    [3.10195]
    pgEval (FindInvitation ic) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 392
    [3.3742][3.10400:10469]()
    updateCache (AcceptInvitation (UserId uid) ic t) = transactQDBM $ do
    [3.3742]
    [3.10469]
    pgEval (AcceptInvitation (UserId uid) ic t) = transactQDBM $ do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 403
    [3.3836][3.10844:10876]()
    updateCache (CreateProject p) =
    [3.3836]
    [3.10876]
    pgEval (CreateProject p) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 409
    [3.4291][3.11144:11190]()
    updateCache (FindProject (P.ProjectId pid)) =
    [3.4291]
    [3.11190]
    pgEval (FindProject (P.ProjectId pid)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 414
    [3.947][3.11341:11387]()
    updateCache (FindUserProjects (UserId uid)) =
    [3.947]
    [3.11387]
    pgEval (FindUserProjects (UserId uid)) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 422
    [3.1014][3.11658:11714]()
    updateCache (AddUserToProject pid current new) = void $
    [3.1014]
    [3.11714]
    pgEval (AddUserToProject pid current new) = void $
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 427
    [3.1043][3.855:900]()
    updateCache dbop @ (CreateBillable _ b) = do
    [3.1043]
    [3.11916]
    pgEval dbop @ (CreateBillable _ b) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 429
    [3.11949][3.11949:11973]()
    pinsert BI.BillableId
    [3.11949]
    [3.11973]
    pinsert B.BillableId
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 433
    [3.12171][3.12171:12210]()
    ( b ^. (BI.project . P._ProjectId)
    [3.12171]
    [3.12210]
    ( b ^. (B.project . P._ProjectId)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 435
    [3.12236][3.12236:12451]()
    , b ^. BI.name
    , b ^. BI.description
    , b ^. (BI.recurrence . to BI.recurrenceName)
    , b ^. (BI.recurrence . to BI.recurrenceCount)
    , b ^. (BI.amount . satoshi)
    , b ^. (BI.gracePeriod . _Days)
    [3.12236]
    [3.12451]
    , b ^. B.name
    , b ^. B.description
    , b ^. (B.recurrence . to B.recurrenceName)
    , b ^. (B.recurrence . to B.recurrenceCount)
    , b ^. (B.amount . satoshi)
    , b ^. (B.gracePeriod . _Days)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 443
    [3.3719][3.12458:12491]()
    updateCache (ReadBillable bid) =
    [3.3719]
    [3.12491]
    pgEval (ReadBillable bid) =
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 449
    [3.12769][3.12769:12804]()
    (Only (bid ^. BI._BillableId))
    [3.12769]
    [3.3942]
    (Only (bid ^. B._BillableId))
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 451
    [3.3943][3.523:576]()
    updateCache dbop @ (CreateSubscription uid bid) = do
    [3.3943]
    [3.576]
    pgEval dbop @ (CreateSubscription uid s) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 453
    [3.609][3.609:637]()
    pinsert BI.SubscriptionId
    [3.609]
    [3.637]
    pinsert B.SubscriptionId
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 457
    [3.746][3.746:811]()
    (uid ^. _UserId, bid ^. BI._BillableId, eventId ^. _EventId)
    [3.746]
    [3.811]
    (uid ^. _UserId, s ^. (B.billable . B._BillableId), eventId ^. _EventId)
    pgEval (FindSubscriptions uid pid) =
    pquery ((,) <$> subscriptionIdParser <*> subscriptionParser)
    "SELECT id, billable_id, start_date, end_date \
    \FROM subscriptions s \
    \JOIN billables b ON b.id = s.billable_id \
    \WHERE s.user_id = ? \
    \AND b.project_id = ?"
    (uid ^. _UserId, pid ^. P._ProjectId)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 468
    [3.812][3.901:954]()
    updateCache dbop @ (CreatePaymentRequest _ req) = do
    [3.812]
    [3.863]
    pgEval dbop @ (CreatePaymentRequest _ req) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 475
    [3.1044][3.1044:1093]()
    ( req ^. (subscription . BI._SubscriptionId)
    [3.1044]
    [2.1540]
    ( req ^. (subscription . B._SubscriptionId)
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 480
    [2.1568][3.955:1001](),[3.1189][3.955:1001]()
    updateCache dbop @ (CreatePayment _ req) = do
    [2.1568]
    [3.48]
    pgEval dbop @ (CreatePayment _ req) = do
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 491
    [3.1045][3.12989:13039]()
    updateCache (RaiseDBError err _) = raiseError err
    [3.1045]
    [3.3944]
    pgEval (RaiseDBError err _) = raiseError err
  • replacement in lib/Aftok/Database/PostgreSQL.hs at line 499
    [3.3947][3.13218:13272]()
    instance DBEval QDBM where
    dbEval e = updateCache e
    [3.3947]
    instance MonadDB QDBM where
    liftdb = pgEval
  • edit in lib/Aftok/Database.hs at line 2
    [3.39]
    [3.39]
    {-# LANGUAGE FlexibleInstances #-}
  • edit in lib/Aftok/Database.hs at line 4
    [3.75]
    [3.75]
    {-# LANGUAGE TupleSections #-}
  • replacement in lib/Aftok/Database.hs at line 10
    [3.143][3.143:173]()
    import Control.Lens
    [3.143]
    [3.173]
    import Control.Lens (view, (^.))
  • replacement in lib/Aftok/Database.hs at line 18
    [3.333][3.3989:4021]()
    import Aftok.Payments
    [3.333]
    [3.801]
    import Aftok.Payments.Types
  • edit in lib/Aftok/Database.hs at line 28
    [3.6105][3.6105:6137]()
    type DBProg a = Program DBOp a
  • replacement in lib/Aftok/Database.hs at line 56
    [3.13383][3.13383:13451]()
    CreateSubscription :: UserId -> BillableId -> DBOp SubscriptionId
    [3.13383]
    [3.4199]
    CreateSubscription :: UserId -> Subscription -> DBOp SubscriptionId
    FindSubscriptions :: UserId -> ProjectId -> DBOp [(SubscriptionId, Subscription)]
  • replacement in lib/Aftok/Database.hs at line 78
    [3.5147][3.5147:5215](),[3.5215][3.421:479]()
    raiseOpForbidden :: UserId -> OpForbiddenReason -> DBOp x -> DBOp x
    raiseOpForbidden uid r = RaiseDBError (OpForbidden uid r)
    [3.5147]
    [3.5274]
    class (Monad m) => MonadDB (m :: * -> *) where
    liftdb :: DBOp x -> m x
    instance MonadDB (Program DBOp) where
    liftdb = fc
  • replacement in lib/Aftok/Database.hs at line 84
    [3.5275][3.105:146](),[3.146][3.480:532](),[3.5316][3.480:532]()
    raiseSubjectNotFound :: DBOp y -> DBOp x
    raiseSubjectNotFound = RaiseDBError SubjectNotFound
    [3.5275]
    [3.7338]
    raiseOpForbidden :: (MonadDB m) => UserId -> OpForbiddenReason -> DBOp x -> m x
    raiseOpForbidden uid r op = liftdb $ RaiseDBError (OpForbidden uid r) op
  • replacement in lib/Aftok/Database.hs at line 87
    [3.7339][3.7339:7386]()
    class DBEval m where
    dbEval :: DBOp a -> m a
    [3.7339]
    [3.7386]
    raiseSubjectNotFound :: (MonadDB m) => DBOp y -> m x
    raiseSubjectNotFound op = liftdb $ RaiseDBError SubjectNotFound op
  • replacement in lib/Aftok/Database.hs at line 92
    [3.7400][3.7400:7465]()
    createUser :: User -> DBProg UserId
    createUser = fc . CreateUser
    [3.7400]
    [3.7465]
    createUser :: (MonadDB m) => User -> m UserId
    createUser = liftdb . CreateUser
  • replacement in lib/Aftok/Database.hs at line 95
    [3.7466][3.7466:7533]()
    findUser :: UserId -> DBProg (Maybe User)
    findUser = fc . FindUser
    [3.7466]
    [3.5044]
    findUser :: (MonadDB m) => UserId -> m (Maybe User)
    findUser = liftdb . FindUser
  • replacement in lib/Aftok/Database.hs at line 98
    [3.5045][3.7534:7626]()
    findUserByName :: UserName -> DBProg (Maybe KeyedUser)
    findUserByName = fc . FindUserByName
    [3.5045]
    [3.7626]
    findUserByName :: (MonadDB m) => UserName -> m (Maybe KeyedUser)
    findUserByName = liftdb . FindUserByName
  • replacement in lib/Aftok/Database.hs at line 103
    [3.7643][3.7643:7688]()
    createProject :: Project -> DBProg ProjectId
    [3.7643]
    [3.7688]
    createProject :: (MonadDB m) => Project -> m ProjectId
  • replacement in lib/Aftok/Database.hs at line 105
    [3.7709][3.7709:7739]()
    pid <- fc $ CreateProject p
    [3.7709]
    [3.771]
    pid <- liftdb $ CreateProject p
  • replacement in lib/Aftok/Database.hs at line 109
    [3.7810][3.7810:7871]()
    findProject :: ProjectId -> UserId -> DBProg (Maybe Project)
    [3.7810]
    [3.7871]
    findProject :: (MonadDB m) => ProjectId -> UserId -> m (Maybe Project)
  • replacement in lib/Aftok/Database.hs at line 114
    [3.565][3.7987:8080](),[3.7987][3.7987:8080]()
    findUserProjects :: UserId -> DBProg [KeyedProject]
    findUserProjects = fc . FindUserProjects
    [3.565]
    [3.8254]
    findUserProjects :: (MonadDB m) => UserId -> m [KeyedProject]
    findUserProjects = liftdb . FindUserProjects
  • replacement in lib/Aftok/Database.hs at line 117
    [3.8255][3.8255:8316]()
    withProjectAuth :: ProjectId -> UserId -> DBOp a -> DBProg a
    [3.8255]
    [3.8316]
    withProjectAuth :: (MonadDB m) => ProjectId -> UserId -> DBOp a -> m a
  • replacement in lib/Aftok/Database.hs at line 120
    [3.8378][3.566:624]()
    fc $ if any (\(pid', _) -> pid' == pid) px
    then act
    [3.8378]
    [3.5370]
    if any (\(pid', _) -> pid' == pid) px
    then liftdb act
  • replacement in lib/Aftok/Database.hs at line 124
    [3.304][3.304:367]()
    checkProjectAuth :: ProjectId -> UserId -> DBOp a -> DBProg ()
    [3.304]
    [3.367]
    checkProjectAuth :: (MonadDB m) => ProjectId -> UserId -> DBOp a -> m ()
  • replacement in lib/Aftok/Database.hs at line 129
    [3.487][3.487:554]()
    else void . fc $ raiseOpForbidden uid UserNotProjectMember act
    [3.487]
    [3.556]
    else void $ raiseOpForbidden uid UserNotProjectMember act
  • replacement in lib/Aftok/Database.hs at line 131
    [3.557][3.5426:5498](),[3.5426][3.5426:5498]()
    addUserToProject :: ProjectId -> InvitingUID -> InvitedUID -> DBProg ()
    [3.557]
    [3.625]
    addUserToProject :: (MonadDB m) => ProjectId -> InvitingUID -> InvitedUID -> m ()
  • replacement in lib/Aftok/Database.hs at line 135
    [3.5600][3.5600:5692]()
    createInvitation :: ProjectId -> InvitingUID -> Email -> C.UTCTime -> DBProg InvitationCode
    [3.5600]
    [3.5692]
    createInvitation :: (MonadDB m) => ProjectId -> InvitingUID -> Email -> C.UTCTime -> m InvitationCode
  • replacement in lib/Aftok/Database.hs at line 139
    [3.5801][3.5801:5906]()
    findInvitation :: InvitationCode -> DBProg (Maybe Invitation)
    findInvitation ic = fc $ FindInvitation ic
    [3.5801]
    [3.5906]
    findInvitation :: (MonadDB m) => InvitationCode -> m (Maybe Invitation)
    findInvitation ic = liftdb $ FindInvitation ic
  • replacement in lib/Aftok/Database.hs at line 142
    [3.5907][3.343:413]()
    acceptInvitation :: UserId -> C.UTCTime -> InvitationCode-> DBProg ()
    [3.5907]
    [3.413]
    acceptInvitation :: (MonadDB m) => UserId -> C.UTCTime -> InvitationCode-> m ()
  • replacement in lib/Aftok/Database.hs at line 148
    [3.676][3.6104:6140](),[3.6104][3.6104:6140]()
    fc $ raiseSubjectNotFound act
    [3.676]
    [3.677]
    raiseSubjectNotFound act
  • replacement in lib/Aftok/Database.hs at line 150
    [3.757][3.6221:6275](),[3.6221][3.6221:6275]()
    fc $ raiseOpForbidden uid InvitationExpired act
    [3.757]
    [3.758]
    raiseOpForbidden uid InvitationExpired act
  • replacement in lib/Aftok/Database.hs at line 152
    [3.803][3.6321:6383](),[3.6321][3.6321:6383]()
    fc $ raiseOpForbidden uid InvitationAlreadyAccepted act
    [3.803]
    [3.804]
    raiseOpForbidden uid InvitationAlreadyAccepted act
  • replacement in lib/Aftok/Database.hs at line 159
    [3.8566][3.8566:8631]()
    createEvent :: ProjectId -> UserId -> LogEntry -> DBProg EventId
    [3.8566]
    [3.819]
    createEvent :: (MonadDB m) => ProjectId -> UserId -> LogEntry -> m EventId
  • replacement in lib/Aftok/Database.hs at line 162
    [3.8692][3.8692:8764]()
    amendEvent :: UserId -> EventId -> EventAmendment -> DBProg AmendmentId
    [3.8692]
    [3.8764]
    amendEvent :: (MonadDB m) => UserId -> EventId -> EventAmendment -> m AmendmentId
  • replacement in lib/Aftok/Database.hs at line 167
    [3.6586][3.6586:6627](),[3.6627][3.8934:9016](),[3.8934][3.8934:9016]()
    missing = raiseSubjectNotFound act
    fc $ maybe missing (\(_, uid', _) -> if uid' == uid then act else forbidden) ev
    [3.6586]
    [3.1146]
    missing = raiseSubjectNotFound act
    maybe missing (\(_, uid', _) -> if uid' == uid then liftdb act else forbidden) ev
  • replacement in lib/Aftok/Database.hs at line 170
    [3.1147][3.9017:9097]()
    findEvent :: EventId -> DBProg (Maybe KeyedLogEntry)
    findEvent = fc . FindEvent
    [3.1147]
    [3.4024]
    findEvent :: (MonadDB m) => EventId -> m (Maybe KeyedLogEntry)
    findEvent = liftdb . FindEvent
  • replacement in lib/Aftok/Database.hs at line 173
    [3.4025][3.9098:9207]()
    findEvents :: ProjectId -> UserId -> Interval' -> DBProg [LogEntry]
    findEvents p u i = fc $ FindEvents p u i
    [3.4025]
    [3.1303]
    findEvents :: (MonadDB m) => ProjectId -> UserId -> Interval' -> m [LogEntry]
    findEvents p u i = liftdb $ FindEvents p u i
  • replacement in lib/Aftok/Database.hs at line 176
    [3.1304][3.9208:9265]()
    readWorkIndex :: ProjectId -> UserId -> DBProg WorkIndex
    [3.1304]
    [3.9265]
    readWorkIndex :: (MonadDB m) => ProjectId -> UserId -> m WorkIndex
  • replacement in lib/Aftok/Database.hs at line 181
    [3.834][3.1203:1261]()
    createBillable :: UserId -> Billable -> DBProg BillableId
    [3.834]
    [2.1570]
    createBillable :: (MonadDB m) => UserId -> Billable -> m BillableId
  • replacement in lib/Aftok/Database.hs at line 185
    [3.4547][3.13775:13829](),[3.13829][3.4621:4654](),[3.4621][3.4621:4654]()
    readBillable :: BillableId -> DBProg (Maybe Billable)
    readBillable = fc . ReadBillable
    [3.4547]
    [3.4654]
    readBillable :: (MonadDB m) => BillableId -> m (Maybe Billable)
    readBillable = liftdb . ReadBillable
  • replacement in lib/Aftok/Database.hs at line 188
    [3.4655][3.4655:4784](),[3.4787][3.4787:4788]()
    --createPaymentRequest :: BillableId -> DBProg PaymentRequestId
    --createPaymentRequest bid = do
    -- billable <- readBillable bid
    [3.4655]
    [2.1594]
    findSubscriptions :: (MonadDB m)
    => UserId
    -> ProjectId
    -> m [(SubscriptionId, Subscription' Billable)]
    findSubscriptions uid pid = do
    subscriptions <- liftdb $ FindSubscriptions uid pid
    let sub'' s = sequenceA <$> traverse readBillable s
    sub' (sid, s) = fmap (fmap (sid,)) (sub'' s)
    catMaybes <$> traverse sub' subscriptions
  • replacement in lib/Aftok/Database.hs at line 198
    [2.1595][3.466:515](),[3.4788][3.466:515]()
    readPaymentHistory :: UserId -> DBProg [Payment]
    [2.1595]
    [3.4861]
    readPaymentHistory :: (MonadDB m) => UserId -> m [Payment]
  • replacement in lib/Aftok/Database.hs at line 203
    [3.1306][3.626:671]()
    createAuction :: Auction -> DBProg AuctionId
    [3.1306]
    [3.671]
    createAuction :: (MonadDB m) => Auction -> m AuctionId
  • replacement in lib/Aftok/Database.hs at line 207
    [3.767][3.767:828]()
    findAuction :: AuctionId -> UserId -> DBProg (Maybe Auction)
    [3.767]
    [3.841]
    findAuction :: (MonadDB m) => AuctionId -> UserId -> m (Maybe Auction)
  • replacement in lib/Aftok/Database.hs at line 211
    [3.892][3.179:205]()
    maybeAuc <- fc findOp
    [3.892]
    [3.205]
    maybeAuc <- liftdb findOp
  • replacement in lib/Aftok/Database.hs at line 215
    [3.293][3.293:347]()
    findAuction' :: AuctionId -> UserId -> DBProg Auction
    [3.293]
    [3.864]
    findAuction' :: (MonadDB m) => AuctionId -> UserId -> m Auction
  • replacement in lib/Aftok/Database.hs at line 219
    [3.411][3.411:437]()
    maybeAuc <- fc findOp
    [3.411]
    [3.437]
    maybeAuc <- liftdb findOp
  • replacement in lib/Aftok/Database.hs at line 221
    [3.523][3.523:582]()
    maybe (fc $ raiseSubjectNotFound findOp) pure maybeAuc
    [3.523]
    [3.21]
    maybe (raiseSubjectNotFound findOp) pure maybeAuc
  • replacement in lib/Aftok/Database.hs at line 223
    [3.22][3.4912:4968]()
    createBid :: AuctionId -> UserId -> Bid -> DBProg BidId
    [3.22]
    [3.888]
    createBid :: (MonadDB m) => AuctionId -> UserId -> Bid -> m BidId
  • replacement in lib/Aftok/Database.hs at line 228
    [3.650][3.913:964]()
    fc $ if view bidTime bid > view auctionEnd auc
    [3.650]
    [3.702]
    if view bidTime bid > view auctionEnd auc
  • replacement in lib/Aftok/Database.hs at line 230
    [3.756][3.756:776]()
    else createOp
    [3.756]
    else liftdb createOp
  • edit in lib/Aftok/Json.hs at line 4
    [3.917]
    [72.127]
    {-# LANGUAGE TypeApplications #-}
  • edit in lib/Aftok/Json.hs at line 33
    [3.171]
    [3.1358]
    import Aftok.Time
  • edit in lib/Aftok/Json.hs at line 181
    [3.1836]
    [3.1836]
    , "amount" .= (b ^. (B.amount . satoshi))
    , "gracePeriod" .= (b ^. (B.gracePeriod . _Days))
    , "requestExpiryPeriod" .= (C.toSeconds' <$> (b ^. B.requestExpiryPeriod))
  • replacement in lib/Aftok/Json.hs at line 193
    [3.5682][3.2237:2289](),[3.2289][2.1925:1957](),[2.1957][3.2322:2422](),[3.2322][3.2322:2422]()
    subscriptionJSON :: UserId -> B.BillableId -> Value
    subscriptionJSON uid bid = v1 $
    obj [ "userId" .= tshow (uid ^. _UserId)
    , "billableId" .= tshow (bid ^. B._BillableId)
    [3.5682]
    [3.621]
    createSubscriptionJSON :: UserId -> B.Subscription -> Value
    createSubscriptionJSON uid sub = v1 $
    obj [ "user_id" .= tshow (uid ^. _UserId)
    , "billable_id" .= tshow (sub ^. (B.billable . B._BillableId))
  • file addition: Payments (d--r------)
    [3.679]
  • file addition: Types.hs (----------)
    [0.10523]
    {-# LANGUAGE TemplateHaskell #-}
    module Aftok.Payments.Types where
    import ClassyPrelude
    import Control.Lens (makeLenses, makePrisms)
    import Data.Thyme.Clock as C
    import Data.UUID
    import qualified Network.Bippy.Proto as P
    import Aftok.Billables (SubscriptionId)
    newtype PaymentRequestId = PaymentRequestId UUID deriving (Show, Eq)
    makePrisms ''PaymentRequestId
    newtype PaymentId = PaymentId UUID deriving (Show, Eq)
    makePrisms ''PaymentId
    data PaymentRequest' s = PaymentRequest
    { _subscription :: s
    , _paymentRequest :: P.PaymentRequest
    , _paymentRequestDate :: C.UTCTime
    }
    makeLenses ''PaymentRequest'
    type PaymentRequest = PaymentRequest' SubscriptionId
    data Payment' r = Payment
    { _request :: r
    , _payment :: P.Payment
    , _paymentDate :: C.UTCTime
    }
    makeLenses ''Payment'
    type Payment = Payment' PaymentRequestId
  • edit in lib/Aftok/Payments.hs at line 2
    [3.5720]
    [3.5720]
    {-# LANGUAGE FlexibleContexts #-}
  • replacement in lib/Aftok/Payments.hs at line 4
    [3.5721][3.5721:5749]()
    module Aftok.Payments where
    [3.5721]
    [3.5749]
    module Aftok.Payments
    ( module Aftok.Payments
    , module Aftok.Payments.Types
    ) where
  • replacement in lib/Aftok/Payments.hs at line 11
    [3.5782][2.2213:2275]()
    import Control.Lens (makeLenses, makePrisms)
    [3.5782]
    [3.5839]
    import Control.Lens (makeLenses, view, (%~), (^.))
    import Control.Lens.Tuple
    import Control.Monad.Except (MonadError)
    import Crypto.PubKey.RSA.Types (Error(..), PrivateKey)
    import Crypto.Random.Types (MonadRandom)
  • edit in lib/Aftok/Payments.hs at line 17
    [3.5840]
    [2.2276]
    import Data.AffineSpace ((.+^))
    import Data.Map.Strict (assocs)
  • replacement in lib/Aftok/Payments.hs at line 20
    [2.2318][3.5889:5916](),[3.5889][3.5889:5916]()
    import Data.UUID
    [2.2318]
    [3.5916]
    import Data.Thyme.Time.Core (fromThyme)
  • edit in lib/Aftok/Payments.hs at line 22
    [3.5917]
    [3.5917]
    import qualified Network.Bippy as B
  • edit in lib/Aftok/Payments.hs at line 24
    [3.5959]
    [3.5959]
    import qualified Network.Bippy.Types as BT
    import Network.Haskoin.Script (ScriptOutput(..))
    import Network.URI
  • edit in lib/Aftok/Payments.hs at line 28
    [3.5960]
    [2.2319]
    import Aftok (UserId, BtcAddr(..), userAddress, _BtcAddr)
    import Aftok.Database
  • edit in lib/Aftok/Payments.hs at line 31
    [2.2352]
    [3.610]
    import Aftok.Payments.Types
    import Aftok.Project (ProjectId, depf)
    import qualified Aftok.TimeLog as TL
    import Aftok.Types (satoshi)
    data BillingConfig = BillingConfig
    { _network :: BT.Network
    , _signingKey :: PrivateKey
    , _pkiData :: BT.PKIData
    }
    makeLenses ''BillingConfig
    createPaymentRequests :: (MonadRandom m, MonadReader BillingConfig m, MonadError Error m, MonadDB m) =>
    C.UTCTime -- timestamp for payment request creation
    -> (Subscription' Billable -> m (Maybe Text)) -- generator user memo
    -> (Subscription' Billable -> m (Maybe URI)) -- generator for payment response URL
    -> (Subscription' Billable -> m (Maybe ByteString)) -- generator for merchant payload
    -> UserId -- user responsible for payment
    -> ProjectId -- project whose worklog is to be paid out to
    -> m [PaymentRequestId]
    createPaymentRequests t memogen urigen plgen custId pid = do
    subscriptions <- findSubscriptions custId pid
    cfg <- ask
    let createPaymentDetails' s = do
    memo <- memogen s
    uri <- urigen s
    payload <- plgen s
    createPaymentDetails t memo uri payload (s ^. billable)
  • replacement in lib/Aftok/Payments.hs at line 61
    [3.611][3.5960:6029](),[3.5960][3.5960:6029](),[3.6029][3.612:642]()
    newtype PaymentRequestId = PaymentRequestId UUID deriving (Show, Eq)
    makePrisms ''PaymentRequestId
    [3.611]
    [3.6029]
    createPaymentRequest (sid, s) = do
    details <- createPaymentDetails' s
    req <- B.createPaymentRequest (cfg ^. signingKey) (cfg ^. pkiData) details
    liftdb $ CreatePaymentRequest custId (PaymentRequest sid req t)
    traverse createPaymentRequest subscriptions
    createPaymentDetails :: (MonadRandom m, MonadReader BillingConfig m, MonadDB m) =>
    C.UTCTime -- timestamp for payment request creation
    -> Maybe Text -- user memo
    -> Maybe URI -- payment response URL
    -> Maybe ByteString -- merchant payload
    -> Billable
    -> m P.PaymentDetails
    createPaymentDetails t memo uri payload b = do
    payouts <- getProjectPayouts t (b ^. project)
    outputs <- createPayoutsOutputs t (b ^. amount) payouts
    let expiry = (BT.Expiry . fromThyme . (t .+^)) <$> (b ^. requestExpiryPeriod)
    cfg <- ask
    pure $ B.createPaymentDetails (cfg ^. network) outputs (fromThyme t) expiry memo uri payload
    getProjectPayouts :: (MonadDB m) => C.UTCTime -> ProjectId -> m TL.Payouts
    getProjectPayouts ptime pid = do
    project' <-
    let projectOp = FindProject pid
    in maybe (raiseSubjectNotFound projectOp) pure =<< liftdb projectOp
    widx <- liftdb $ ReadWorkIndex pid
    pure $ TL.payouts (TL.toDepF $ project' ^. depf) ptime widx
    createPayoutsOutputs :: (MonadDB m) => C.UTCTime -> BT.Satoshi -> TL.Payouts -> m [BT.Output]
    createPayoutsOutputs t amt p =
    let payoutFractions :: [(TL.CreditTo, BT.Satoshi)]
    payoutFractions = (_2 %~ outputAmount amt) <$> assocs (p ^. TL._Payouts)
    in join <$> traverse (uncurry (createOutputs t)) payoutFractions
  • replacement in lib/Aftok/Payments.hs at line 100
    [3.6030][3.6030:6085](),[3.6085][3.643:666]()
    newtype PaymentId = PaymentId UUID deriving (Show, Eq)
    makePrisms ''PaymentId
    [3.6030]
    [3.6085]
    createOutputs :: (MonadDB m) => C.UTCTime -> TL.CreditTo -> BT.Satoshi -> m [BT.Output]
    createOutputs _ (TL.CreditToAddress (BtcAddr addr)) amt =
    pure $ [BT.Output amt (PayPKHash addr)]
  • replacement in lib/Aftok/Payments.hs at line 104
    [3.6086][3.1263:1303](),[3.1303][2.2353:2426](),[2.2426][3.6199:6236](),[3.6199][3.6199:6236](),[3.6255][3.6255:6259](),[3.6259][3.715:744]()
    data PaymentRequest' s = PaymentRequest
    { _subscription :: s
    , _paymentRequest :: P.PaymentRequest
    , _paymentRequestDate :: C.UTCTime
    }
    makeLenses ''PaymentRequest'
    [3.6086]
    [3.6287]
    createOutputs _ (TL.CreditToUser uid) amt = do
    addrMay <- (>>= view userAddress) <$> findUser uid
    let createOutput addr = BT.Output amt (PayPKHash (addr ^. _BtcAddr))
    pure . maybeToList $ createOutput <$> addrMay
  • replacement in lib/Aftok/Payments.hs at line 109
    [3.6288][3.745:798]()
    type PaymentRequest = PaymentRequest' SubscriptionId
    [3.6288]
    [3.798]
    createOutputs t (TL.CreditToProject pid) amt = do
    payouts <- getProjectPayouts t pid
    createPayoutsOutputs t amt payouts
  • edit in lib/Aftok/Payments.hs at line 113
    [3.799][3.1304:1330](),[3.1330][2.2427:2479](),[2.2479][3.6359:6389](),[3.6359][3.6359:6389](),[3.6405][3.6405:6409](),[3.6409][3.833:855]()
    data Payment' r = Payment
    { _request :: r
    , _payment :: P.Payment
    , _paymentDate :: C.UTCTime
    }
    makeLenses ''Payment'
  • replacement in lib/Aftok/Payments.hs at line 114
    [3.856][2.2480:2521]()
    type Payment = Payment' PaymentRequestId
    [3.856]
    outputAmount :: BT.Satoshi -> Rational -> BT.Satoshi
    outputAmount i r = BT.Satoshi . round $ toRational (i ^. satoshi) * r
  • edit in lib/Aftok/Project.hs at line 8
    [3.1198]
    [3.6468]
    import Crypto.Random.Types (MonadRandom, getRandomBytes)
  • edit in lib/Aftok/Project.hs at line 13
    [3.1325][3.6470:6471](),[3.6471][3.1325:1357](),[3.1325][3.1325:1357]()
    import OpenSSL.Random
  • edit in lib/Aftok/Project.hs at line 20
    [3.1485]
    [3.1485]
  • replacement in lib/Aftok/Project.hs at line 32
    [3.1766][3.1766:1849]()
    randomInvCode :: IO InvitationCode
    randomInvCode = InvitationCode <$> randBytes 32
    [3.1766]
    [3.1849]
    randomInvCode :: (MonadRandom m) => m InvitationCode
    randomInvCode = InvitationCode <$> getRandomBytes 32
  • replacement in lib/Aftok/TimeLog.hs at line 120
    [3.1422][3.1422:1502]()
    workCredit :: (Functor f, Foldable f) => DepF -> C.UTCTime -> f Interval -> NDT
    [3.1422]
    [3.9530]
    workCredit :: (Foldable f) => DepF -> C.UTCTime -> f Interval -> NDT
  • replacement in lib/Aftok/TimeLog.hs at line 130
    [3.652][3.876:960](),[3.4871][3.876:960](),[3.876][3.876:960]()
    let addIntervalDiff :: (Functor f, Foldable f) => NDT -> f Interval -> (NDT, NDT)
    [3.4871]
    [3.4872]
    let addIntervalDiff :: (Foldable f) => NDT -> f Interval -> (NDT, NDT)
  • edit in lib/Aftok/Util.hs at line 1
    [3.10061]
    [3.10062]
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  • replacement in lib/Aftok/Util.hs at line 11
    [3.10200][3.10200:10236]()
    type Program f a = F (Coyoneda f) a
    [3.10200]
    [3.10236]
    newtype Program (f :: * -> *) (a :: *) = Program
    { runProgram :: F (Coyoneda f) a }
    deriving (Functor, Applicative, Monad)
  • replacement in lib/Aftok/Util.hs at line 19
    [3.10423][3.10423:10442]()
    in iterM eval p
    [3.10423]
    [3.10442]
    in iterM eval (runProgram p)
  • replacement in lib/Aftok/Util.hs at line 22
    [3.10468][3.10468:10494]()
    fc = liftF . liftCoyoneda
    [3.10468]
    [3.6817]
    fc = Program . liftF . liftCoyoneda
  • replacement in migrations/2016-12-31_03-45-17_create-payments.txt at line 49
    [3.8976][3.8976:9031]()
    event_id uuid not null references aftok_events(id)
    [3.8976]
    [3.9031]
    event_id uuid not null references aftok_events(id),
    start_date date not null,
    end_date date null
  • edit in server/Aftok/QConfig.hs at line 1
    [3.4500]
    [3.4501]
    {-# LANGUAGE TypeApplications #-}
  • edit in server/Aftok/QConfig.hs at line 9
    [3.6698]
    [3.6698]
    import qualified Network.Bippy.Types as B
  • edit in server/Aftok/QConfig.hs at line 26
    [3.7190]
    [3.7190]
    , btcConfig :: BtcConfig
  • edit in server/Aftok/QConfig.hs at line 37
    [3.5085]
    [3.5085]
    data BtcConfig = BtcConfig
    { btcNetwork :: B.Network }
  • edit in server/Aftok/QConfig.hs at line 55
    [3.572]
    [74.3]
    <*> readBtcConfig cfg
  • replacement in server/Aftok/QConfig.hs at line 65
    [3.5812][3.5812:5887]()
    baseSnapConfig :: MonadSnap m => QConfig -> SC.Config m a -> SC.Config m a
    [3.5812]
    [3.7525]
    readBtcConfig :: CT.Config -> IO BtcConfig
    readBtcConfig cfg =
    let parseNetwork :: String -> B.Network
    parseNetwork "main" = B.MainNet
    parseNetwork _ = B.TestNet
    in (BtcConfig . parseNetwork) <$> C.require cfg "network"
    baseSnapConfig :: QConfig -> SC.Config m a -> SC.Config m a
  • edit in server/Aftok/QConfig.hs at line 82
    [3.6294]
  • replacement in server/Aftok/Snaplet/Auctions.hs at line 22
    [3.2895][3.2895:2926]()
    import Aftok.Snaplet
    [3.2895]
    [3.2926]
    import Aftok.Snaplet as S
  • replacement in server/Aftok/Snaplet/Auctions.hs at line 25
    [3.2963][3.964:986]()
    import Snap
    [3.2963]
    [3.2993]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet/Auctions.hs at line 41
    [3.3307][3.3307:3357]()
    auctionCreateHandler :: Handler App App AuctionId
    [3.3307]
    [3.3357]
    auctionCreateHandler :: S.Handler App App AuctionId
  • replacement in server/Aftok/Snaplet/Auctions.hs at line 51
    [3.988][3.988:1033]()
    auctionGetHandler :: Handler App App Auction
    [3.988]
    [3.1033]
    auctionGetHandler :: S.Handler App App Auction
  • replacement in server/Aftok/Snaplet/Auctions.hs at line 58
    [3.1246][3.1246:1289]()
    auctionBidHandler :: Handler App App BidId
    [3.1246]
    [3.1289]
    auctionBidHandler :: S.Handler App App BidId
  • replacement in server/Aftok/Snaplet/Auth.hs at line 17
    [3.7978][3.7978:8008]()
    import Snap.Snaplet
    [3.7978]
    [3.8009]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet/Auth.hs at line 20
    [3.644][3.8060:8104]()
    requireLogin :: Handler App App AU.AuthUser
    [3.644]
    [3.1209]
    requireLogin :: S.Handler App App AU.AuthUser
  • replacement in server/Aftok/Snaplet/Auth.hs at line 28
    [3.1540][3.8204:8247]()
    requireUser :: Handler App App AU.AuthUser
    [3.1540]
    [3.8247]
    requireUser :: S.Handler App App AU.AuthUser
  • replacement in server/Aftok/Snaplet/Auth.hs at line 33
    [3.1683][3.1683:1723]()
    requireUserId :: Handler App App UserId
    [3.1683]
    [3.1723]
    requireUserId :: S.Handler App App UserId
  • replacement in server/Aftok/Snaplet/Payments.hs at line 11
    [3.9959][2.2951:2992](),[2.2992][3.10001:10028](),[3.10001][3.10001:10028]()
    requestPaymentHandler :: Handler App App
    requestPaymentHandler = do
    [3.9959]
    [3.10028]
    import Aftok.QConfig
    requestPaymentHandler :: QConfig -> Handler App App
    requestPaymentHandler cfg = do
  • replacement in server/Aftok/Snaplet/Payments.hs at line 19
    [3.10163][3.10163:10265](),[3.10265][2.2993:3022]()
    payouts <- snapEval $ fc (ReadWorkIndex pid)
    pure $ payouts (toDepF $ project ^. depf) ptime widx
    -- look up the outstanding
    [3.10163]
    [3.10295]
    widx <- snapEval $ fc (ReadWorkIndex pid)
    -- look up outstanding subscriptions the user has for this project
    -- determine which subscriptions need to be paid
    -- create a payment request for each subscription
  • edit in server/Aftok/Snaplet/Payments.hs at line 24
    [3.10307]
    [3.10307]
  • edit in server/Aftok/Snaplet/Payments.hs at line 27
    [3.10308]
  • replacement in server/Aftok/Snaplet/Projects.hs at line 30
    [3.2624][3.2624:2654]()
    import Snap.Snaplet
    [3.2624]
    [3.2725]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet/Projects.hs at line 38
    [3.3056][3.3056:3106]()
    projectCreateHandler :: Handler App App ProjectId
    [3.2915]
    [3.3106]
    projectCreateHandler :: S.Handler App App ProjectId
  • replacement in server/Aftok/Snaplet/Projects.hs at line 46
    [3.3443][3.12241:12294]()
    projectListHandler :: Handler App App [KeyedProject]
    [3.3443]
    [3.1433]
    projectListHandler :: S.Handler App App [KeyedProject]
  • replacement in server/Aftok/Snaplet/Projects.hs at line 51
    [3.1564][3.3401:3446]()
    projectGetHandler :: Handler App App Project
    [3.1564]
    [3.3446]
    projectGetHandler :: S.Handler App App Project
  • replacement in server/Aftok/Snaplet/Projects.hs at line 58
    [3.8937][3.8937:8991]()
    projectInviteHandler :: QConfig -> Handler App App ()
    [3.8937]
    [3.8991]
    projectInviteHandler :: QConfig -> S.Handler App App ()
  • replacement in server/Aftok/Snaplet/Users.hs at line 22
    [3.8941][3.8941:8971]()
    import Snap.Snaplet
    [3.8941]
    [3.8971]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet/Users.hs at line 49
    [3.4425][3.10962:11004]()
    registerHandler :: Handler App App UserId
    [3.4425]
    [3.657]
    registerHandler :: S.Handler App App UserId
  • replacement in server/Aftok/Snaplet/Users.hs at line 63
    [3.585][3.585:631]()
    acceptInvitationHandler :: Handler App App ()
    [3.585]
    [3.631]
    acceptInvitationHandler :: S.Handler App App ()
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 23
    [3.10091][3.10091:10121]()
    import Snap.Snaplet
    [3.10091]
    [3.5830]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 25
    [3.8282][3.3150:3219](),[3.5831][3.3150:3219]()
    logWorkHandler :: (C.UTCTime -> LogEvent) -> Handler App App EventId
    [3.5831]
    [3.10122]
    logWorkHandler :: (C.UTCTime -> LogEvent) -> S.Handler App App EventId
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 35
    [3.571][3.571:643]()
    logWorkBTCHandler :: (C.UTCTime -> LogEvent) -> Handler App App EventId
    [3.571]
    [3.643]
    logWorkBTCHandler :: (C.UTCTime -> LogEvent) -> S.Handler App App EventId
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 49
    [3.6348][3.1566:1618]()
    loggedIntervalsHandler :: Handler App App WorkIndex
    [3.6348]
    [3.3428]
    loggedIntervalsHandler :: S.Handler App App WorkIndex
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 55
    [3.6632][3.4859:4907]()
    logEntriesHandler :: Handler App App [LogEntry]
    [3.6632]
    [3.4907]
    logEntriesHandler :: S.Handler App App [LogEntry]
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 67
    [3.5386][3.1662:1704](),[3.6632][3.1662:1704]()
    payoutsHandler :: Handler App App Payouts
    [3.5386]
    [3.10183]
    payoutsHandler :: S.Handler App App Payouts
  • replacement in server/Aftok/Snaplet/WorkLog.hs at line 77
    [3.3782][3.8683:8732]()
    amendEventHandler :: Handler App App AmendmentId
    [3.3782]
    [3.8732]
    amendEventHandler :: S.Handler App App AmendmentId
  • replacement in server/Aftok/Snaplet.hs at line 21
    [3.10882][3.10882:10912]()
    import Snap.Snaplet
    [3.10882]
    [3.10912]
    import Snap.Snaplet as S
  • replacement in server/Aftok/Snaplet.hs at line 33
    [3.1864][3.1864:1907]()
    instance HasPostgres (Handler b App) where
    [3.1864]
    [3.11449]
    instance HasPostgres (S.Handler b App) where
  • replacement in server/Aftok/Snaplet.hs at line 37
    [3.2007][3.11545:11605]()
    snapEval :: (MonadSnap m, HasPostgres m) => DBProg a -> m a
    [3.2007]
    [3.11605]
    snapEval :: (MonadSnap m, HasPostgres m) => Program DBOp a -> m a
  • replacement in server/Aftok/Snaplet.hs at line 46
    [3.11873][3.11873:11945]()
    e <- liftPG $ \conn -> runEitherT (runQDBM conn $ interpret dbEval p)
    [3.11873]
    [3.11945]
    e <- liftPG $ \conn -> liftIO $ runEitherT (runQDBM conn $ interpret liftdb p)
  • replacement in server/Aftok/Snaplet.hs at line 70
    [3.9524][3.9524:9648]()
    readRequestJSON :: MonadSnap m => Int64 -> m A.Value
    readRequestJSON i = do
    requestBody <- A.decode <$> readRequestBody i
    [3.9524]
    [3.9648]
    readRequestJSON :: MonadSnap m => Word64 -> m A.Value
    readRequestJSON len = do
    requestBody <- A.decode <$> readRequestBody len
  • replacement in server/Main.hs at line 35
    [3.11874][3.12437:12521](),[3.8568][3.12437:12521]()
    initCookieSessionManager (authSiteKey cfg) "quookie" (cookieTimeout cfg)
    [3.11874]
    [3.12521]
    initCookieSessionManager (authSiteKey cfg) "quookie" (Just "aftok.com") (cookieTimeout cfg)
  • file addition: stack-deps.yaml (----------)
    [76.2]
    ---
    - Boolean-0.2.3
    - HUnit-1.3.1.2
    - MemoTrie-0.6.4
    - MonadRandom-0.4.2.3
    - NumInstances-1.4
    - QuickCheck-2.8.2
    - RSA-2.2.0
    - ReadArgs-1.2.3
    - SHA-1.6.4.2
    - StateVar-1.1.0.4
    - adjunctions-4.3
    - aeson-0.11.2.1
    - aftok-0.1
    - ansi-terminal-0.6.2.3
    - ansi-wl-pprint-0.6.7.3
    - array-0.5.1.1
    - asn1-encoding-0.9.4
    - asn1-parse-0.9.4
    - asn1-types-0.3.2
    - async-2.1.1
    - attoparsec-0.13.1.0
    - authenticate-oauth-1.5.1.2
    - base-4.9.0.0
    - base-orphans-0.5.4
    - base16-bytestring-0.1.1.6
    - base64-bytestring-1.0.0.1
    - basic-prelude-0.6.1
    - bifunctors-5.4.1
    - binary-0.8.3.0
    - bippy-0.1.0.0
    - blaze-builder-0.4.0.2
    - blaze-html-0.8.1.3
    - blaze-markup-0.7.1.1
    - byteable-0.1.1
    - bytedump-1.0
    - bytestring-0.10.8.1
    - bytestring-builder-0.10.8.1.0
    - case-insensitive-1.2.0.7
    - cereal-0.5.4.0
    - chunked-data-0.3.0
    - cipher-aes-0.2.11
    - classy-prelude-1.0.2
    - clientsession-0.9.1.2
    - clock-0.7.2
    - comonad-5
    - conduit-1.2.8
    - configurator-0.3.0.0
    - connection-0.2.6
    - constraints-0.8
    - containers-0.5.7.1
    - contravariant-1.4
    - cookie-0.4.2.1
    - cprng-aes-0.6.1
    - crypto-api-0.13.2
    - crypto-cipher-types-0.0.9
    - crypto-pubkey-types-0.4.3
    - crypto-random-0.0.9
    - cryptohash-0.11.9
    - cryptohash-md5-0.11.100.1
    - cryptohash-sha1-0.11.100.1
    - cryptonite-0.21
    - data-binary-ieee754-0.4.4
    - data-default-0.7.1.1
    - data-default-class-0.1.2.0
    - data-default-instances-containers-0.0.1
    - data-default-instances-dlist-0.0.1
    - data-default-instances-old-locale-0.0.1
    - deepseq-1.4.2.0
    - directory-1.2.6.2
    - directory-tree-0.12.1
    - distributive-0.5.1
    - dlist-0.8.0.2
    - dlist-instances-0.1.1.1
    - either-4.4.1.1
    - entropy-0.3.7
    - errors-2.1.3
    - exceptions-0.8.3
    - fail-4.9.0.0
    - filepath-1.4.1.0
    - free-4.12.4
    - ghc-prim-0.5.0.0
    - groups-0.4.0.0
    - hashable-1.2.4.0
    - haskoin-core-0.4.0
    - heaps-0.3.3
    - heist-1.0.1.0
    - hourglass-0.2.10
    - http-client-0.4.31.2
    - http-client-tls-0.2.4.1
    - http-types-0.9.1
    - integer-gmp-1.0.0.1
    - io-streams-1.3.6.0
    - io-streams-haproxy-1.0.0.1
    - iso8601-time-0.1.4
    - kan-extensions-5.0.1
    - keys-3.11
    - largeword-1.2.5
    - lens-4.14
    - lens-aeson-1.0.0.5
    - lifted-async-0.9.1
    - lifted-base-0.2.3.8
    - map-syntax-0.2.0.1
    - memory-0.13
    - mime-mail-0.4.12
    - mime-types-0.1.0.7
    - mmorph-1.0.9
    - monad-control-1.0.1.0
    - monad-unlift-0.2.0
    - mono-traversable-1.0.1
    - mono-traversable-instances-0.1.0.0
    - mtl-2.2.1
    - murmur3-1.0.3
    - mutable-containers-0.3.3
    - mwc-random-0.13.5.0
    - network-2.6.3.1
    - network-info-0.2.0.8
    - network-uri-2.6.1.0
    - old-locale-1.0.0.7
    - optparse-applicative-0.12.1.0
    - parallel-3.2.1.0
    - parsec-3.1.11
    - pbkdf-1.1.1.1
    - pem-0.2.2
    - pointed-5
    - postgresql-libpq-0.9.3.0
    - postgresql-simple-0.5.2.1
    - prelude-extras-0.4.0.3
    - primitive-0.6.1.0
    - process-1.4.2.0
    - profunctors-5.2
    - protobuf-0.2.1.1
    - psqueues-0.2.2.3
    - pureMD5-2.1.3
    - pwstore-fast-2.4.4
    - random-1.1
    - readable-0.3.1
    - reflection-2.1.2
    - regex-base-0.93.2
    - regex-posix-0.95.2
    - resource-pool-0.2.3.2
    - resourcet-1.1.9
    - safe-0.3.10
    - safe-exceptions-0.1.4.0
    - say-0.1.0.0
    - scientific-0.3.4.9
    - secp256k1-0.4.6
    - securemem-0.1.9
    - semigroupoids-5.1
    - semigroups-0.18.2
    - setenv-0.1.1.3
    - skein-1.0.9.4
    - smtp-mail-0.1.4.6
    - snap-1.0.0.1
    - snap-core-1.0.1.0
    - snap-server-1.0.1.1
    - snaplet-postgresql-simple-1.0.1.0
    - socks-0.5.5
    - split-0.2.3.1
    - stm-2.4.4.1
    - stm-chans-3.0.0.4
    - streaming-commons-0.1.16
    - string-conversions-0.4.0.1
    - syb-0.6
    - system-filepath-0.4.13.4
    - tagged-0.8.5
    - template-haskell-2.11.0.0
    - text-1.2.2.1
    - tf-random-0.5
    - thyme-0.3.5.5
    - time-1.6.0.1
    - time-locale-compat-0.1.1.3
    - tls-1.3.9
    - transformers-0.5.2.0
    - transformers-base-0.4.4
    - transformers-compat-0.5.1.4
    - unexceptionalio-0.3.0
    - unix-2.7.2.0
    - unix-compat-0.4.3.1
    - unordered-containers-0.2.7.2
    - utf8-string-1.0.1.1
    - uuid-1.3.13
    - uuid-types-1.0.3
    - vector-0.11.0.0
    - vector-algorithms-0.7.0.1
    - vector-instances-3.3.1
    - vector-space-0.10.4
    - vector-th-unbox-0.2.1.6
    - void-0.7.1
    - wreq-0.4.1.0
    - x509-1.6.5
    - x509-store-1.6.2
    - x509-system-1.6.4
    - x509-validation-1.6.5
    - xmlhtml-0.2.3.5
    - zlib-0.6.1.2
    - zlib-bindings-0.1.1.5
  • replacement in stack.yaml at line 6
    [3.10594][3.10594:10647]()
    commit: 6284d5fff3954e0e52d559298364035a220867af
    [3.10594]
    [3.10647]
    commit: ddfc1bf0911351d0be51f33ea9e4166a24d2b19a
  • replacement in stack.yaml at line 10
    [3.10695][3.10695:11016](),[3.11016][3.1150:1182](),[3.1150][3.1150:1182](),[3.1182][3.11017:11119](),[3.11119][3.1182:1200](),[3.1182][3.1182:1200]()
    - aeson-0.11.2.1
    - base-orphans-0.5.4
    - bytestring-builder-0.10.8.1.0
    - call-stack-0.1.0
    - haskoin-core-0.4.0
    - hspec-2.3.2
    - hspec-core-2.3.2
    - hspec-discover-2.3.2
    - hspec-expectations-0.8.2
    - mmorph-1.0.9
    - mono-traversable-0.10.2
    - murmur3-1.0.1
    - pbkdf-1.1.1.1
    - postgresql-libpq-0.9.2.0
    - postgresql-simple-0.5.2.1
    - resource-pool-catchio-0.2.1.0
    - secp256k1-0.4.5
    - snaplet-postgresql-simple-0.6.0.4
    - unix-compat-0.4.3.1
    - vector-th-unbox-0.2.1.6
    resolver: lts-5.3
    [3.10695]
    - heist-1.0.1.0
    - map-syntax-0.2.0.1
    - snap-1.0.0.1
    - snaplet-postgresql-simple-1.0.1.0
    resolver: lts-7.16