mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Add payment to cron endpoint for recurring subscribers, set cron to nce a day, set expiration to 31 days
This commit is contained in:
parent
e69d974ad7
commit
b9c2d04ed4
@ -1,102 +1,106 @@
|
|||||||
import prisma from "../prisma";
|
import prisma from "../prisma";
|
||||||
|
import { webln } from "@getalby/sdk";
|
||||||
|
import { LightningAddress } from "@getalby/sdk";
|
||||||
|
|
||||||
|
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
|
||||||
|
|
||||||
export const getAllUsers = async () => {
|
export const getAllUsers = async () => {
|
||||||
return await prisma.user.findMany({
|
return await prisma.user.findMany({
|
||||||
|
include: {
|
||||||
|
role: true, // Include related role
|
||||||
|
purchased: {
|
||||||
include: {
|
include: {
|
||||||
role: true, // Include related role
|
course: true, // Include course details in purchases
|
||||||
purchased: {
|
resource: true, // Include resource details in purchases
|
||||||
include: {
|
|
||||||
course: true, // Include course details in purchases
|
|
||||||
resource: true, // Include resource details in purchases
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserById = async (id) => {
|
export const getUserById = async (id) => {
|
||||||
return await prisma.user.findUnique({
|
return await prisma.user.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
include: {
|
||||||
|
role: true, // Include related role
|
||||||
|
purchased: {
|
||||||
include: {
|
include: {
|
||||||
role: true, // Include related role
|
course: true, // Include course details in purchases
|
||||||
purchased: {
|
resource: true, // Include resource details in purchases
|
||||||
include: {
|
|
||||||
course: true, // Include course details in purchases
|
|
||||||
resource: true, // Include resource details in purchases
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserByPubkey = async (pubkey) => {
|
export const getUserByPubkey = async (pubkey) => {
|
||||||
return await prisma.user.findUnique({
|
return await prisma.user.findUnique({
|
||||||
where: { pubkey },
|
where: { pubkey },
|
||||||
|
include: {
|
||||||
|
role: true, // Include related role
|
||||||
|
purchased: {
|
||||||
include: {
|
include: {
|
||||||
role: true, // Include related role
|
course: true, // Include course details in purchases
|
||||||
purchased: {
|
resource: true, // Include resource details in purchases
|
||||||
include: {
|
|
||||||
course: true, // Include course details in purchases
|
|
||||||
resource: true, // Include resource details in purchases
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addResourcePurchaseToUser = async (userId, purchaseData) => {
|
export const addResourcePurchaseToUser = async (userId, purchaseData) => {
|
||||||
return await prisma.user.update({
|
return await prisma.user.update({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
data: {
|
data: {
|
||||||
purchased: {
|
purchased: {
|
||||||
create: {
|
create: {
|
||||||
resourceId: purchaseData.resourceId,
|
resourceId: purchaseData.resourceId,
|
||||||
amountPaid: purchaseData.amountPaid,
|
amountPaid: purchaseData.amountPaid,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
},
|
||||||
purchased: {
|
include: {
|
||||||
include: {
|
purchased: {
|
||||||
resource: true,
|
include: {
|
||||||
},
|
resource: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const addCoursePurchaseToUser = async (userId, purchaseData) => {
|
export const addCoursePurchaseToUser = async (userId, purchaseData) => {
|
||||||
return await prisma.user.update({
|
return await prisma.user.update({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
data: {
|
data: {
|
||||||
purchased: {
|
purchased: {
|
||||||
create: {
|
create: {
|
||||||
courseId: purchaseData.courseId,
|
courseId: purchaseData.courseId,
|
||||||
amountPaid: purchaseData.amountPaid,
|
amountPaid: purchaseData.amountPaid,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const createUser = async (data) => {
|
export const createUser = async (data) => {
|
||||||
return await prisma.user.create({
|
return await prisma.user.create({
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUser = async (id, data) => {
|
export const updateUser = async (id, data) => {
|
||||||
console.log("user modelllll", id, data)
|
console.log("user modelllll", id, data)
|
||||||
return await prisma.user.update({
|
return await prisma.user.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteUser = async (id) => {
|
export const deleteUser = async (id) => {
|
||||||
return await prisma.user.delete({
|
return await prisma.user.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUserSubscription = async (userId, isSubscribed, nwc) => {
|
export const updateUserSubscription = async (userId, isSubscribed, nwc) => {
|
||||||
@ -129,24 +133,27 @@ export const updateUserSubscription = async (userId, isSubscribed, nwc) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkAndUpdateExpiredSubscriptions = async () => {
|
export const findExpiredSubscriptions = async () => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneHourAgo = new Date(now.getTime() - 1 * 60 * 60 * 1000);
|
const thirtyOneDaysAgo = new Date(now.getTime() - 31 * 24 * 60 * 60 * 1000);
|
||||||
const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000);
|
|
||||||
|
|
||||||
const expiredSubscriptions = await prisma.role.findMany({
|
return await prisma.role.findMany({
|
||||||
where: {
|
where: {
|
||||||
subscribed: true,
|
subscribed: true,
|
||||||
lastPaymentAt: {
|
lastPaymentAt: {
|
||||||
lt: fiveMinutesAgo
|
lt: thirtyOneDaysAgo
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
userId: true
|
userId: true,
|
||||||
|
nwc: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const updatePromises = expiredSubscriptions.map(({ userId }) =>
|
export const expireUserSubscriptions = async (userIds) => {
|
||||||
|
const now = new Date();
|
||||||
|
const updatePromises = userIds.map((userId) =>
|
||||||
prisma.role.update({
|
prisma.role.update({
|
||||||
where: { userId },
|
where: { userId },
|
||||||
data: {
|
data: {
|
||||||
@ -160,6 +167,5 @@ export const checkAndUpdateExpiredSubscriptions = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await prisma.$transaction(updatePromises);
|
await prisma.$transaction(updatePromises);
|
||||||
|
return userIds.length;
|
||||||
return expiredSubscriptions.length;
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { checkAndUpdateExpiredSubscriptions } from "@/db/models/userModels";
|
import { findExpiredSubscriptions, updateUserSubscription, expireUserSubscriptions } from "@/db/models/userModels";
|
||||||
|
import { webln } from "@getalby/sdk";
|
||||||
|
import { LightningAddress } from '@getalby/lightning-tools';
|
||||||
|
|
||||||
|
const lnAddress = process.env.LIGHTNING_ADDRESS;
|
||||||
|
const amount = 25; // Set the subscription amount in satoshis
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
if (req.headers.authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
if (req.headers.authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
||||||
@ -7,8 +12,41 @@ export default async function handler(req, res) {
|
|||||||
|
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
try {
|
try {
|
||||||
const updatedCount = await checkAndUpdateExpiredSubscriptions();
|
const expiredSubscriptions = await findExpiredSubscriptions();
|
||||||
res.status(200).json({ message: `Cron job completed successfully. Updated ${updatedCount} subscriptions.` });
|
const stillExpired = [];
|
||||||
|
|
||||||
|
for (const { userId, nwc } of expiredSubscriptions) {
|
||||||
|
if (nwc) {
|
||||||
|
try {
|
||||||
|
const nwcProvider = new webln.NostrWebLNProvider({
|
||||||
|
nostrWalletConnectUrl: nwc
|
||||||
|
});
|
||||||
|
await nwcProvider.enable();
|
||||||
|
|
||||||
|
const ln = new LightningAddress(lnAddress);
|
||||||
|
await ln.fetch();
|
||||||
|
const newInvoice = await ln.requestInvoice({ satoshi: amount });
|
||||||
|
|
||||||
|
const response = await nwcProvider.sendPayment(newInvoice?.paymentRequest);
|
||||||
|
|
||||||
|
if (response && response?.preimage) {
|
||||||
|
await updateUserSubscription(userId, true, nwc);
|
||||||
|
continue; // Skip adding to stillExpired list
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Payment failed for user ${userId}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stillExpired.push(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const expiredCount = await expireUserSubscriptions(stillExpired);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
message: `Cron job completed successfully.
|
||||||
|
Processed ${expiredSubscriptions.length} subscriptions.
|
||||||
|
Expired ${expiredCount} subscriptions.`
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Cron job error:', error);
|
console.error('Cron job error:', error);
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
|
@ -22,24 +22,19 @@ const Profile = () => {
|
|||||||
const [subscribedUntil, setSubscribedUntil] = useState(null);
|
const [subscribedUntil, setSubscribedUntil] = useState(null);
|
||||||
const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null);
|
const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null);
|
||||||
|
|
||||||
const { data: session, status, update } = useSession();
|
const { data: session } = useSession();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { ndk } = useNDKContext();
|
const { ndk } = useNDKContext();
|
||||||
const menu = useRef(null);
|
const menu = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Refetch the session when the component mounts
|
|
||||||
update();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session && session.user) {
|
if (session && session.user) {
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
if (session.user.role) {
|
if (session.user.role) {
|
||||||
setSubscribed(session.user.role.subscribed);
|
setSubscribed(session.user.role.subscribed);
|
||||||
const subscribedAt = new Date(session.user.role.lastPaymentAt);
|
const subscribedAt = new Date(session.user.role.lastPaymentAt);
|
||||||
// The user is subscribed until the date in subscribedAt + 30 days
|
// The user is subscribed until the date in subscribedAt + 31 days
|
||||||
const subscribedUntil = new Date(subscribedAt.getTime() + 30 * 24 * 60 * 60 * 1000);
|
const subscribedUntil = new Date(subscribedAt.getTime() + 31 * 24 * 60 * 60 * 1000);
|
||||||
setSubscribedUntil(subscribedUntil);
|
setSubscribedUntil(subscribedUntil);
|
||||||
if (session.user.role.subscriptionExpiredAt) {
|
if (session.user.role.subscriptionExpiredAt) {
|
||||||
const expiredAt = new Date(session.user.role.subscriptionExpiredAt)
|
const expiredAt = new Date(session.user.role.subscriptionExpiredAt)
|
||||||
|
@ -7,7 +7,7 @@ export const findKind0Fields = async (kind0) => {
|
|||||||
|
|
||||||
const findTruthyPropertyValue = (object, properties) => {
|
const findTruthyPropertyValue = (object, properties) => {
|
||||||
for (const property of properties) {
|
for (const property of properties) {
|
||||||
if (object[property]) {
|
if (object?.[property]) {
|
||||||
return object[property];
|
return object[property];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"crons": [
|
"crons": [
|
||||||
{
|
{
|
||||||
"path": "/api/users/subscription/cron",
|
"path": "/api/users/subscription/cron",
|
||||||
"schedule": "0 * * * *"
|
"schedule": "0 0 * * *"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user