Abhises commited on
Commit
7853dfb
·
1 Parent(s): cce469c

added backlinks

Browse files
prisma/schema.prisma CHANGED
@@ -34,6 +34,7 @@ model Workspace {
34
  receiverThreads ExchangeThread[] @relation("ReceiverWorkspace")
35
  giverLinkPlacements LinkPlacement[] @relation("GiverLinkPlacements")
36
  receiverLinkPlacements LinkPlacement[] @relation("ReceiverLinkPlacements")
 
37
  }
38
 
39
  model TeamMember {
@@ -100,6 +101,20 @@ model AdminNotification {
100
  createdAt DateTime @default(now())
101
  }
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  model SystemSettings {
104
  id String @id @default("singleton")
105
  cronExpression String @default("*/10 * * * *")
 
34
  receiverThreads ExchangeThread[] @relation("ReceiverWorkspace")
35
  giverLinkPlacements LinkPlacement[] @relation("GiverLinkPlacements")
36
  receiverLinkPlacements LinkPlacement[] @relation("ReceiverLinkPlacements")
37
+ notifications Notification[]
38
  }
39
 
40
  model TeamMember {
 
101
  createdAt DateTime @default(now())
102
  }
103
 
104
+ model Notification {
105
+ id String @id @default(uuid())
106
+ workspaceId String
107
+ type String
108
+ title String?
109
+ body String?
110
+ link String?
111
+ read Boolean @default(false)
112
+ createdAt DateTime @default(now())
113
+ payload String?
114
+
115
+ workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
116
+ }
117
+
118
  model SystemSettings {
119
  id String @id @default("singleton")
120
  cronExpression String @default("*/10 * * * *")
src/controllers/threads.js CHANGED
@@ -208,13 +208,7 @@ const updateThreadStatus = async (req, res) => {
208
  receiverWorkspaceName: selfWorkspace.websiteName,
209
  receiverWorkspaceDomain: selfWorkspace.domain,
210
  });
211
- // also notify self just in case
212
- wsManager.sendNotification(member.workspaceId, {
213
- type: 'connection_accepted',
214
- threadId: updated.id,
215
- receiverWorkspaceName: selfWorkspace.websiteName,
216
- receiverWorkspaceDomain: selfWorkspace.domain,
217
- });
218
  } else if (newStatus === 'REJECTED') {
219
  wsManager.sendNotification(otherId, {
220
  type: 'connection_rejected',
 
208
  receiverWorkspaceName: selfWorkspace.websiteName,
209
  receiverWorkspaceDomain: selfWorkspace.domain,
210
  });
211
+
 
 
 
 
 
 
212
  } else if (newStatus === 'REJECTED') {
213
  wsManager.sendNotification(otherId, {
214
  type: 'connection_rejected',
src/index.js CHANGED
@@ -7,6 +7,7 @@ const workspaceRoutes = require('./routes/workspaces');
7
  const threadRoutes = require('./routes/threads');
8
  const messageRoutes = require('./routes/messages');
9
  const linkRoutes = require('./routes/links');
 
10
 
11
  const app = express();
12
 
@@ -63,6 +64,7 @@ app.use('/api/workspaces', workspaceRoutes);
63
  app.use('/api/threads', threadRoutes);
64
  app.use('/api/messages', messageRoutes);
65
  app.use('/api/links', linkRoutes);
 
66
 
67
  const adminRoutes = require('./routes/admin');
68
  app.use('/api/admin', adminRoutes);
 
7
  const threadRoutes = require('./routes/threads');
8
  const messageRoutes = require('./routes/messages');
9
  const linkRoutes = require('./routes/links');
10
+ const notificationRoutes = require('./routes/notifications');
11
 
12
  const app = express();
13
 
 
64
  app.use('/api/threads', threadRoutes);
65
  app.use('/api/messages', messageRoutes);
66
  app.use('/api/links', linkRoutes);
67
+ app.use('/api/notifications', notificationRoutes);
68
 
69
  const adminRoutes = require('./routes/admin');
70
  app.use('/api/admin', adminRoutes);
src/lib/ws.js CHANGED
@@ -1,4 +1,5 @@
1
  const { Server } = require('socket.io');
 
2
 
3
  class SocketManager {
4
  constructor() {
@@ -57,10 +58,21 @@ class SocketManager {
57
  }
58
  }
59
 
60
- sendNotification(workspaceId, payload) {
61
  if (this.io) {
62
  this.io.to(`workspace:${workspaceId}`).emit('notification', payload);
63
  }
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
 
66
  broadcastGlobalNotification(payload) {
 
1
  const { Server } = require('socket.io');
2
+ const prisma = require('./prisma');
3
 
4
  class SocketManager {
5
  constructor() {
 
58
  }
59
  }
60
 
61
+ async sendNotification(workspaceId, payload) {
62
  if (this.io) {
63
  this.io.to(`workspace:${workspaceId}`).emit('notification', payload);
64
  }
65
+ try {
66
+ await prisma.notification.create({
67
+ data: {
68
+ workspaceId,
69
+ type: payload.type,
70
+ payload: JSON.stringify(payload),
71
+ }
72
+ });
73
+ } catch (err) {
74
+ console.error('Failed to persist notification:', err);
75
+ }
76
  }
77
 
78
  broadcastGlobalNotification(payload) {
src/routes/notifications.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const authMiddleware = require('../middleware/auth');
3
+ const prisma = require('../lib/prisma');
4
+ const router = express.Router();
5
+
6
+ router.get('/', authMiddleware, async (req, res) => {
7
+ try {
8
+ const member = await prisma.teamMember.findFirst({
9
+ where: { userId: req.user.userId },
10
+ });
11
+ if (!member) return res.status(404).json({ error: 'No workspace found' });
12
+
13
+ const notifications = await prisma.notification.findMany({
14
+ where: { workspaceId: member.workspaceId },
15
+ orderBy: { createdAt: 'desc' },
16
+ take: 50
17
+ });
18
+
19
+ res.json({ notifications });
20
+ } catch (err) {
21
+ console.error(err);
22
+ res.status(500).json({ error: 'Server error' });
23
+ }
24
+ });
25
+
26
+ router.post('/mark-read', authMiddleware, async (req, res) => {
27
+ try {
28
+ const member = await prisma.teamMember.findFirst({
29
+ where: { userId: req.user.userId },
30
+ });
31
+ if (!member) return res.status(404).json({ error: 'No workspace found' });
32
+
33
+ await prisma.notification.updateMany({
34
+ where: { workspaceId: member.workspaceId, read: false },
35
+ data: { read: true }
36
+ });
37
+
38
+ res.json({ success: true });
39
+ } catch (err) {
40
+ console.error(err);
41
+ res.status(500).json({ error: 'Server error' });
42
+ }
43
+ });
44
+
45
+ module.exports = router;