shuttlepro-shared 1.3.18 → 1.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/index.js +0 -15
- package/index.js +0 -8
- package/middlewares/checkPermission/index.js +36 -23
- package/models/UserRole.js +119 -1
- package/models.js +1 -62
- package/package.json +2 -13
- package/common/repositories/chatMember.repository.js +0 -9
- package/common/repositories/customerProfile.repository.js +0 -147
- package/common/repositories/descriptionTemplates.repository.js +0 -229
- package/common/repositories/index.js +0 -32
- package/common/repositories/integration.repository.js +0 -210
- package/common/repositories/label.repository.js +0 -95
- package/common/repositories/notificationSettings.repository.js +0 -95
- package/common/repositories/role.repository.js +0 -333
- package/common/repositories/settings.repository.js +0 -32
- package/common/repositories/shipper.repository.js +0 -77
- package/common/repositories/socialMediaSetting.repository.js +0 -33
- package/common/repositories/user.repository.js +0 -150
- package/common/repositories/userPermission.repository.js +0 -228
- package/common/repositories/userRepository.js +0 -31
- package/common/repositories/userRole.repository.js +0 -235
- package/common/repositories/userRolePermission.repository.js +0 -59
- package/common/repositories/workspace.repository.js +0 -147
- package/config/bull.js +0 -78
- package/config/config.js +0 -14
- package/config/database.js +0 -4
- package/config/index.js +0 -13
- package/config/redis.js +0 -195
- package/config/socket.js +0 -172
- package/models/AgentActivity.js +0 -192
- package/models/Assignment.js +0 -23
- package/models/BusinessDistribution.js +0 -23
- package/models/Card.js +0 -144
- package/models/CardComments.js +0 -33
- package/models/ChatMember.js +0 -17
- package/models/Chatbot.js +0 -20
- package/models/Checkpoint.js +0 -50
- package/models/City.js +0 -17
- package/models/Column.js +0 -28
- package/models/Conversation.js +0 -87
- package/models/Customer.js +0 -37
- package/models/CustomerProfile.js +0 -27
- package/models/DefaultRolePermission.js +0 -34
- package/models/DescriptionTemplate.js +0 -22
- package/models/Integration.js +0 -51
- package/models/Label.js +0 -42
- package/models/Message.js +0 -47
- package/models/NewProduct.js +0 -71
- package/models/NotificationSettings.js +0 -130
- package/models/Order.js +0 -244
- package/models/OrderProduct.js +0 -37
- package/models/Profile.js +0 -127
- package/models/Report.js +0 -27
- package/models/Setting.js +0 -18
- package/models/Shipper.js +0 -62
- package/models/SocialMediaSetting.js +0 -28
- package/models/Status.js +0 -58
- package/models/StatusType.js +0 -10
- package/models/Step.js +0 -50
- package/models/Type.js +0 -25
- package/models/UserWorkflow.js +0 -46
- package/models/Workspace.js +0 -318
- package/utils/decorator-factory.js +0 -264
- package/utils/logger.js +0 -41
package/config/bull.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
const Queue = require("bull");
|
|
2
|
-
const config = require("./config");
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Create a new queue.
|
|
6
|
-
* @param {string} queueName - The name of the queue.
|
|
7
|
-
* @param {Object} [redisConfig=config.redis] - Redis configuration.
|
|
8
|
-
* @returns {Object} - A collection of queue-related functions.
|
|
9
|
-
*/
|
|
10
|
-
const createQueue = (queueName, redisConfig = config.redis) => {
|
|
11
|
-
const queue = new Queue(queueName, { redis: redisConfig });
|
|
12
|
-
|
|
13
|
-
// Attach event listeners for logging
|
|
14
|
-
queue.on("completed", (job) => console.log(`Job ${job.id} completed.`));
|
|
15
|
-
queue.on("failed", (job, err) => console.error(`Job ${job.id} failed:`, err));
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Add a job to the queue.
|
|
19
|
-
* @param {Object} data - Data to be processed by the job.
|
|
20
|
-
* @param {Object} [options] - Bull job options (e.g., delay, attempts).
|
|
21
|
-
* @returns {Promise<Job>} - The created job.
|
|
22
|
-
*/
|
|
23
|
-
const addJob = async (
|
|
24
|
-
data,
|
|
25
|
-
options = {
|
|
26
|
-
attempts: 3,
|
|
27
|
-
removeOnComplete: true,
|
|
28
|
-
}
|
|
29
|
-
) => {
|
|
30
|
-
return await queue.add(data, options);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Process jobs in the queue.
|
|
35
|
-
* @param {Function} processor - The function to process each job.
|
|
36
|
-
*/
|
|
37
|
-
const processJobs = (processor) => {
|
|
38
|
-
queue.process(processor);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Close the queue connection.
|
|
43
|
-
* @returns {Promise<void>}
|
|
44
|
-
*/
|
|
45
|
-
const closeConnection = async () => {
|
|
46
|
-
await queue.close();
|
|
47
|
-
console.log(`Queue "${queue.name}" connection closed.`);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Pause the queue.
|
|
52
|
-
* @returns {Promise<void>}
|
|
53
|
-
*/
|
|
54
|
-
const pauseQueue = async () => {
|
|
55
|
-
await queue.pause();
|
|
56
|
-
console.log(`Queue "${queue.name}" paused.`);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Resume the queue.
|
|
61
|
-
* @returns {Promise<void>}
|
|
62
|
-
*/
|
|
63
|
-
const resumeQueue = async () => {
|
|
64
|
-
await queue.resume();
|
|
65
|
-
console.log(`Queue "${queue.name}" resumed.`);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Return the functional interface
|
|
69
|
-
return {
|
|
70
|
-
addJob,
|
|
71
|
-
processJobs,
|
|
72
|
-
closeConnection,
|
|
73
|
-
pauseQueue,
|
|
74
|
-
resumeQueue,
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
module.exports = { createQueue };
|
package/config/config.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const ALLOWED_URLS = process.env.ALLOWED_ORIGIN.split(",");
|
|
2
|
-
const WEBHOOK_API_KEY = process.env.API_KEY || process.env.WEBHOOK_API_KEY;
|
|
3
|
-
const mode = process.env.MODE || "production";
|
|
4
|
-
|
|
5
|
-
const redis = {
|
|
6
|
-
url: process.env.REDIS_URI,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
WEBHOOK_API_KEY,
|
|
11
|
-
ALLOWED_URLS,
|
|
12
|
-
mode,
|
|
13
|
-
redis,
|
|
14
|
-
};
|
package/config/database.js
DELETED
package/config/index.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const bullConfig = require("./bull");
|
|
2
|
-
const redisConfig = require("./redis");
|
|
3
|
-
const config = require("./config");
|
|
4
|
-
const databaseConfig = require("./database");
|
|
5
|
-
const socketConfig = require("./socket");
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
bullConfig,
|
|
9
|
-
redisConfig,
|
|
10
|
-
config,
|
|
11
|
-
databaseConfig,
|
|
12
|
-
socketConfig,
|
|
13
|
-
};
|
package/config/redis.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
const { createClient } = require("redis");
|
|
2
|
-
require("dotenv").config();
|
|
3
|
-
|
|
4
|
-
const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379";
|
|
5
|
-
|
|
6
|
-
// ✅ Create main Redis client
|
|
7
|
-
const client = createClient({
|
|
8
|
-
url: REDIS_URL,
|
|
9
|
-
socket: { reconnectStrategy: (retries) => Math.min(retries * 50, 1000) }, // Exponential backoff
|
|
10
|
-
});
|
|
11
|
-
const publisher = client.duplicate();
|
|
12
|
-
const subscriber = client.duplicate();
|
|
13
|
-
|
|
14
|
-
// ✅ Redis Events
|
|
15
|
-
const handleEvents = (client, label = "Redis") => {
|
|
16
|
-
client.on("error", (err) => console.error(`❌ ${label} Error:`, err));
|
|
17
|
-
client.on("connect", () => console.log(`✅ ${label} Connected`));
|
|
18
|
-
client.on("ready", () => console.log(`🚀 ${label} Ready to use`));
|
|
19
|
-
client.on("end", () => console.log(`❗ ${label} Connection Closed`));
|
|
20
|
-
client.on("reconnecting", () => console.warn(`🔄 ${label} Reconnecting...`));
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
handleEvents(client, "Main Redis");
|
|
24
|
-
handleEvents(publisher, "Publisher Redis");
|
|
25
|
-
handleEvents(subscriber, "Subscriber Redis");
|
|
26
|
-
|
|
27
|
-
// ✅ Ensure Redis is connected once during app startup
|
|
28
|
-
const connectRedis = async () => {
|
|
29
|
-
try {
|
|
30
|
-
if (!client.isOpen) await client.connect();
|
|
31
|
-
if (!publisher.isOpen) await publisher.connect();
|
|
32
|
-
if (!subscriber.isOpen) await subscriber.connect();
|
|
33
|
-
|
|
34
|
-
// Set keyspace events only once
|
|
35
|
-
const config = await client.configGet("notify-keyspace-events");
|
|
36
|
-
if (!config["notify-keyspace-events"]?.includes("Ex")) {
|
|
37
|
-
await client.configSet("notify-keyspace-events", "Ex");
|
|
38
|
-
}
|
|
39
|
-
} catch (err) {
|
|
40
|
-
console.error("❌ Failed to connect to Redis:", err);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// ✅ Publish Data to a Channel
|
|
45
|
-
const publishToChannel = async (channel, message) => {
|
|
46
|
-
try {
|
|
47
|
-
await publisher.publish(channel, JSON.stringify(message));
|
|
48
|
-
} catch (err) {
|
|
49
|
-
console.error("❌ Error publishing message:", err);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// ✅ Subscribe & Listen for Messages
|
|
54
|
-
const subscribeToChannel = async (channel, callback, expiry = false) => {
|
|
55
|
-
try {
|
|
56
|
-
await subscriber.subscribe(channel, (message) => {
|
|
57
|
-
if (expiry) callback(message);
|
|
58
|
-
else callback(JSON.parse(message));
|
|
59
|
-
});
|
|
60
|
-
} catch (err) {
|
|
61
|
-
console.error("❌ Error subscribing to channel:", err);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// ✅ Set Data in Redis (Supports String & Hash)
|
|
66
|
-
const setRedisData = async (
|
|
67
|
-
key,
|
|
68
|
-
value,
|
|
69
|
-
field = null,
|
|
70
|
-
expiryInSeconds = 3600
|
|
71
|
-
) => {
|
|
72
|
-
try {
|
|
73
|
-
const stringifiedValue = JSON.stringify(value);
|
|
74
|
-
let result;
|
|
75
|
-
|
|
76
|
-
if (field) {
|
|
77
|
-
result = await client.hSet(key, field, stringifiedValue);
|
|
78
|
-
if (expiryInSeconds) {
|
|
79
|
-
await client.expire(key, expiryInSeconds);
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
result = expiryInSeconds
|
|
83
|
-
? await client.set(key, stringifiedValue, { EX: expiryInSeconds })
|
|
84
|
-
: await client.set(key, stringifiedValue);
|
|
85
|
-
}
|
|
86
|
-
return result;
|
|
87
|
-
} catch (err) {
|
|
88
|
-
console.error("❌ Error setting Redis data:", err);
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// ✅ Get Data from Redis (Supports String & Hash)
|
|
94
|
-
const getRedisData = async (key, field = null) => {
|
|
95
|
-
try {
|
|
96
|
-
const result = field
|
|
97
|
-
? await client.hGet(key, field)
|
|
98
|
-
: await client.get(key);
|
|
99
|
-
return result ? JSON.parse(result) : null;
|
|
100
|
-
} catch (err) {
|
|
101
|
-
console.error("❌ Error getting Redis data:", err);
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
/**
|
|
106
|
-
* ✅ Get Expiry Time from Redis
|
|
107
|
-
* @param {string} key - The Redis key
|
|
108
|
-
* @param {string|null} field - Optional field for Hash retrieval
|
|
109
|
-
*/
|
|
110
|
-
const getRedisDataTime = async (key) => {
|
|
111
|
-
try {
|
|
112
|
-
await connectRedis();
|
|
113
|
-
let result = await client.ttl(key);
|
|
114
|
-
return result ? JSON.parse(result) : null;
|
|
115
|
-
} catch (err) {
|
|
116
|
-
console.error("❌ Error getting Redis data:", err);
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// ✅ Delete Data from Redis (Supports String & Hash)
|
|
122
|
-
const deleteRedisData = async (key, field = null) => {
|
|
123
|
-
try {
|
|
124
|
-
return field ? await client.hDel(key, field) : await client.del(key);
|
|
125
|
-
} catch (err) {
|
|
126
|
-
console.error("❌ Error deleting Redis data:", err);
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// ✅ Redis Set Operations
|
|
132
|
-
const addDataToRedisSet = async (key, value) => {
|
|
133
|
-
try {
|
|
134
|
-
await client.sAdd(key, value);
|
|
135
|
-
return true;
|
|
136
|
-
} catch (err) {
|
|
137
|
-
console.error("❌ Error adding to Redis set:", err);
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const removeDataFromRedisSet = async (key, value) => {
|
|
143
|
-
try {
|
|
144
|
-
await client.sRem(key, value);
|
|
145
|
-
return true;
|
|
146
|
-
} catch (err) {
|
|
147
|
-
console.error("❌ Error removing from Redis set:", err);
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const isMemberOfRedisSet = async (key, value) => {
|
|
153
|
-
try {
|
|
154
|
-
return await client.sIsMember(key, value);
|
|
155
|
-
} catch (err) {
|
|
156
|
-
console.error("❌ Error checking membership in Redis set:", err);
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// ✅ Graceful Shutdown
|
|
162
|
-
const closeClients = async () => {
|
|
163
|
-
if (client.isOpen) await client.quit();
|
|
164
|
-
if (publisher.isOpen) await publisher.quit();
|
|
165
|
-
if (subscriber.isOpen) await subscriber.quit();
|
|
166
|
-
console.log("❗ Redis Clients Disconnected Gracefully");
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
// ✅ Ensure Redis disconnects properly on process exit
|
|
170
|
-
process.on("exit", closeClients);
|
|
171
|
-
process.on("SIGINT", async () => {
|
|
172
|
-
await closeClients();
|
|
173
|
-
process.exit();
|
|
174
|
-
});
|
|
175
|
-
process.on("SIGTERM", async () => {
|
|
176
|
-
await closeClients();
|
|
177
|
-
process.exit();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// ✅ Export Functions
|
|
181
|
-
module.exports = {
|
|
182
|
-
client,
|
|
183
|
-
publisher,
|
|
184
|
-
subscriber,
|
|
185
|
-
connectRedis,
|
|
186
|
-
setRedisData,
|
|
187
|
-
getRedisDataTime,
|
|
188
|
-
getRedisData,
|
|
189
|
-
deleteRedisData,
|
|
190
|
-
publishToChannel,
|
|
191
|
-
subscribeToChannel,
|
|
192
|
-
addDataToRedisSet,
|
|
193
|
-
removeDataFromRedisSet,
|
|
194
|
-
isMemberOfRedisSet,
|
|
195
|
-
};
|
package/config/socket.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
const { Server } = require("socket.io");
|
|
2
|
-
const { publisher, subscriber, connectRedis } = require("./redis");
|
|
3
|
-
require("dotenv").config();
|
|
4
|
-
|
|
5
|
-
let io;
|
|
6
|
-
const namespaceSockets = {}; // Store different namespace sockets
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Initialize Socket.IO server with namespaces
|
|
10
|
-
* @param {http.Server} server - HTTP server instance
|
|
11
|
-
* @param {string} namespaceParam - Socket namespace name (default: "conversation")
|
|
12
|
-
* @param {string} redisChannel - Redis channel for this namespace (default: "socket_events")
|
|
13
|
-
* @returns {SocketIO.Namespace} - The initialized namespace
|
|
14
|
-
*/
|
|
15
|
-
const initializeSocket = async (
|
|
16
|
-
server,
|
|
17
|
-
namespaceParam = "conversation",
|
|
18
|
-
redisChannel = "socket_events"
|
|
19
|
-
) => {
|
|
20
|
-
// Initialize Socket.IO server if not already done
|
|
21
|
-
if (!io) {
|
|
22
|
-
io = new Server(server, {
|
|
23
|
-
cors: {
|
|
24
|
-
origin: "*",
|
|
25
|
-
methods: ["GET", "POST"],
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
console.log("✅ Socket.IO server initialized");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Return existing namespace if already initialized
|
|
32
|
-
if (namespaceSockets[namespaceParam]) {
|
|
33
|
-
console.log(`📢 Using existing namespace: /${namespaceParam}`);
|
|
34
|
-
return namespaceSockets[namespaceParam];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Create and store new namespace
|
|
38
|
-
const namespace = io.of(`/${namespaceParam}`);
|
|
39
|
-
namespaceSockets[namespaceParam] = namespace;
|
|
40
|
-
console.log(`🚀 Created new namespace: /${namespaceParam}`);
|
|
41
|
-
|
|
42
|
-
// Ensure Redis is connected
|
|
43
|
-
await connectRedis();
|
|
44
|
-
|
|
45
|
-
// Create a unique Redis channel for this namespace
|
|
46
|
-
const nsRedisChannel = `${redisChannel}_${namespaceParam}`;
|
|
47
|
-
|
|
48
|
-
// Subscribe to Redis events for this namespace
|
|
49
|
-
await subscriber.subscribe(nsRedisChannel, (messageStr) => {
|
|
50
|
-
try {
|
|
51
|
-
const message = JSON.parse(messageStr);
|
|
52
|
-
const { workspaceId, event, data } = message;
|
|
53
|
-
|
|
54
|
-
console.log(`📥 Redis message received on ${nsRedisChannel}:`, {
|
|
55
|
-
workspaceId,
|
|
56
|
-
event,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Emit to specific workspace room in this namespace
|
|
60
|
-
if (workspaceId) {
|
|
61
|
-
namespace.to(workspaceId).emit(event, data);
|
|
62
|
-
console.log(
|
|
63
|
-
`📢 Event ${event} emitted to workspace ${workspaceId} in /${namespaceParam}`
|
|
64
|
-
);
|
|
65
|
-
} else {
|
|
66
|
-
// Broadcast to all clients in this namespace if no workspaceId specified
|
|
67
|
-
namespace.emit(event, data);
|
|
68
|
-
console.log(
|
|
69
|
-
`📢 Event ${event} broadcasted to all clients in /${namespaceParam}`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
} catch (err) {
|
|
73
|
-
console.error(
|
|
74
|
-
`❌ Error handling Redis message on ${nsRedisChannel}:`,
|
|
75
|
-
err
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Handle new socket connections to this namespace
|
|
81
|
-
namespace.on("connection", (socket) => {
|
|
82
|
-
const { workspaceId } = socket.handshake.query;
|
|
83
|
-
|
|
84
|
-
if (!workspaceId) {
|
|
85
|
-
console.warn(`⚠️ Connection rejected: No workspaceId provided`);
|
|
86
|
-
socket.disconnect(true);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log(
|
|
91
|
-
`✅ Client connected: ${socket.id} (Workspace: ${workspaceId}) in /${namespaceParam}`
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// Join workspace room
|
|
95
|
-
socket.join(workspaceId);
|
|
96
|
-
|
|
97
|
-
// Send connection confirmation to client
|
|
98
|
-
socket.emit("connected", {
|
|
99
|
-
status: "connected",
|
|
100
|
-
socketId: socket.id,
|
|
101
|
-
namespace: namespaceParam,
|
|
102
|
-
workspaceId,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Handle custom events from clients
|
|
106
|
-
socket.on("client_event", (data) => {
|
|
107
|
-
console.log(`📥 Client event from ${socket.id}:`, data);
|
|
108
|
-
// You can process client events here
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Handle disconnect
|
|
112
|
-
socket.on("disconnect", (reason) => {
|
|
113
|
-
console.log(
|
|
114
|
-
`❌ Client disconnected: ${socket.id} (Workspace: ${workspaceId}, Reason: ${reason})`
|
|
115
|
-
);
|
|
116
|
-
socket.leave(workspaceId);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Handle errors
|
|
120
|
-
socket.on("error", (error) => {
|
|
121
|
-
console.error(`❌ Socket error for ${socket.id}:`, error);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
console.log(
|
|
126
|
-
`✅ Namespace /${namespaceParam} initialized and listening on Redis channel: ${nsRedisChannel}`
|
|
127
|
-
);
|
|
128
|
-
return namespace;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Send event to clients via Redis pub/sub
|
|
133
|
-
* @param {object} params - Event parameters
|
|
134
|
-
* @param {string} params.workspaceId - Target workspace ID
|
|
135
|
-
* @param {string} params.event - Event name
|
|
136
|
-
* @param {any} params.data - Event data payload
|
|
137
|
-
* @param {string} [params.namespace="conversation"] - Target namespace
|
|
138
|
-
* @param {string} [params.redisChannel="socket_events"] - Base Redis channel
|
|
139
|
-
* @returns {Promise<void>}
|
|
140
|
-
*/
|
|
141
|
-
const sendEventToServer = async ({
|
|
142
|
-
workspaceId,
|
|
143
|
-
event,
|
|
144
|
-
data,
|
|
145
|
-
namespace = "conversation",
|
|
146
|
-
redisChannel = "socket_events",
|
|
147
|
-
}) => {
|
|
148
|
-
try {
|
|
149
|
-
// Create namespace-specific Redis channel
|
|
150
|
-
const nsRedisChannel = `${redisChannel}_${namespace}`;
|
|
151
|
-
|
|
152
|
-
// Ensure Redis is connected
|
|
153
|
-
await connectRedis();
|
|
154
|
-
|
|
155
|
-
// Create message payload
|
|
156
|
-
const message = JSON.stringify({ workspaceId, event, data });
|
|
157
|
-
|
|
158
|
-
// Publish to Redis
|
|
159
|
-
await publisher.publish(nsRedisChannel, message);
|
|
160
|
-
|
|
161
|
-
console.log(
|
|
162
|
-
`📢 Event published to Redis channel ${nsRedisChannel}: ${event} (Workspace: ${workspaceId})`
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
return true;
|
|
166
|
-
} catch (err) {
|
|
167
|
-
console.error("❌ Error publishing to Redis:", err);
|
|
168
|
-
throw err;
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
module.exports = { initializeSocket, sendEventToServer };
|
package/models/AgentActivity.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
const mongoose = require("mongoose");
|
|
2
|
-
const { Schema } = mongoose;
|
|
3
|
-
|
|
4
|
-
const breakSchema = new mongoose.Schema({
|
|
5
|
-
refId: { type: String, required: true },
|
|
6
|
-
breakId: { type: String, required: false },
|
|
7
|
-
startTime: { type: Date, required: true },
|
|
8
|
-
endTime: { type: Date, required: false },
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
const responseSchema = new mongoose.Schema({
|
|
12
|
-
queryMessageId: { type: [String], default: [] },
|
|
13
|
-
responseMessageId: { type: [String], default: [] },
|
|
14
|
-
responseTime: { type: Number, required: false },
|
|
15
|
-
accuracy: { type: Number, required: false, default: 10 },
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const activitySchema = new mongoose.Schema({
|
|
19
|
-
refId: { type: String, required: true },
|
|
20
|
-
type: {
|
|
21
|
-
type: String,
|
|
22
|
-
required: true,
|
|
23
|
-
default: "other",
|
|
24
|
-
enum: ["conversation", "ticket", "order", "other"],
|
|
25
|
-
},
|
|
26
|
-
platformName: { type: String, required: false },
|
|
27
|
-
platformType: { type: String, required: false },
|
|
28
|
-
customerName: { type: String, default: "", required: false },
|
|
29
|
-
conversationId: { type: String, default: "", required: false },
|
|
30
|
-
profileId: { type: String, required: false },
|
|
31
|
-
conversationType: {
|
|
32
|
-
type: String,
|
|
33
|
-
enum: ["email", "comment", "message", ""],
|
|
34
|
-
default: "",
|
|
35
|
-
required: false,
|
|
36
|
-
},
|
|
37
|
-
status: { type: String, required: false, default: "unassigned" },
|
|
38
|
-
sourceType: { type: String, required: false, default: "normal" },
|
|
39
|
-
labels: [{ type: Schema.Types.ObjectId, ref: "Label" }],
|
|
40
|
-
platformId: { type: String, required: false },
|
|
41
|
-
assignTime: { type: Date, required: false },
|
|
42
|
-
qaScore: { type: Number, required: false, default: 10 },
|
|
43
|
-
startTime: { type: String, required: false },
|
|
44
|
-
endTime: { type: String, required: false },
|
|
45
|
-
resolutionTime: { type: String, required: false },
|
|
46
|
-
responses: { type: [responseSchema], default: [] },
|
|
47
|
-
remarks: { type: String, required: false },
|
|
48
|
-
avgAccuracy: { type: Number, required: false, default: 10 },
|
|
49
|
-
sender: { type: String, required: "" },
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const totalActivitySchema = new mongoose.Schema({
|
|
53
|
-
type: { type: String, required: true },
|
|
54
|
-
platformType: { type: String, required: false },
|
|
55
|
-
count: { type: Number, required: true },
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const agentActivitySchema = new mongoose.Schema(
|
|
59
|
-
{
|
|
60
|
-
_id: {
|
|
61
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
62
|
-
default: () => new mongoose.Types.ObjectId(),
|
|
63
|
-
},
|
|
64
|
-
agentId: { type: String, required: true },
|
|
65
|
-
agentRole: { type: String, default: "" },
|
|
66
|
-
agentName: { type: String, required: false },
|
|
67
|
-
agentShift: { type: Object, default: {}, required: false },
|
|
68
|
-
workspaceId: {
|
|
69
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
70
|
-
required: true,
|
|
71
|
-
ref: "Workspace",
|
|
72
|
-
},
|
|
73
|
-
date: { type: String, required: true },
|
|
74
|
-
lateMinutes: {
|
|
75
|
-
type: Number,
|
|
76
|
-
default: 0,
|
|
77
|
-
},
|
|
78
|
-
earlyLeaveMinutes: {
|
|
79
|
-
type: Number,
|
|
80
|
-
default: 0,
|
|
81
|
-
},
|
|
82
|
-
shiftStartTime: { type: [Date], default: [] },
|
|
83
|
-
shiftEndTime: { type: [Date], default: [] },
|
|
84
|
-
shifts: [
|
|
85
|
-
{
|
|
86
|
-
shiftStartTime: { type: Date, required: true, default: null },
|
|
87
|
-
shiftEndTime: { type: Date, required: false, default: null },
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
isLate: { type: Boolean, required: true, default: false },
|
|
91
|
-
isEarlyLeave: { type: Boolean, required: true, default: false },
|
|
92
|
-
breaks: { type: [breakSchema], default: [] },
|
|
93
|
-
activities: { type: [activitySchema], default: [] },
|
|
94
|
-
totalPsc: { type: Number, required: false, default: 0 },
|
|
95
|
-
totalQa: { type: Number, required: false, default: 0 },
|
|
96
|
-
weightedQa: { type: Number, required: false, default: 0 },
|
|
97
|
-
weightedPsc: { type: Number, required: false, default: 0 },
|
|
98
|
-
kpiScore: { type: Number, required: false, default: 0 },
|
|
99
|
-
totalActivities: { type: [totalActivitySchema], default: [] },
|
|
100
|
-
totalWorkTime: { type: Number, required: false, default: 0 },
|
|
101
|
-
totalBreakTime: { type: Number, required: false, default: 0 },
|
|
102
|
-
totalIdleTime: { type: Number, required: false, default: 0 },
|
|
103
|
-
},
|
|
104
|
-
{ timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } }
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
agentActivitySchema.index({ workspaceId: 1 });
|
|
108
|
-
agentActivitySchema.index({ date: 1 });
|
|
109
|
-
agentActivitySchema.index({ agentId: 1 });
|
|
110
|
-
agentActivitySchema.index({ "activities.platformId": 1 });
|
|
111
|
-
agentActivitySchema.index({ "activities.labels": 1 });
|
|
112
|
-
agentActivitySchema.index({ workspaceId: 1, date: 1, agentId: 1 });
|
|
113
|
-
agentActivitySchema.index({
|
|
114
|
-
workspaceId: 1,
|
|
115
|
-
date: 1,
|
|
116
|
-
agentId: 1,
|
|
117
|
-
"activities.platformId": 1,
|
|
118
|
-
"activities.labels": 1,
|
|
119
|
-
});
|
|
120
|
-
agentActivitySchema.index({
|
|
121
|
-
workspaceId: 1,
|
|
122
|
-
date: 1,
|
|
123
|
-
agentId: 1,
|
|
124
|
-
"activities.platformId": 1,
|
|
125
|
-
});
|
|
126
|
-
agentActivitySchema.index({
|
|
127
|
-
workspaceId: 1,
|
|
128
|
-
date: 1,
|
|
129
|
-
agentId: 1,
|
|
130
|
-
"activities.labels": 1,
|
|
131
|
-
});
|
|
132
|
-
agentActivitySchema.index(
|
|
133
|
-
{ "activities.platformId": 1, "activities.labels": 1 },
|
|
134
|
-
{
|
|
135
|
-
partialFilterExpression: {
|
|
136
|
-
"activities.platformId": { $exists: true },
|
|
137
|
-
"activities.labels": { $exists: true },
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
);
|
|
141
|
-
const AgentActivity = mongoose.model("AgentActivity", agentActivitySchema);
|
|
142
|
-
|
|
143
|
-
const findOneAndUpdateAgentActivity = async (
|
|
144
|
-
findQuery = {},
|
|
145
|
-
updateQuery = null
|
|
146
|
-
) => {
|
|
147
|
-
try {
|
|
148
|
-
if (!findQuery || Object.values(findQuery).length === 0) {
|
|
149
|
-
console.log("Find Query is required.");
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const agentActivityForActivitiesUpdated = await AgentActivity.findOne(
|
|
154
|
-
findQuery
|
|
155
|
-
).sort({ createdAt: -1 });
|
|
156
|
-
|
|
157
|
-
if (!agentActivityForActivitiesUpdated) {
|
|
158
|
-
console.log("No matching record found.");
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const bsonSize = require("bson").calculateObjectSize(
|
|
163
|
-
agentActivityForActivitiesUpdated
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
if (bsonSize <= 1000000) {
|
|
167
|
-
return await AgentActivity.findOneAndUpdate(findQuery, updateQuery);
|
|
168
|
-
} else {
|
|
169
|
-
const { breaks, activities, totalActivities, ...restData } =
|
|
170
|
-
agentActivityForActivitiesUpdated.toObject();
|
|
171
|
-
|
|
172
|
-
const newAgentActivity = await AgentActivity.create({
|
|
173
|
-
...restData,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const agentActivityRecord = await AgentActivity.findOneAndUpdate(
|
|
177
|
-
{ ...findQuery, _id: newAgentActivity._id },
|
|
178
|
-
updateQuery
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
return agentActivityRecord;
|
|
182
|
-
}
|
|
183
|
-
} catch (err) {
|
|
184
|
-
console.error("Error:", err);
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
module.exports = {
|
|
190
|
-
AgentActivity,
|
|
191
|
-
findOneAndUpdateAgentActivity,
|
|
192
|
-
};
|
package/models/Assignment.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const mongoose = require("mongoose");
|
|
2
|
-
|
|
3
|
-
const assignmentSchema = new mongoose.Schema({
|
|
4
|
-
cardId: {
|
|
5
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
6
|
-
ref: "Card",
|
|
7
|
-
required: true,
|
|
8
|
-
},
|
|
9
|
-
id: {
|
|
10
|
-
type: String,
|
|
11
|
-
required: true,
|
|
12
|
-
},
|
|
13
|
-
name: {
|
|
14
|
-
type: String,
|
|
15
|
-
},
|
|
16
|
-
email: {
|
|
17
|
-
type: String,
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const Assignment = mongoose.model("Assignment", assignmentSchema);
|
|
22
|
-
|
|
23
|
-
module.exports = Assignment;
|