Skip to content

Commit

Permalink
feat: webhook updates (#191)
Browse files Browse the repository at this point in the history
Co-authored-by: Zack Pollard <[email protected]>
  • Loading branch information
danieldietzler and zackpollard authored Jan 31, 2025
1 parent 5fdb0e3 commit a20814f
Show file tree
Hide file tree
Showing 12 changed files with 564 additions and 12 deletions.
32 changes: 30 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,32 @@ export const getConfig = () => {
const githubStatusWebhookSlug = process.env.GITHUB_STATUS_SLUG;
const stripeWebhookSlug = process.env.STRIPE_PAYMENT_SLUG;
const commitSha = process.env.COMMIT_SHA;
const fourthwallUser = process.env.FOURTHWALL_USER;
const fourthwallPassword = process.env.FOURTHWALL_PASSWORD;
const fourthwallWebhookSlug = process.env.FOURTHWALL_SLUG;

if (!clientId || !clientSecret || !databaseUri || !botToken || !zulipUsername || !zulipApiKey || !zulipDomain) {
console.log({ clientId, clientSecret, databaseUri, botToken, zulipUsername, zulipApiKey, zulipDomain });
if (
!clientId ||
!clientSecret ||
!databaseUri ||
!botToken ||
!zulipUsername ||
!zulipApiKey ||
!zulipDomain ||
!fourthwallUser ||
!fourthwallPassword
) {
console.log({
clientId,
clientSecret,
databaseUri,
botToken,
zulipUsername,
zulipApiKey,
zulipDomain,
fourthwallUser,
fourthwallPassword,
});
throw new Error('Missing required environment variables');
}

Expand All @@ -36,11 +59,16 @@ export const getConfig = () => {
githubWebhook: githubWebhookSlug,
githubStatusWebhook: githubStatusWebhookSlug,
stripeWebhook: stripeWebhookSlug,
fourthwallWebhook: fourthwallWebhookSlug,
},
zulip: {
username: zulipUsername,
apiKey: zulipApiKey,
realm: zulipDomain,
},
fourthwall: {
user: fourthwallUser,
password: fourthwallPassword,
},
};
};
9 changes: 9 additions & 0 deletions src/controllers/webhook.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Body, Controller, Injectable, Param, Post } from '@nestjs/common';
import { WebhookEvent } from '@octokit/webhooks-types';
import { GithubStatusComponent, GithubStatusIncident, StripeBase } from 'src/dtos/webhook.dto';
import { FourthwallOrderCreateWebhook, FourthwallOrderUpdateWebhook } from 'src/interfaces/fourthwall.interface';
import { WebhookService } from 'src/services/webhook.service';

@Injectable()
Expand All @@ -22,4 +23,12 @@ export class WebhookController {
async onStripePayment(@Body() dto: StripeBase, @Param('slug') slug: string) {
await this.service.onStripePayment(dto, slug);
}

@Post('fourthwall-order/:slug')
async onFourthwallOrder(
@Body() dto: FourthwallOrderCreateWebhook | FourthwallOrderUpdateWebhook,
@Param('slug') slug: string,
) {
await this.service.onFourthwallOrder(dto, slug);
}
}
30 changes: 27 additions & 3 deletions src/interfaces/database.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,44 @@ export type DiscordMessage = Selectable<DiscordMessagesTable>;
export type NewDiscordMessage = Insertable<DiscordMessagesTable>;
export type UpdateDiscordMessage = Updateable<DiscordMessagesTable> & { id: string };

export interface FourthwallOrdersTable {
id: string;
discount: number;
tax: number;
shipping: number;
subtotal: number;
total: number;
revenue: number;
profit: number;
username?: string;
message?: string;
status: string;
createdAt: Date;
testMode: boolean;
}

export type FourthwallOrder = Selectable<FourthwallOrdersTable>;
export type NewFourthwallOrder = Insertable<FourthwallOrdersTable>;
export type UpdateFourthwallOrder = Updateable<FourthwallOrdersTable> & { id: string };

export interface Database {
payment: PaymentTable;
sponsor: SponsorTable;
discord_links: DiscordLinksTable;
discord_messages: DiscordMessagesTable;
fourthwall_orders: FourthwallOrdersTable;
}

export type LicenseCountOptions = {
export type ReportOptions = {
day?: DateTime;
week?: DateTime;
month?: DateTime;
};

export interface IDatabaseRepository {
runMigrations(): Promise<void>;
createPayment(entitY: NewPayment): Promise<void>;
getTotalLicenseCount(options?: LicenseCountOptions): Promise<{ server: number; client: number }>;
createPayment(entity: NewPayment): Promise<void>;
getTotalLicenseCount(options?: ReportOptions): Promise<{ server: number; client: number }>;
getSponsorLicenses(githubUsername: string): Promise<License[]>;
getDiscordLinks(): Promise<DiscordLink[]>;
getDiscordLink(name: string): Promise<DiscordLink | undefined>;
Expand All @@ -95,4 +116,7 @@ export interface IDatabaseRepository {
addDiscordMessage(message: NewDiscordMessage): Promise<void>;
updateDiscordMessage(message: UpdateDiscordMessage): Promise<void>;
removeDiscordMessage(id: string): Promise<void>;
createFourthwallOrder(entity: NewFourthwallOrder): Promise<void>;
updateFourthwallOrder(entity: UpdateFourthwallOrder): Promise<void>;
getTotalFourthwallOrders(options?: ReportOptions): Promise<{ revenue: number; profit: number }>;
}
259 changes: 259 additions & 0 deletions src/interfaces/fourthwall.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
export const IFourthwallRepository = 'IFourthwallRepository';

type Price = { value: number; currency: string };

export interface FourthwallOrder {
type: string;
profit: Price;
id: string;
friendlyId: string;
cartId: string;
checkoutId: string;
giftId: any;
status: string;
refund: {
elements: [
{
type: string;
data: {
type: string;
amount: Price;
issuer: string;
reason: string;
};
createdAt: string;
principalName: any;
},
];
};
cancellation: FourthwallCancellation;
shopId: string;
email: string;
offers: [
{
offer: FourthwallOffer;
variant: FourthwallVariant;
variantId: string;
quantity: number;
price: Price;
},
];
offersCancelled: [
{
offer: FourthwallOffer;
variant: FourthwallVariant;
variantId: string;
quantity: number;
price: Price;
},
];
currentAmounts: {
offers: Price;
shipping: Price;
tax: Price;
discount: Price;
total: Price;
};
cancelledAmounts: {
offers: Price;
shipping: Price;
tax: Price;
discount: Price;
total: Price;
};
paidPaymentFee: any;
paidBySupporter: Price;
totalTax: {
total: Price;
totalRate: number;
elements: [{ amount: Price; rate: number; title: string; taxType: string }];
};
merchandiseTotal: Price;
donation: any;
discount: any;
creatorBudget: any;
billing: { address: Address };
shipping: {
address: Address;
method: string;
price: Price;
shipments: [
{
id: string;
items: [{ offerId: string; variantId: string }];
shippingRate: {
id: string;
shipmentId: string;
service: string;
description: string;
price: Price;
type: string;
};
},
];
};
replacement: any;
additionalFields: [{ name: string; value: string }];
createdAt: string;
updatedAt: string;
fulfillmentStatus: string;
message?: string;
salesChannel: { type: string };
totalPrice: Price;
}

export interface FourthwallCancellation {
cancellationType: string;
position: number;
issuer: string;
issuedAt: string;
principalName: any;
reason: string;
cancelledItems: any;
cancelledAmounts: any;
}

export interface FourthwallOffer {
type: string;
id: string;
shopId: string;
customizationId: string;
productId: string;
bespokeProductId: any;
membershipTierVariantId: any;
requirements: { allowedTiers: any };
name: string;
slug: string;
description: string;
variantTypes: [
{
type: string;
title: string;
options: [
{
name: string;
colorSwatch?: string;
price: any;
compareAtPrice: any;
weight: any;
id: string;
},
];
variesBy: {
price: boolean;
height: boolean;
imagery: boolean;
};
},
];
fulfillingService: string;
manufacturingService: string;
drop: any;
digitalItems: any[];
additionalSections: [{ type: string; title: string; bodyHtml: string }];
soundScanInfo: any;
visualHints: { customSkus: boolean };
metafields: any;
createdAt: string;
updatedAt: string;
state: { status: string; available: boolean };
variants: FourthwallVariant[];
}

export interface FourthwallVariant {
type: string;
id: string;
offerId: string;
shopId: string;
status: string;
name: string;
slug: string;
sku: string;
productVariantId: string;
price: Price;
compareAtPrice: any;
weight: { value: number; unit: string };
dimensions: { length: number; width: number; height: number; unit: string };
attributesList: [{ name: string; colorSwatch?: string; type: string }];
settings: { requiresShipping: boolean; taxable: boolean; isSoundScanProduct: boolean; donation: boolean };
images: string[];
position: number;
quantity: any;
metafields: any;
createdAt: string;
updatedAt: string;
unitPrice: Price;
attributesDescription: string;
colorAttribute: { name: string; colorSwatch: string; type: string };
sizeAttribute?: { name: string; type: string };
customAttribute: any;
colorOption: { name: string; colorSwatch: string; type: string };
customOption: any;
sizeOption?: { name: string; type: string };
attributes: { COLOR: string; SIZE?: string };
colorName: string;
size: string;
colorSwatch: string;
customVariationValue: string;
options: { requiresShiping: boolean; taxable: boolean; isSoundScanProduct: boolean; donation: boolean };
productId: any;
barcode: any;
}

interface Address {
firstName: string;
lastName: string;
address1: string;
address2: string;
city: string;
state: string;
country: string;
zip: string;
phone: string;
vatId: any;
}

export interface FourthwallOrderCreateWebhook {
testMode: boolean;
id: string;
webhookId: string;
shopId: string;
type: 'ORDER_PLACED';
apiVersion: string;
createdAt: string;
data: FourthwallOrderData;
}

interface FourthwallOrderData {
amounts: { discount: Price; donation: Price; shipping: Price; subtotal: Price; tax: Price; total: Price };
billing: { address: Address };
checkoutId: string;
createdAt: string;
email: string;
emailMarketingOptIn: boolean;
friendlyId: string;
id: string;
message?: string;
offers: FourthwallOffer[];
shipping: { address: Address };
shopId: string;
source: { type: string };
status: string;
updatedAt: string;
username?: string;
}

export interface FourthwallOrderUpdateWebhook {
testMode: boolean;
id: string;
webhookId: string;
shopId: string;
type: 'ORDER_UPDATED';
apiVersion: string;
createdAt: string;
data: FourthwallOrderData & { update: { type: string } };
}

export interface IFourthwallRepository {
getOrder({ id, user, password }: { id: string; user: string; password: string }): Promise<FourthwallOrder>;
}
Loading

0 comments on commit a20814f

Please sign in to comment.