Spaces:
Paused
Paused
Download src/controllers/threads.js from Abhises/backlinks-api: direct link, hf CLI and curl.
- Browser
- Download file 8.38 kB
-
https://huggingface.co/spaces/Abhises/backlinks-api/resolve/main/src/controllers/threads.js
- Command line
-
hf download hf://spaces/Abhises/backlinks-api/src/controllers/threads.js
-
curl -L -o threads.js https://huggingface.co/spaces/Abhises/backlinks-api/resolve/main/src/controllers/threads.js
8.38 kB
| const prisma = require('../lib/prisma'); | |
| const wsManager = require('../lib/ws'); | |
| // Helper: get user's workspace | |
| async function getUserWorkspace(userId) { | |
| const member = await prisma.teamMember.findFirst({ | |
| where: { userId }, | |
| include: { workspace: true }, | |
| }); | |
| return member; | |
| } | |
| const createThread = async (req, res) => { | |
| const { receiverWorkspaceId } = req.body; | |
| if (!receiverWorkspaceId) { | |
| return res.status(400).json({ error: 'Receiver workspace ID required' }); | |
| } | |
| try { | |
| const member = await getUserWorkspace(req.user.userId); | |
| if (!member) return res.status(404).json({ error: 'You have no workspace' }); | |
| if (member.workspaceId === receiverWorkspaceId) { | |
| return res.status(400).json({ error: 'Cannot send request to your own workspace' }); | |
| } | |
| // Check for existing thread | |
| const existing = await prisma.exchangeThread.findFirst({ | |
| where: { | |
| OR: [ | |
| { giverWorkspaceId: member.workspaceId, receiverWorkspaceId }, | |
| { giverWorkspaceId: receiverWorkspaceId, receiverWorkspaceId: member.workspaceId }, | |
| ], | |
| }, | |
| }); | |
| if (existing) return res.status(409).json({ error: 'Thread already exists between these workspaces' }); | |
| const thread = await prisma.exchangeThread.create({ | |
| data: { | |
| giverWorkspaceId: member.workspaceId, | |
| receiverWorkspaceId, | |
| stage: 'NEW', | |
| status: 'PENDING', | |
| giverAccepted: true, | |
| }, | |
| include: { | |
| giverWorkspace: true, | |
| receiverWorkspace: true, | |
| }, | |
| }); | |
| wsManager.sendNotification(receiverWorkspaceId, { | |
| type: 'new_connection', | |
| threadId: thread.id, | |
| senderWorkspaceName: thread.giverWorkspace.websiteName, | |
| senderWorkspaceDomain: thread.giverWorkspace.domain, | |
| }); | |
| res.status(201).json({ thread }); | |
| } catch (err) { | |
| console.error(err); | |
| res.status(500).json({ error: 'Server error' }); | |
| } | |
| }; | |
| const getThreads = async (req, res) => { | |
| const { filter } = req.query; // all | new | in | out | |
| try { | |
| const member = await getUserWorkspace(req.user.userId); | |
| if (!member) return res.status(404).json({ error: 'No workspace found' }); | |
| const wsId = member.workspaceId; | |
| let where = { | |
| OR: [{ giverWorkspaceId: wsId }, { receiverWorkspaceId: wsId }], | |
| status: { not: 'REJECTED' }, | |
| }; | |
| if (filter === 'new') where.stage = 'NEW'; | |
| else if (filter === 'in') { | |
| where = { receiverWorkspaceId: wsId, status: { not: 'REJECTED' } }; | |
| } | |
| else if (filter === 'out') { | |
| where = { giverWorkspaceId: wsId, status: { not: 'REJECTED' } }; | |
| } | |
| else if (filter === 'rejected') { | |
| where = { rejectedByWorkspaceId: wsId, status: 'REJECTED' }; | |
| } | |
| const threads = await prisma.exchangeThread.findMany({ | |
| where, | |
| include: { | |
| giverWorkspace: { | |
| select: { | |
| id: true, domain: true, websiteName: true, niche: true, country: true, description: true, createdAt: true, | |
| teamMembers: { where: { role: 'OWNER' }, select: { user: { select: { name: true } } } } | |
| } | |
| }, | |
| receiverWorkspace: { | |
| select: { | |
| id: true, domain: true, websiteName: true, niche: true, country: true, description: true, createdAt: true, | |
| teamMembers: { where: { role: 'OWNER' }, select: { user: { select: { name: true } } } } | |
| } | |
| }, | |
| messages: { orderBy: { timestamp: 'desc' }, take: 1 }, | |
| linkPlacement: true, | |
| }, | |
| orderBy: { updatedAt: 'desc' }, | |
| }); | |
| let settings = await prisma.systemSettings.findUnique({ where: { id: 'singleton' } }); | |
| const rejectLimit = settings ? settings.rejectLimit : 5; | |
| res.json({ threads, workspaceId: wsId, rejectLimit }); | |
| } catch (err) { | |
| console.error(err); | |
| res.status(500).json({ error: 'Server error' }); | |
| } | |
| }; | |
| const getThreadById = async (req, res) => { | |
| try { | |
| const member = await getUserWorkspace(req.user.userId); | |
| if (!member) return res.status(404).json({ error: 'No workspace found' }); | |
| const thread = await prisma.exchangeThread.findUnique({ | |
| where: { id: req.params.id }, | |
| include: { | |
| giverWorkspace: { | |
| include: { teamMembers: { where: { role: 'OWNER' }, select: { user: { select: { name: true } } } } } | |
| }, | |
| receiverWorkspace: { | |
| include: { teamMembers: { where: { role: 'OWNER' }, select: { user: { select: { name: true } } } } } | |
| }, | |
| messages: { | |
| orderBy: { timestamp: 'asc' }, | |
| include: { sender: { select: { id: true, name: true, email: true } } }, | |
| }, | |
| linkPlacement: true, | |
| }, | |
| }); | |
| if (!thread) return res.status(404).json({ error: 'Thread not found' }); | |
| // Verify access | |
| if (thread.giverWorkspaceId !== member.workspaceId && thread.receiverWorkspaceId !== member.workspaceId) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| res.json({ thread, workspaceId: member.workspaceId }); | |
| } catch (err) { | |
| console.error(err); | |
| res.status(500).json({ error: 'Server error' }); | |
| } | |
| }; | |
| const updateThreadStatus = async (req, res) => { | |
| const { status } = req.body; // ACCEPTED | REJECTED | |
| if (!['ACCEPTED', 'REJECTED'].includes(status)) { | |
| return res.status(400).json({ error: 'Status must be ACCEPTED or REJECTED' }); | |
| } | |
| try { | |
| const member = await getUserWorkspace(req.user.userId); | |
| if (!member) return res.status(404).json({ error: 'No workspace found' }); | |
| const thread = await prisma.exchangeThread.findUnique({ where: { id: req.params.id } }); | |
| if (!thread) return res.status(404).json({ error: 'Thread not found' }); | |
| const isGiver = thread.giverWorkspaceId === member.workspaceId; | |
| const isReceiver = thread.receiverWorkspaceId === member.workspaceId; | |
| if (!isGiver && !isReceiver) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| let updateData = {}; | |
| let newStatus = thread.status; | |
| let newStage = thread.stage; | |
| let giverAccepted = thread.giverAccepted; | |
| let receiverAccepted = thread.receiverAccepted; | |
| if (status === 'REJECTED') { | |
| let settings = await prisma.systemSettings.findUnique({ where: { id: 'singleton' } }); | |
| const rejectLimit = settings ? settings.rejectLimit : 5; | |
| const rejectedCount = await prisma.exchangeThread.count({ | |
| where: { rejectedByWorkspaceId: member.workspaceId, status: 'REJECTED' } | |
| }); | |
| if (rejectedCount >= rejectLimit) { | |
| return res.status(403).json({ error: `Cannot reject more than ${rejectLimit} requests` }); | |
| } | |
| newStatus = 'REJECTED'; | |
| newStage = 'NEW'; | |
| updateData = { status: newStatus, stage: newStage, rejectedByWorkspaceId: member.workspaceId }; | |
| } else if (status === 'ACCEPTED') { | |
| if (isGiver) giverAccepted = true; | |
| if (isReceiver) receiverAccepted = true; | |
| updateData = { giverAccepted, receiverAccepted }; | |
| if (giverAccepted && receiverAccepted) { | |
| newStatus = 'ACCEPTED'; | |
| newStage = 'CHAT'; | |
| updateData.status = newStatus; | |
| updateData.stage = newStage; | |
| } | |
| } | |
| const updated = await prisma.exchangeThread.update({ | |
| where: { id: req.params.id }, | |
| data: updateData, | |
| include: { | |
| giverWorkspace: true, | |
| receiverWorkspace: true, | |
| }, | |
| }); | |
| // Determine who to notify | |
| const otherId = isGiver ? thread.receiverWorkspaceId : thread.giverWorkspaceId; | |
| const selfWorkspace = isGiver ? updated.giverWorkspace : updated.receiverWorkspace; | |
| if (newStatus === 'ACCEPTED' && newStage === 'CHAT') { | |
| wsManager.sendNotification(otherId, { | |
| type: 'connection_accepted', | |
| threadId: updated.id, | |
| receiverWorkspaceName: selfWorkspace.websiteName, | |
| receiverWorkspaceDomain: selfWorkspace.domain, | |
| }); | |
| } else if (newStatus === 'REJECTED') { | |
| wsManager.sendNotification(otherId, { | |
| type: 'connection_rejected', | |
| threadId: updated.id, | |
| receiverWorkspaceName: selfWorkspace.websiteName, | |
| receiverWorkspaceDomain: selfWorkspace.domain, | |
| }); | |
| } | |
| res.json({ thread: updated }); | |
| } catch (err) { | |
| console.error(err); | |
| res.status(500).json({ error: 'Server error' }); | |
| } | |
| }; | |
| module.exports = { | |
| createThread, | |
| getThreads, | |
| getThreadById, | |
| updateThreadStatus, | |
| }; | |