Abhises's picture
added cron job
58a6c46
Raw History Blame Contribute Delete
5.97 kB
const prisma = require('../lib/prisma');
const wsManager = require('../lib/ws');
const VALID_LINK_TYPES = ['GUEST_POST', 'NICHE_EDIT', 'IMAGE', 'OTHER'];
const VALID_STATUSES = ['LIVE', 'REMOVED', 'DEPARTED'];
const createOrUpdateLink = async (req, res) => {
const { threadId, sourceUrl, targetUrl, anchorText, linkType } = req.body;
if (!sourceUrl || !targetUrl || !anchorText || !linkType) {
return res.status(400).json({ error: 'sourceUrl, targetUrl, anchorText, and linkType are required' });
}
if (!VALID_LINK_TYPES.includes(linkType)) {
return res.status(400).json({ error: `linkType must be one of: ${VALID_LINK_TYPES.join(', ')}` });
}
try {
const member = await prisma.teamMember.findFirst({
where: { userId: req.user.userId },
include: { workspace: true },
});
if (!member) return res.status(404).json({ error: 'No workspace found' });
let giverWorkspaceId = member.workspaceId;
let receiverWorkspaceId = null;
if (threadId) {
const thread = await prisma.exchangeThread.findUnique({ where: { id: threadId }, include: { linkPlacement: true } });
if (!thread) return res.status(404).json({ error: 'Thread not found' });
const isOriginalGiver = thread.giverWorkspaceId === member.workspaceId;
const isOriginalReceiver = thread.receiverWorkspaceId === member.workspaceId;
if (!isOriginalGiver && !isOriginalReceiver) {
return res.status(403).json({ error: 'Access denied' });
}
if (thread.linkPlacement && thread.linkPlacement.giverWorkspaceId !== member.workspaceId) {
return res.status(403).json({ error: 'Link already placed by the other party. You cannot edit it.' });
}
giverWorkspaceId = member.workspaceId;
receiverWorkspaceId = isOriginalGiver ? thread.receiverWorkspaceId : thread.giverWorkspaceId;
// Check giver domain ownership
const giverDomain = member.workspace.domain;
if (!sourceUrl.includes(giverDomain)) {
return res.status(400).json({ error: `Source URL must belong to your domain: ${giverDomain}` });
}
// If the original receiver is the one submitting, we must swap the roles on the Thread!
if (!isOriginalGiver && !thread.linkPlacement) {
await prisma.exchangeThread.update({
where: { id: threadId },
data: {
giverWorkspaceId: member.workspaceId,
receiverWorkspaceId: thread.giverWorkspaceId,
giverAccepted: thread.receiverAccepted,
receiverAccepted: thread.giverAccepted
}
});
}
}
// Upsert link placement
let link;
if (threadId) {
link = await prisma.linkPlacement.upsert({
where: { threadId },
update: { sourceUrl, targetUrl, anchorText, linkType },
create: {
threadId,
giverWorkspaceId,
receiverWorkspaceId,
sourceUrl,
targetUrl,
anchorText,
linkType,
status: 'LIVE',
},
});
// Advance thread stage to PLACED
await prisma.exchangeThread.update({
where: { id: threadId },
data: { stage: 'PLACED' },
});
} else {
link = await prisma.linkPlacement.create({
data: {
giverWorkspaceId,
receiverWorkspaceId: receiverWorkspaceId || giverWorkspaceId,
sourceUrl,
targetUrl,
anchorText,
linkType,
status: 'LIVE',
},
});
}
// Send notification to the receiver that the link was placed
if (receiverWorkspaceId) {
wsManager.sendNotification(receiverWorkspaceId, {
type: 'link_placed',
threadId: threadId || '',
body: `${member.workspace.domain} has added the backlink details. Check your Dashboard!`,
});
}
res.status(201).json({ link });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
};
const getLinks = async (req, res) => {
try {
const member = await prisma.teamMember.findFirst({
where: { userId: req.user.userId },
});
if (!member) return res.status(404).json({ error: 'No workspace found' });
const wsId = member.workspaceId;
const links = await prisma.linkPlacement.findMany({
where: {
OR: [{ giverWorkspaceId: wsId }, { receiverWorkspaceId: wsId }],
},
include: {
giverWorkspace: { select: { id: true, domain: true, websiteName: true } },
receiverWorkspace: { select: { id: true, domain: true, websiteName: true } },
thread: { select: { id: true, stage: true, status: true } },
},
orderBy: { datePlaced: 'desc' },
});
res.json({ links, workspaceId: wsId });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
};
const updateLinkStatus = async (req, res) => {
const { status } = req.body;
if (!VALID_STATUSES.includes(status)) {
return res.status(400).json({ error: `Status must be one of: ${VALID_STATUSES.join(', ')}` });
}
try {
const member = await prisma.teamMember.findFirst({
where: { userId: req.user.userId },
});
if (!member) return res.status(404).json({ error: 'No workspace found' });
const link = await prisma.linkPlacement.findUnique({ where: { id: req.params.id } });
if (!link) return res.status(404).json({ error: 'Link not found' });
if (link.giverWorkspaceId !== member.workspaceId && link.receiverWorkspaceId !== member.workspaceId) {
return res.status(403).json({ error: 'Access denied' });
}
const updated = await prisma.linkPlacement.update({
where: { id: req.params.id },
data: { status },
});
res.json({ link: updated });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Server error' });
}
};
module.exports = {
createOrUpdateLink,
getLinks,
updateLinkStatus,
};