Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions apps/web/app/api/user/brands/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,46 @@ export const POST = withSession(async ({ req, session }) => {
{ status: 500 },
);
}
} else if (advertiserId === "6") { // eBay
try {
const { ebayClientId, ebayClientSecret } = relationship;

if (!ebayClientId || !ebayClientSecret) {
return NextResponse.json(
{ error: "Missing eBay credentials." },
{ status: 400 }
);
}

// Example eBay API integration
const ebayUrl = "https://api.ebay.com/affiliate/links";
const headers = {
Authorization: `Bearer ${ebayClientSecret}`,
"Content-Type": "application/json",
};

const response = await fetch(ebayUrl, {
method: "GET",
headers,
});

if (!response.ok) {
throw new Error("Failed to fetch data from eBay");
}

const data = await response.json();

// Process eBay data as needed
// For example, create or update brands based on eBay data

return NextResponse.json({ message: "eBay integration successful." });
} catch (error) {
console.error("Error processing eBay advertiser:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 },
);
}
} else if (advertiserId === "2") {
const clientId = relationship.clientId;
const encryptedClientSecret = relationship.encryptedClientSecret;
Expand Down
5 changes: 4 additions & 1 deletion apps/web/app/api/user/networks/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { encrypt, withSession } from "@/lib/auth";
import prisma from "@/lib/prisma";
import { NextResponse } from "next/server";
import { NextApiRequest, NextApiResponse } from 'next';

// GET /api/user/userAdvertiserRelationships – get all user-advertiser relationships for a specific user
export const GET = withSession(async ({ session }) => {
Expand Down Expand Up @@ -32,7 +33,7 @@ export const GET = withSession(async ({ session }) => {
});

// POST /api/user/networks – create a new UserAdvertiserRelationship
export const POST = withSession(async ({ req, session }) => {
export const POST = withSession(async (req: NextApiRequest, res: NextApiResponse) => {
const {
advertiserId,
username,
Expand Down Expand Up @@ -122,4 +123,6 @@ export const PUT = withSession(async ({ req }) => {
});

return NextResponse.json({ userAdvertiserRelationship });
} else if (advertiserId === "6") { // eBay
// Existing eBay integration code
});
126 changes: 126 additions & 0 deletions apps/web/lib/api/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,70 @@ export async function processLink({
geo,
} = payload;

// Add eBay integration logic
const advertiserId = userBrandRelationship.advertiserId;
if (advertiserId === "6") { // eBay
const userAdvertiserRelation = userBrandRelationship.userAdvertiserRelation;
const ebayClientId = userAdvertiserRelation.ebayClientId || "";
const ebayClientSecret = decrypt(userAdvertiserRelation.encryptedEbayClientSecret || "");

if (!ebayClientId || !ebayClientSecret) {
return {
link: payload,
error: "Missing credentials for eBay affiliate program.",
code: "unprocessable_entity",
};
}

const ebayUrl = "https://api.ebay.com/affiliate/links";
const headers = {
Authorization: `Bearer ${ebayClientSecret}`,
"Content-Type": "application/json",
};

const data = {
websiteId: ebayClientId,
originalUrl: processedUrl,
// Add other necessary fields as per eBay's API documentation
};

try {
const response = await fetch(ebayUrl, {
method: "POST",
headers,
body: JSON.stringify(data),
});

if (response.ok) {
const responseData = await response.json();
const affiliateLink = responseData.affiliateLink || null;

return {
link: {
...payload,
aff_url: affiliateLink,
projectId: workspace?.id || null,
...(userId && { userId }),
},
error: null,
};
} else {
const errorData = await response.json();
return {
link: payload,
error: errorData.message || "Failed to generate eBay affiliate link.",
code: "unprocessable_entity",
};
}
} catch (error) {
console.error("Error generating eBay affiliate link:", error);
return {
link: payload,
error: "Internal server error while generating affiliate link.",
code: "internal_error",
};
}
}
const tagIds = combineTagIds(payload);

// url checks
Expand Down Expand Up @@ -562,7 +626,69 @@ export async function processLink({
userBrandRelationship.brandAdvertiserRelation.brandIdAtAdvertiser;
const userAdvertiserRelation =
userBrandRelationship.userAdvertiserRelation;
} else if (advertiserId === "6") { // eBay
const userAdvertiserRelation = userBrandRelationship.userAdvertiserRelation;
const ebayClientId = userAdvertiserRelation.ebayClientId || "";
const ebayClientSecret = decrypt(userAdvertiserRelation.encryptedEbayClientSecret || "");

if (!ebayClientId || !ebayClientSecret) {
return {
link: payload,
error: "Missing credentials for eBay affiliate program.",
code: "unprocessable_entity",
};
}

const ebayUrl = "https://api.ebay.com/affiliate/links";
const headers = {
Authorization: `Bearer ${ebayClientSecret}`,
"Content-Type": "application/json",
};

const data = {
websiteId: ebayClientId,
originalUrl: processedUrl,
// Add other necessary fields as per eBay's API documentation
};

try {
const response = await fetch(ebayUrl, {
method: "POST",
headers,
body: JSON.stringify(data),
});

if (response.ok) {
const responseData = await response.json();
const affiliateLink = responseData.affiliateLink; // Adjust based on actual response

return {
link: {
...payload,
aff_url: affiliateLink || null,
projectId: workspace?.id || null,
...(userId && {
userId,
}),
},
error: null,
};
} else {
const errorData = await response.json();
return {
link: payload,
error: errorData.message || "Failed to generate eBay affiliate link.",
code: "unprocessable_entity",
};
}
} catch (error) {
console.error("Error generating eBay affiliate link:", error);
return {
link: payload,
error: "Internal server error while generating affiliate link.",
code: "internal_error",
};
}
const clientId = userAdvertiserRelation.clientId || "";
const encryptedClientSecret =
userAdvertiserRelation.encryptedClientSecret || "";
Expand Down
2 changes: 2 additions & 0 deletions apps/web/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ model UserAdvertiserRelationship {
encryptedClientSecret String? @db.VarChar(1000)
accountId String?
websiteId String?
ebayClientId String? @db.VarChar(1000)
encryptedEbayClientSecret String? @db.VarChar(1000)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
advertiser Advertiser @relation(fields: [advertiserId], references: [id], onDelete: Cascade)
userBrandRelationships UserBrandRelationship[]
Expand Down
151 changes: 143 additions & 8 deletions apps/web/ui/modals/add-edit-network-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -619,13 +619,13 @@ function AddEditNetworkModal({
<div>
<div className="flex items-center justify-between">
<label
htmlFor={`url-${randomIdx}`}
htmlFor={`ebayClientId-${randomIdx}`}
className="block text-sm font-medium text-gray-700"
>
API Key
Client ID
</label>
<a
href="https://docs.affeasy.link/quickstart/affiliate-networks/planethowl"
href="https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-500"
Expand All @@ -635,14 +635,47 @@ function AddEditNetworkModal({
</div>
<div className="relative mt-1 flex rounded-md shadow-sm">
<input
name="apiKey"
id={`apiKey-${randomIdx}`}
placeholder="Enter your HOWL API Key"
value={partialApiKey ?? ""}
name="ebayClientId"
id={`ebayClientId-${randomIdx}`}
placeholder="Enter your eBay Client ID"
value={clientId ?? ""}
required
autoComplete="off"
onChange={(e) =>
handleInputChange("partialApiKey", e.target.value)
handleInputChange("ebayClientId", e.target.value)
}
className={`${"border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500"} block w-full rounded-md focus:outline-none sm:text-sm`}
aria-invalid="true"
/>
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label
htmlFor={`ebayClientSecret-${randomIdx}`}
className="block text-sm font-medium text-gray-700"
>
Client Secret
</label>
<a
href="https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-500"
>
<HelpCircle className="h-4 w-4" />
</a>
</div>
<div className="relative mt-1 flex rounded-md shadow-sm">
<input
name="clientSecret"
id={`clientSecret-${randomIdx}`}
placeholder="Enter your eBay Client Secret"
value={partialClientSecret ?? ""}
required
autoComplete="off"
onChange={(e) =>
handleInputChange("partialClientSecret", e.target.value)
}
className={`${"border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500"} block w-full rounded-md focus:outline-none sm:text-sm`}
aria-invalid="true"
Expand Down Expand Up @@ -683,6 +716,108 @@ function AddEditNetworkModal({
</div>
</div>
</>
) : advertiserId === "5" ? ( // Impact.com
<>
<div>
<div className="flex items-center justify-between">
<label
htmlFor={`ebayClientId-${randomIdx}`}
className="block text-sm font-medium text-gray-700"
>
Client ID
</label>
<a
href="https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-500"
>
<HelpCircle className="h-4 w-4" />
</a>
</div>
<div className="relative mt-1 flex rounded-md shadow-sm">
<input
name="ebayClientId"
id={`ebayClientId-${randomIdx}`}
placeholder="Enter your eBay Client ID"
value={clientId ?? ""}
required
autoComplete="off"
onChange={(e) =>
handleInputChange("ebayClientId", e.target.value)
}
className={`${"border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500"} block w-full rounded-md focus:outline-none sm:text-sm`}
aria-invalid="true"
/>
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label
htmlFor={`ebayClientSecret-${randomIdx}`}
className="block text-sm font-medium text-gray-700"
>
Client Secret
</label>
<a
href="https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-500"
>
<HelpCircle className="h-4 w-4" />
</a>
</div>
<div className="relative mt-1 flex rounded-md shadow-sm">
<input
name="clientSecret"
id={`clientSecret-${randomIdx}`}
placeholder="Enter your eBay Client Secret"
value={partialClientSecret ?? ""}
required
autoComplete="off"
onChange={(e) =>
handleInputChange("partialClientSecret", e.target.value)
}
className={`${"border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500"} block w-full rounded-md focus:outline-none sm:text-sm`}
aria-invalid="true"
/>
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label
htmlFor={`accountId-${randomIdx}`}
className="block text-sm font-medium text-gray-700"
>
Account ID
</label>
<a
href="https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-500"
>
<HelpCircle className="h-4 w-4" />
</a>
</div>
<div className="relative mt-1 flex rounded-md shadow-sm">
<input
name="accountId"
id={`accountId-${randomIdx}`}
placeholder="Enter your eBay Account ID"
value={accountId ?? ""}
required
autoComplete="off"
onChange={(e) =>
handleInputChange("accountId", e.target.value)
}
className={`${"border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500"} block w-full rounded-md focus:outline-none sm:text-sm`}
aria-invalid="true"
/>
</div>
</div>
</>
) : advertiserId === "5" ? ( // Impact.com
<>
<div>
Expand Down