Download src/controllers/subscriptionController.ts from nexusbert/zurri: direct link, hf CLI and curl.
- Browser
- Download file 5.2 kB
-
https://huggingface.co/spaces/nexusbert/zurri/resolve/main/src/controllers/subscriptionController.ts
- Command line
-
hf download hf://spaces/nexusbert/zurri/src/controllers/subscriptionController.ts
-
curl -L -o subscriptionController.ts https://huggingface.co/spaces/nexusbert/zurri/resolve/main/src/controllers/subscriptionController.ts
5.2 kB
| import { Request, Response } from 'express'; | |
| import { AppDataSource } from '../config/database'; | |
| import { Agent, AgentStatus } from '../entities/Agent'; | |
| import { Subscription, SubscriptionStatus } from '../entities/Subscription'; | |
| import { User } from '../entities/User'; | |
| import crypto from 'crypto'; | |
| const agentRepository = AppDataSource.getRepository(Agent); | |
| const subscriptionRepository = AppDataSource.getRepository(Subscription); | |
| const userRepository = AppDataSource.getRepository(User); | |
| export class SubscriptionController { | |
| /** | |
| * Create subscription/purchase agent access | |
| */ | |
| async createSubscription(req: Request, res: Response) { | |
| try { | |
| const { agentId } = req.params; | |
| const userId = (req as any).user.id; | |
| // Get agent | |
| const agent = await agentRepository.findOne({ | |
| where: { id: agentId, status: AgentStatus.APPROVED }, | |
| }); | |
| if (!agent) { | |
| return res.status(404).json({ error: 'Agent not found or not approved' }); | |
| } | |
| // Check if user already has active subscription | |
| const existing = await subscriptionRepository.findOne({ | |
| where: { | |
| userId, | |
| agentId, | |
| status: SubscriptionStatus.ACTIVE, | |
| }, | |
| }); | |
| if (existing) { | |
| return res.status(400).json({ | |
| error: 'You already have an active subscription to this agent', | |
| }); | |
| } | |
| // Calculate expiry | |
| const expiresAt = agent.isSubscription | |
| ? new Date( | |
| Date.now() + (agent.subscriptionDuration || 30) * 24 * 60 * 60 * 1000 | |
| ) | |
| : new Date('2099-12-31'); // One-time purchase = lifetime (or very long) | |
| // Create subscription (payment verification happens via webhook) | |
| const subscription = subscriptionRepository.create({ | |
| userId, | |
| agentId, | |
| expiresAt, | |
| status: SubscriptionStatus.ACTIVE, | |
| isPaymentVerified: false, // Will be verified via webhook | |
| }); | |
| const savedSubscription = await subscriptionRepository.save(subscription); | |
| // Generate payment reference (for Paystack) | |
| const paymentReference = `sub_${savedSubscription.id}_${Date.now()}`; | |
| savedSubscription.paymentReference = paymentReference; | |
| await subscriptionRepository.save(savedSubscription); | |
| res.status(201).json({ | |
| subscription: savedSubscription, | |
| payment: { | |
| reference: paymentReference, | |
| amount: agent.price, | |
| currency: 'NGN', // Adjust based on your setup | |
| }, | |
| }); | |
| } catch (error) { | |
| console.error('Create subscription error:', error); | |
| res.status(500).json({ error: 'Failed to create subscription' }); | |
| } | |
| } | |
| /** | |
| * Get user's subscriptions | |
| */ | |
| async getMySubscriptions(req: Request, res: Response) { | |
| try { | |
| const userId = (req as any).user.id; | |
| const subscriptions = await subscriptionRepository.find({ | |
| where: { userId }, | |
| relations: ['agent'], | |
| order: { createdAt: 'DESC' }, | |
| }); | |
| res.json(subscriptions); | |
| } catch (error) { | |
| console.error('Get subscriptions error:', error); | |
| res.status(500).json({ error: 'Failed to get subscriptions' }); | |
| } | |
| } | |
| /** | |
| * Cancel subscription | |
| */ | |
| async cancelSubscription(req: Request, res: Response) { | |
| try { | |
| const { id } = req.params; | |
| const userId = (req as any).user.id; | |
| const subscription = await subscriptionRepository.findOne({ | |
| where: { id, userId }, | |
| }); | |
| if (!subscription) { | |
| return res.status(404).json({ error: 'Subscription not found' }); | |
| } | |
| subscription.status = SubscriptionStatus.CANCELLED; | |
| await subscriptionRepository.save(subscription); | |
| res.json({ message: 'Subscription cancelled', subscription }); | |
| } catch (error) { | |
| console.error('Cancel subscription error:', error); | |
| res.status(500).json({ error: 'Failed to cancel subscription' }); | |
| } | |
| } | |
| /** | |
| * Verify payment via Paystack webhook | |
| */ | |
| async verifyPayment(req: Request, res: Response) { | |
| try { | |
| const secret = process.env.PAYSTACK_SECRET; | |
| if (!secret) { | |
| throw new Error('Paystack secret not configured'); | |
| } | |
| const hash = crypto | |
| .createHmac('sha512', secret) | |
| .update(JSON.stringify(req.body)) | |
| .digest('hex'); | |
| if (hash !== req.headers['x-paystack-signature']) { | |
| return res.status(401).json({ error: 'Invalid signature' }); | |
| } | |
| const event = req.body; | |
| if (event.event === 'charge.success') { | |
| const { reference, metadata } = event.data; | |
| // Find subscription by payment reference | |
| const subscription = await subscriptionRepository.findOne({ | |
| where: { paymentReference: reference }, | |
| }); | |
| if (subscription) { | |
| subscription.isPaymentVerified = true; | |
| subscription.status = SubscriptionStatus.ACTIVE; | |
| await subscriptionRepository.save(subscription); | |
| } | |
| } | |
| res.json({ received: true }); | |
| } catch (error) { | |
| console.error('Payment verification error:', error); | |
| res.status(500).json({ error: 'Payment verification failed' }); | |
| } | |
| } | |
| } | |