Skip to content

Commit

Permalink
feat(release): update f3c1916
Browse files Browse the repository at this point in the history
  • Loading branch information
dtfiedler committed Dec 18, 2023
1 parent 8008b90 commit f804a3f
Show file tree
Hide file tree
Showing 29 changed files with 1,508 additions and 144 deletions.
65 changes: 65 additions & 0 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,68 @@ paths:
schema:
type: string
default: "Invalid currency"

/redeem:
get:
summary: Redeem credits gifted via email
description: Redeem credits gifted via email by providing the destination wallet address for the credits, the redemption ID, and recipient email address

parameters:
- name: destinationAddress
in: query
required: true
schema:
type: string
description: Destination wallet address

- name: id
in: query
required: true
schema:
type: string
description: ID for the redemption

- name: email
in: query
required: true
schema:
type: string
description: Recipient email address for the redemption

responses:
"200":
description: OK
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: Payment receipt redeemed for 1000 winc!
userBalance:
type: string
example: 1000
userAddress:
type: string
example: abcdefghijklmnopqrxtuvwxyz123456789ABCDEFGH
userCreationDate:
type: string
example: 2023-05-17T21:46:38.404Z

"400":
description: Bad Request
content:
text/plain:
schema:
type: string
description: "Error message string dependent on cause"
example: "Failure to redeem payment receipt!"

"503":
description: Service Unavailable
content:
text/plain:
schema:
type: string
default: "Error while redeeming payment receipt. Unable to reach Database!"
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@
"@types/koa": "^2.13.4",
"@types/koa-router": "^7.4.4",
"@types/koa__cors": "^3.3.0",
"@types/mandrill-api": "^1.0.33",
"@types/mocha": "^9.1.1",
"@types/node": "^18.16.1",
"@types/sinon": "^10.0.11",
"@types/sinon-chai": "^3.2.9",
"@types/validator": "^13.11.7",
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"axios-mock-adapter": "^1.21.2",
Expand Down Expand Up @@ -78,12 +80,14 @@
"koa-jwt": "^4.0.4",
"koa-router": "11.0.1",
"koa2-swagger-ui": "^5.8.0",
"mandrill-api": "^1.0.45",
"p-limit": "^3.1.0",
"pg": "^8.8.0",
"prom-client": "^14.1.0",
"raw-body": "^2.5.2",
"sinon-chai": "^3.7.0",
"stripe": "^11.13.0",
"validator": "^13.11.0",
"winston": "^3.8.2",
"yaml": "^2.2.2"
}
Expand Down
2 changes: 2 additions & 0 deletions src/architecture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
import Stripe from "stripe";

import { Database } from "./database/database";
import { EmailProvider } from "./emailProvider";
import { PricingService } from "./pricing/pricing";

export interface Architecture {
paymentDatabase: Database;
pricingService: PricingService;
stripe: Stripe;
emailProvider?: EmailProvider;
}
8 changes: 8 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,11 @@ export const recognizedCountries = [
export const promoCodeBackfills = {
welcomeTwentyPercentOff: "TOKEN2049",
};

export const maxGiftMessageLength = process.env.MAX_GIFT_MESSAGE_LENGTH ?? 250;

export const giftingEmailAddress =
process.env.GIFTING_EMAILL_ADDRESS ?? "[email protected]";

/** gifting on top up via email depends on GIFTING_ENABLED="true" env var */
export const isGiftingEnabled = process.env.GIFTING_ENABLED === "true";
8 changes: 7 additions & 1 deletion src/database/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
SingleUseCodePaymentCatalog,
TopUpQuote,
TopUpQuoteId,
UnredeemedGift,
UploadAdjustmentCatalog,
User,
UserAddress,
Expand All @@ -47,7 +48,7 @@ export interface Database {
getBalance: (userAddress: UserAddress) => Promise<WC>;
createPaymentReceipt: (
paymentReceipt: CreatePaymentReceiptParams
) => Promise<void>;
) => Promise<void | UnredeemedGift>;
getPaymentReceipt: (
paymentReceiptId: PaymentReceiptId
) => Promise<PaymentReceipt>;
Expand Down Expand Up @@ -77,4 +78,9 @@ export interface Database {
) => Promise<SingleUseCodePaymentCatalog[]>;
getUploadAdjustmentCatalogs: () => Promise<UploadAdjustmentCatalog[]>;
getPaymentAdjustmentCatalogs(): Promise<PaymentAdjustmentCatalog[]>;
redeemGift: (params: {
paymentReceiptId: string;
recipientEmail: string;
destinationAddress: string;
}) => Promise<User>;
}
14 changes: 14 additions & 0 deletions src/database/dbConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export const tableNames = {
paymentAdjustmentCatalog: "payment_adjustment_catalog",
singleUseCodePaymentAdjustmentCatalog:
"single_use_code_payment_adjustment_catalog",

unredeemedGift: "unredeemed_gift",
redeemedGift: "redeemed_gift",
} as const;

export const columnNames = {
Expand All @@ -52,6 +55,7 @@ export const columnNames = {
quoteExpirationDate: "quote_expiration_date",
quoteCreationDate: "quote_creation_date",
paymentProvider: "payment_provider",
giftMessage: "gift_message", // Optional gift message, ignored in non-gift top-ups for now

// Failed top up quote
failedReason: "failed_reason",
Expand Down Expand Up @@ -105,4 +109,14 @@ export const columnNames = {

operator: "operator",
operatorMagnitude: "operator_magnitude",

// Unredeemed Gift
giftedWincAmount: "gifted_winc_amount",
recipientEmail: "recipient_email",
senderEmail: "sender_email",
creationDate: "creation_date",
expirationDate: "expiration_date",

// Redeemed Gift
redemptionDate: "redemption_date",
} as const;
22 changes: 20 additions & 2 deletions src/database/dbMaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
AdjustmentCatalogDBResult,
ChargebackReceipt,
ChargebackReceiptDBResult,
DestinationAddressType,
FailedTopUpQuote,
FailedTopUpQuoteDBResult,
PaymentAdjustmentCatalog,
Expand All @@ -31,9 +32,12 @@ import {
SingleUseCodePaymentCatalogDBResult,
TopUpQuote,
TopUpQuoteDBResult,
UnredeemedGift,
UnredeemedGiftDBResult,
UploadAdjustmentCatalog,
UploadAdjustmentCatalogDBResult,
User,
UserAddressType,
UserDBResult,
} from "./dbTypes";

Expand All @@ -47,7 +51,7 @@ export function userDBMap({
return {
promotionalInfo: promotional_info as PromotionalInfo,
userAddress: user_address,
userAddressType: user_address_type,
userAddressType: user_address_type as UserAddressType,
userCreationDate: user_creation_date,
winstonCreditBalance: new Winston(winston_credit_balance),
};
Expand All @@ -74,7 +78,7 @@ export function topUpQuoteDBMap({
quoteCreationDate: quote_creation_date,
quoteExpirationDate: quote_expiration_date,
destinationAddress: destination_address,
destinationAddressType: destination_address_type,
destinationAddressType: destination_address_type as DestinationAddressType,
winstonCreditAmount: new Winston(winston_credit_amount),
};
}
Expand Down Expand Up @@ -159,3 +163,17 @@ export function singleUseCodePaymentCatalogDBMap(
maximumDiscountAmount: dbResult.maximum_discount_amount,
};
}

export function unredeemedGiftDBMap(
dbResult: UnredeemedGiftDBResult
): UnredeemedGift {
return {
paymentReceiptId: dbResult.payment_receipt_id,
giftedWincAmount: new Winston(dbResult.gifted_winc_amount),
recipientEmail: dbResult.recipient_email,
giftMessage: dbResult.gift_message,
giftCreationDate: dbResult.creation_date,
giftExpirationDate: dbResult.expiration_date,
senderEmail: dbResult.sender_email,
};
}
53 changes: 50 additions & 3 deletions src/database/dbTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ export interface PaymentAdjustment extends Adjustment {
}

export type UserAddress = string | PublicArweaveAddress;
export type UserAddressType = string | "arweave";

export const userAddressTypes = ["arweave"] as const;
export type UserAddressType = (typeof userAddressTypes)[number];

export const destinationAddressTypes = ["email", "arweave"] as const;
export type DestinationAddressType = (typeof destinationAddressTypes)[number];

/** Currently using Postgres Date type (ISO String) */
export type Timestamp = string;
Expand Down Expand Up @@ -85,14 +90,15 @@ export interface User {
export interface TopUpQuote {
topUpQuoteId: TopUpQuoteId;
destinationAddress: UserAddress;
destinationAddressType: UserAddressType;
destinationAddressType: DestinationAddressType;
paymentAmount: PaymentAmount;
quotedPaymentAmount: PaymentAmount;
currencyType: CurrencyType;
winstonCreditAmount: WC;
quoteExpirationDate: Timestamp;
quoteCreationDate: Timestamp;
paymentProvider: PaymentProvider;
giftMessage?: string;
}

export type CreateTopUpQuoteParams = Omit<TopUpQuote, "quoteCreationDate"> & {
Expand All @@ -113,6 +119,7 @@ export interface CreatePaymentReceiptParams {
topUpQuoteId: TopUpQuoteId;
paymentAmount: PaymentAmount;
currencyType: CurrencyType;
senderEmail?: string;
}

export interface ChargebackReceipt extends PaymentReceipt {
Expand Down Expand Up @@ -180,7 +187,10 @@ export type AuditChangeReason =
| "payment"
| "account_creation"
| "chargeback"
| "refund";
| "refund"
| "gifted_payment"
| "gifted_payment_redemption"
| "gifted_account_creation";

export interface AuditLogInsert {
user_address: string;
Expand Down Expand Up @@ -209,6 +219,7 @@ export interface TopUpQuoteDBInsert {
winston_credit_amount: string;
payment_provider: string;
quote_expiration_date: string;
gift_message?: string;
}

export interface TopUpQuoteDBResult extends TopUpQuoteDBInsert {
Expand Down Expand Up @@ -338,3 +349,39 @@ export interface PaymentAdjustmentDBInsert extends AdjustmentDBInsert {
export interface PaymentAdjustmentDBResult
extends PaymentAdjustmentDBInsert,
AdjustmentDBResult {}

export interface UnredeemedGiftDBInsert {
payment_receipt_id: string;
gifted_winc_amount: string;
recipient_email: string;
sender_email?: string;
gift_message?: string;
}

export interface UnredeemedGiftDBResult extends UnredeemedGiftDBInsert {
creation_date: string;
expiration_date: string;
}

export interface RedeemedGiftDBInsert extends UnredeemedGiftDBResult {
destination_address: string;
}

export interface RedeemedGiftDBResult extends RedeemedGiftDBInsert {
redemption_date: string;
}

export interface UnredeemedGift {
paymentReceiptId: PaymentReceiptId;
giftedWincAmount: WC;
recipientEmail: string;
senderEmail?: string;
giftMessage?: string;
giftCreationDate: Timestamp;
giftExpirationDate: Timestamp;
}

export interface RedeemedGift extends UnredeemedGift {
destinationAddress: UserAddress;
redemptionDate: Timestamp;
}
14 changes: 14 additions & 0 deletions src/database/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,17 @@ export class PromoCodeExceedsMaxUses extends PromoCodeError {
this.name = "PromoCodeExceedsMaxUses";
}
}

export class GiftRedemptionError extends Error {
constructor(errorMessage = "Failure to redeem payment receipt!") {
super(errorMessage);
this.name = "GiftRedemptionError";
}
}

export class GiftAlreadyRedeemed extends GiftRedemptionError {
constructor() {
super("Gift has already been redeemed!");
this.name = "GiftAlreadyRedeemed";
}
}
Loading

0 comments on commit f804a3f

Please sign in to comment.