mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-05 00:32:03 +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 { webln } from "@getalby/sdk";
|
||||
import { LightningAddress } from "@getalby/sdk";
|
||||
|
||||
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
|
||||
|
||||
export const getAllUsers = async () => {
|
||||
return await prisma.user.findMany({
|
||||
return await prisma.user.findMany({
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
},
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUserById = async (id) => {
|
||||
return await prisma.user.findUnique({
|
||||
where: { id },
|
||||
return await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
},
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUserByPubkey = async (pubkey) => {
|
||||
return await prisma.user.findUnique({
|
||||
where: { pubkey },
|
||||
return await prisma.user.findUnique({
|
||||
where: { pubkey },
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
role: true, // Include related role
|
||||
purchased: {
|
||||
include: {
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
},
|
||||
course: true, // Include course details in purchases
|
||||
resource: true, // Include resource details in purchases
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const addResourcePurchaseToUser = async (userId, purchaseData) => {
|
||||
return await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
purchased: {
|
||||
create: {
|
||||
resourceId: purchaseData.resourceId,
|
||||
amountPaid: purchaseData.amountPaid,
|
||||
},
|
||||
return await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
purchased: {
|
||||
create: {
|
||||
resourceId: purchaseData.resourceId,
|
||||
amountPaid: purchaseData.amountPaid,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
purchased: {
|
||||
include: {
|
||||
resource: true,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
purchased: {
|
||||
include: {
|
||||
resource: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const addCoursePurchaseToUser = async (userId, purchaseData) => {
|
||||
return await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
purchased: {
|
||||
create: {
|
||||
courseId: purchaseData.courseId,
|
||||
amountPaid: purchaseData.amountPaid,
|
||||
},
|
||||
return await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
purchased: {
|
||||
create: {
|
||||
courseId: purchaseData.courseId,
|
||||
amountPaid: purchaseData.amountPaid,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const createUser = async (data) => {
|
||||
return await prisma.user.create({
|
||||
data,
|
||||
});
|
||||
return await prisma.user.create({
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUser = async (id, data) => {
|
||||
console.log("user modelllll", id, data)
|
||||
return await prisma.user.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
console.log("user modelllll", id, data)
|
||||
return await prisma.user.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteUser = async (id) => {
|
||||
return await prisma.user.delete({
|
||||
where: { id },
|
||||
});
|
||||
return await prisma.user.delete({
|
||||
where: { id },
|
||||
});
|
||||
};
|
||||
|
||||
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 oneHourAgo = new Date(now.getTime() - 1 * 60 * 60 * 1000);
|
||||
const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000);
|
||||
const thirtyOneDaysAgo = new Date(now.getTime() - 31 * 24 * 60 * 60 * 1000);
|
||||
|
||||
const expiredSubscriptions = await prisma.role.findMany({
|
||||
where: {
|
||||
return await prisma.role.findMany({
|
||||
where: {
|
||||
subscribed: true,
|
||||
lastPaymentAt: {
|
||||
lt: fiveMinutesAgo
|
||||
lt: thirtyOneDaysAgo
|
||||
}
|
||||
},
|
||||
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({
|
||||
where: { userId },
|
||||
data: {
|
||||
@ -160,6 +167,5 @@ export const checkAndUpdateExpiredSubscriptions = async () => {
|
||||
);
|
||||
|
||||
await prisma.$transaction(updatePromises);
|
||||
|
||||
return expiredSubscriptions.length;
|
||||
return userIds.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) {
|
||||
if (req.headers.authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
||||
@ -7,8 +12,41 @@ export default async function handler(req, res) {
|
||||
|
||||
if (req.method === 'POST') {
|
||||
try {
|
||||
const updatedCount = await checkAndUpdateExpiredSubscriptions();
|
||||
res.status(200).json({ message: `Cron job completed successfully. Updated ${updatedCount} subscriptions.` });
|
||||
const expiredSubscriptions = await findExpiredSubscriptions();
|
||||
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) {
|
||||
console.error('Cron job error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
|
@ -22,24 +22,19 @@ const Profile = () => {
|
||||
const [subscribedUntil, setSubscribedUntil] = useState(null);
|
||||
const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null);
|
||||
|
||||
const { data: session, status, update } = useSession();
|
||||
const { data: session } = useSession();
|
||||
const { returnImageProxy } = useImageProxy();
|
||||
const { ndk } = useNDKContext();
|
||||
const menu = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Refetch the session when the component mounts
|
||||
update();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (session && session.user) {
|
||||
setUser(session.user);
|
||||
if (session.user.role) {
|
||||
setSubscribed(session.user.role.subscribed);
|
||||
const subscribedAt = new Date(session.user.role.lastPaymentAt);
|
||||
// The user is subscribed until the date in subscribedAt + 30 days
|
||||
const subscribedUntil = new Date(subscribedAt.getTime() + 30 * 24 * 60 * 60 * 1000);
|
||||
// The user is subscribed until the date in subscribedAt + 31 days
|
||||
const subscribedUntil = new Date(subscribedAt.getTime() + 31 * 24 * 60 * 60 * 1000);
|
||||
setSubscribedUntil(subscribedUntil);
|
||||
if (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) => {
|
||||
for (const property of properties) {
|
||||
if (object[property]) {
|
||||
if (object?.[property]) {
|
||||
return object[property];
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"crons": [
|
||||
{
|
||||
"path": "/api/users/subscription/cron",
|
||||
"schedule": "0 * * * *"
|
||||
"schedule": "0 0 * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user