zurri / src /controllers /subscriptionController.ts
nexusbert's picture
initial commit
b5e5eac
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' });
}
}
}