Follow the types! Too many functions were taking Value as their input rather than Object (for all versioned data structures.) This ended up cleaning up code in a number of unexpected places.
7VGYLTMURLVSVUYFW7TCRZTDQ6RE2EPSPPA43XKHDOBFWYVVSJHQC
FXJQACESPGTLPG5ELXBU3M3OQXUZQQIR7HPIEHQ3FNUTMWVH4WBAC
GKLIPHR5YOBKEMC4744J3WYYFLPFXMZEOLC6Z26QXAG4IM2HQVEQC
2LZYVHFSGAHDZD4TKSSHUHYR3N6LJFDSWUV2SFVP3GXNT7Y43BNQC
M3KUPGZK2UTW4FG3Q632K7P7MI4FVWD5TTIP45UTI3E72UKOWJBAC
4ZLEDBK7VGLKFUPENAFLUJYNFLKFYJ3TREPQ7P6PKMYGJUXB55HQC
JEOPOOPTQ7ESS2IG7KROXNF67RB37X63GVM6UK3FYMZG6VUUQG2AC
GCVQD44VRPQVKPZEPIC4AOIXLJIG2ZMV3QI2Y7KALUT6NVUBSGSAC
W35DDBFYF6Z4ZPCFEO5RPAONZLYCSNTXUSTS6FIUUVZHCI6Q7GHAC
XTBSG4C7SCZUFOU2BTNFR6B6TCGYI35BWUV4PVTS3N7KNH5VEARQC
A6HKMINBNGQLLX4QJMYWKQ4JAEHVJ4HIRVDKPPDI3FJUO2AAB7OQC
O722AOKEWXWJPRHGJREU6QPW7HEFPPRETZIAADZ2RMAXHARCNEKAC
Z3MK2PJ5U222DXRS22WCDHVPZ7HVAR3HOCUNXIGX6VMEPBQDF6PQC
NLZ3JXLOOIL37O3RRQWXHNPNSNEOOLPD6MCB754BEBECQB3KGR2AC
POX3UAMTGCNS3SU5I6IKDNCCSHEAUSFBZ3WCMQ3EXKPNXETOI6BAC
2XQD6KKKD6QVHFHAEMVE3XXY7X2T7BLTLL7XIILZAXNJJH2YONUQC
7HPY3QPFPN35PSPUBVNW2GTFB3CBQZBST4J2BAVJ7QMXLIUN52JAC
O5FVTOM6YFBLEPF3S576K6IMT6ZZ5VQCSB3YVXNS4CKBITKCRZ7AC
ASF3UPJLCX7KIUCNJD5KAXSPDXCUEJHLL4HBRTRUBPCW73IXOCWQC
Z7KS5XHHC6PAMTVBHXY7KUSS3BWAOU6FSYIITUCFOOJZU4OUJHBAC
RN7EI6INGUUHGMNY5RU3NH56WPLRZY5ZMYDNFMNE3TGV4ESFLQIAC
RPAJLHMTUJU4AYNBOHVGHGGB4NY2NLY3BVPYN5FMWB3ZIMAUQHCQC
UILI6PILCRDPZ3XYA54LGIGPSU7ERWNHCE7R3CE64ZEC7ONOEMOQC
BWN72T44GRRZ6K2OPN56FTLNEB7J7AGC7T2U5HSMLEKUPGJP2NUAC
SPJCFHXWUHL5DPU72R6MLMVYCRL4YNOMGTDXRFL6GZPN5KOHAW7AC
2G3GNDDUOVPF45PELJ65ZB2IXEHJJXJILFRVHZXGPXUL4BVNZJFQC
HALRDT2F22DAQ54M334YSKD2XJCAXDXEZPDKGMOWKH7XELBAS6MAC
flags: {}
packages:
- '.'
extra-deps:
- snaplet-postgresql-simple-0.6.0.4
- resource-pool-catchio-0.2.1.0
resolver: lts-5.3
#allow-newer: true
local-bin-path: /opt/aftok/bin
unversion :: (Version -> Value -> Parser a) -> Value -> Parser a
unversion f (Object v) = do
verstr <- v .: "schemaVersion"
unversion :: String -> (Version -> Object -> Parser a) -> Value -> Parser a
unversion name f o = do
verstr <- withObject name (.: "schemaVersion") o
v .: "value" >>= f vers
unversion _ x =
fail $ show x <> " did not contain the expected version information."
withObject name (f vers) o
unv1 :: String -> (Value -> Parser a) -> Value -> Parser a
unv1 name f = unversion $ \x -> case x of
Version 1 0 -> f
_ -> badVersion name x
unv1 :: String -> (Object -> Parser a) -> Value -> Parser a
unv1 name f = unversion name $ p where
p (Version 1 0) = f
p ver = badVersion name ver
object [ "projectId" .= tshow (pid ^. _ProjectId)
, "project" .= projectJSON project
]
obj [ "projectId" .= tshow (pid ^. _ProjectId)
, "project" .= projectJSON project
]
object [ "projectName" .= (p ^. projectName)
, "inceptionDate" .= (p ^. inceptionDate)
, "initiator" .= tshow (p ^. (P.initiator._UserId))
]
obj [ "projectName" .= (p ^. projectName)
, "inceptionDate" .= (p ^. inceptionDate)
, "initiator" .= tshow (p ^. (P.initiator._UserId))
]
object [ "projectId" .= tshow (x ^. (A.projectId._ProjectId))
, "initiator" .= tshow (x ^. (A.initiator._UserId))
, "raiseAmount" .= (x ^. (raiseAmount._Satoshi))
]
obj [ "projectId" .= tshow (x ^. (A.projectId._ProjectId))
, "initiator" .= tshow (x ^. (A.initiator._UserId))
, "raiseAmount" .= (x ^. (raiseAmount._Satoshi))
]
creditToJSON (CreditToAddress addr) = v2 $ object [ "creditToAddress" .= (addr ^. _BtcAddr) ]
creditToJSON (CreditToUser uid) = v2 $ object [ "creditToUser" .= tshow (uid ^. _UserId) ]
creditToJSON (CreditToProject pid) = v2 $ object [ "creditToProject" .= projectIdJSON pid ]
creditToJSON (CreditToAddress addr) = v2 $ obj [ "creditToAddress" .= (addr ^. _BtcAddr) ]
creditToJSON (CreditToUser uid) = v2 $ obj [ "creditToUser" .= tshow (uid ^. _UserId) ]
creditToJSON (CreditToProject pid) = v2 $ obj [ "creditToProject" .= projectIdJSON pid ]
object [ "creditTo" .= creditToJSON c
, "event" .= logEventJSON ev
, "eventMeta" .= m
]
obj [ "creditTo" .= creditToJSON c
, "event" .= logEventJSON ev
, "eventMeta" .= m
]
parseCreditTo :: Value -> Parser CreditTo
parseCreditTo = unversion "CreditTo" $ p where
p (Version 1 0) = parseCreditToV1
p (Version 2 0) = parseCreditToV2
p ver = badVersion "EventAmendment" ver
parseCreditToV1 :: Object -> Parser CreditTo
parseCreditToV1 x = CreditToAddress <$> (parseBtcAddrJson =<< (x .: "btcAddr"))
parseCreditToV2 :: Object -> Parser CreditTo
parseCreditToV2 o =
let parseCreditToAddr o' =
fmap CreditToAddress . parseBtcAddrJson <$> O.lookup "creditToAddress" o'
parseCreditToUser o' =
fmap (CreditToUser . UserId) . parseUUID <$> O.lookup "creditToUser" o'
parseCreditToProject o' =
fmap (CreditToProject . ProjectId) . parseUUID <$> O.lookup "creditToProject" o'
notFound = fail $ "Value " <> show o <> " does not represent a CreditTo value."
parseV v = (parseCreditToAddr v <|> parseCreditToUser v <|> parseCreditToProject v)
in fromMaybe notFound $ parseV o
parsePayoutsJSON = unversion $ \ver -> case ver of
(Version 1 _) -> \v -> Payouts . MS.mapKeys (CreditToAddress . BtcAddr) <$> parseJSON v
(Version 2 0) -> \v -> do
xs <- parseJSON v
let parsePayoutRecord x = (,) <$> (parseCreditTo =<< (x .: "creditTo"))
<*> x .: "payoutRatio"
Payouts . MS.fromList <$> traverse parsePayoutRecord xs
_ -> badVersion "Payouts" ver
parsePayoutsJSON = unversion "Payouts" $ p where
p :: Version -> Object -> Parser Payouts
p (Version 1 _) v = Payouts . MS.mapKeys (CreditToAddress . BtcAddr) <$> parseJSON (Object v)
p (Version 2 0) v =
let parsePayoutRecord x = (,) <$> (parseCreditToV2 =<< (x .: "creditTo")) <*> x .: "payoutRatio"
in Payouts . MS.fromList <$> (traverse parsePayoutRecord =<< parseJSON (Object v))
p ver x = badVersion "Payouts" ver x
parseEventAmendment t = unversion $ \v -> case v of
Version 1 0 -> parseEventAmendmentV1 t
Version 2 0 -> parseEventAmendmentV2 t
_ -> badVersion "EventAmendment" v
parseEventAmendment t = unversion "EventAmendment" $ p where
p (Version 1 _) = parseEventAmendmentV1 t
p (Version 2 0) = parseEventAmendmentV2 t
p ver = badVersion "EventAmendment" ver
parseA "timeChange" = TimeChange t <$> x .: "eventTime"
parseA "addrChange" = CreditToChange t <$> parseCreditTo v
parseA "metadataChange" = MetadataChange t <$> x .: "eventMeta"
parseA "timeChange" = TimeChange t <$> o .: "eventTime"
parseA "addrChange" = CreditToChange t <$> parseCreditToV1 o
parseA "metadataChange" = MetadataChange t <$> o .: "eventMeta"
in x .: "amendment" >>= parseA
parseEventAmendmentV1 _ x =
fail $ "Value " <> show x <> " is not a JSON object."
in o .: "amendment" >>= parseA
parseA "timeChange" = TimeChange t <$> x .: "eventTime"
parseA "creditToChange" = CreditToChange t <$> parseCreditTo v
parseA "metadataChange" = MetadataChange t <$> x .: "eventMeta"
parseA "timeChange" = TimeChange t <$> o .: "eventTime"
parseA "creditToChange" = CreditToChange t <$> parseCreditToV2 o
parseA "metadataChange" = MetadataChange t <$> o .: "eventMeta"
parseCreditTo :: Value -> Parser CreditTo
parseCreditTo = unversion $ \v -> case v of
Version 1 0 -> withObject "BtcAddr" parseCreditToV1
Version 2 0 -> withObject "CreditTo" parseCreditToV2
_ -> badVersion "EventAmendment" v
parseCreditToV1 :: Object -> Parser CreditTo
parseCreditToV1 x = CreditToAddress <$> (parseBtcAddrJson =<< (x .: "btcAddr"))
parseCreditToV2 :: Object -> Parser CreditTo
parseCreditToV2 x =
let parseCreditToAddr (Object x') = do
addrText <- O.lookup "creditToAddress" x'
pure (CreditToAddress <$> parseBtcAddrJson addrText)
parseCreditToAddr _ = Nothing
parseCreditToUser (Object x') = do
userText <- O.lookup "creditToUser" x'
pure (CreditToUser . UserId <$> parseUUID userText)
parseCreditToUser _ = Nothing
--parseCreditToProject (Object x') = Nothing
parseCreditToProject _ = Nothing
notFound = fail $ "Value " <> show x <> " does not represent a CreditTo value."
parseV v = (parseCreditToAddr v <|> parseCreditToUser v <|> parseCreditToProject v)
in do
body <- x .: "creditTo"
fromMaybe notFound $ parseV body
parseLogEntry f = unversion parseLogEntry' where
parseLogEntry' (Version 2 0) (Object x) = do
creditTo' <- x .: "creditTo" >>= parseCreditTo
eventMeta' <- x .:? "eventMeta"
parseLogEntry f = unversion "LogEntry" p where
p (Version 2 0) o = do
creditTo' <- o .: "creditTo" >>= parseCreditToV2
eventMeta' <- o .:? "eventMeta"
curl -v -k -u $USER -X POST -d "{\"creditTo\": {\"creditToUser\": \"$UID\"}}" "https://aftok.com/projects/$PID/logStart"
curl -v -k -u $USER -X POST -d "{\"schemaVersion\": \"2.0\", \"creditTo\": {\"creditToUser\": \"$UID\"}}" "https://aftok.com/projects/$PID/logStart"
auctionCreateParser = unv1 "auctions" $ \v ->
case v of
(Object o) -> CA <$> o .: "raiseAmount"
<*> o .: "auctionEnd"
_ -> mzero
auctionCreateParser = unv1 "auctions" p where
p o = CA <$> o .: "raiseAmount" <*> o .: "auctionEnd"
bidCreateParser uid t = unv1 "bids" $ \v ->
case v of
(Object o) -> Bid uid <$> (Seconds <$> o .: "bidSeconds")
<*> (Satoshi <$> o .: "bidAmount")
<*> pure t
_ -> mzero
bidCreateParser uid t = unv1 "bids" p where
p o = Bid uid <$> (Seconds <$> o .: "bidSeconds")
<*> (Satoshi <$> o .: "bidAmount")
<*> pure t