flykup_model_production 1.0.16 → 1.0.18
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/.gitattributes +2 -0
- package/.github/workflows/publish.yml +31 -0
- package/auth.js +14 -14
- package/config.js +1 -1
- package/db_connection.js +23 -23
- package/index.js +140 -140
- package/models/AadhaarVerification.js +131 -131
- package/models/AdminEmail.model.js +38 -38
- package/models/BankVerification.js +92 -92
- package/models/GSTVerification.js +89 -89
- package/models/LiveStreamInteraction.model.js +101 -101
- package/models/ProductInteraction.model.js +108 -108
- package/models/Review.model.js +121 -121
- package/models/SearchAnalytics.js +23 -23
- package/models/ShoppableInteraction.model.js +106 -106
- package/models/Wishlist.model.js +29 -29
- package/models/admin.model.js +42 -42
- package/models/appUpdate.model.js +19 -19
- package/models/assets.model.js +32 -32
- package/models/blockedRegion.models.js +27 -27
- package/models/chat.model.js +511 -511
- package/models/coHostInvitation.model.js +60 -60
- package/models/follow.model.js +38 -38
- package/models/loginlogs.model.js +26 -26
- package/models/notification.model.js +130 -129
- package/models/order.modal.js +385 -385
- package/models/orderPayment.model.js +218 -218
- package/models/productListing.model.js +322 -322
- package/models/profileInteractions.model.js +44 -44
- package/models/registerShow.model.js +29 -29
- package/models/sellerDraft.model.js +27 -27
- package/models/shipper.model.js +126 -126
- package/models/shoppableVideo.model.js +237 -237
- package/models/shoppableVideoComment.model.js +57 -57
- package/models/shoppableVideoLike.model.js +29 -29
- package/models/shoppableVideoSave.model.js +27 -27
- package/models/shows.model.js +603 -603
- package/models/stock.model.js +105 -105
- package/models/ticket.model.js +115 -115
- package/package.json +18 -18
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import mongoose, { Schema, model } from "mongoose";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// Define the Rendition sub-schema
|
|
8
|
-
const RenditionSchema = new Schema({
|
|
9
|
-
resolution: { type: String, required: false }, // e.g. "1080p"
|
|
10
|
-
bitrate: { type: Number, required: false }, // e.g. 3000000 (bps)
|
|
11
|
-
playlistKey: { type: String, required: false }, // e.g. "video123/1080p.m3u8"
|
|
12
|
-
hlsUrl: { type: String, required: false }, // Full HLS URL for this rendition
|
|
13
|
-
size: { type: Number, required: false }, // bytes of all .ts + playlist
|
|
14
|
-
ratio: { type: Number, required: false }, // size/originalSize
|
|
15
|
-
}, { _id: false }); // No separate _id for subdocuments unless needed
|
|
16
|
-
|
|
17
|
-
const ShoppableVideoSchema = new Schema(
|
|
18
|
-
{
|
|
19
|
-
host: {
|
|
20
|
-
type: Schema.Types.ObjectId,
|
|
21
|
-
required: true,
|
|
22
|
-
refPath: 'hostModel'
|
|
23
|
-
},
|
|
24
|
-
hostModel: {
|
|
25
|
-
type: String,
|
|
26
|
-
required: true,
|
|
27
|
-
enum: ['sellers', 'dropshippers'],
|
|
28
|
-
index: true
|
|
29
|
-
},
|
|
30
|
-
title: {
|
|
31
|
-
type: String,
|
|
32
|
-
trim: true,
|
|
33
|
-
required: true,
|
|
34
|
-
},
|
|
35
|
-
description: {
|
|
36
|
-
type: String,
|
|
37
|
-
required: false,
|
|
38
|
-
trim: true,
|
|
39
|
-
},
|
|
40
|
-
category: { type: String, required: false, trim: false},
|
|
41
|
-
subcategory: { type: String, required: false, trim: false },
|
|
42
|
-
// thumbnailURL might be set initially or updated by the processing service
|
|
43
|
-
isThumbnailEnabled: {
|
|
44
|
-
type: Boolean,
|
|
45
|
-
default: false, // toggle OFF by default
|
|
46
|
-
},
|
|
47
|
-
thumbnailURL: {
|
|
48
|
-
type: String,
|
|
49
|
-
default: null
|
|
50
|
-
},
|
|
51
|
-
isProductsAvailable : { type : Boolean, required : true, default : false },
|
|
52
|
-
productsListed: {
|
|
53
|
-
type: [
|
|
54
|
-
{
|
|
55
|
-
type: Schema.Types.ObjectId,
|
|
56
|
-
ref: "productlistings",
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
default: [],
|
|
60
|
-
},
|
|
61
|
-
hashTags: {
|
|
62
|
-
type: [
|
|
63
|
-
{
|
|
64
|
-
type: String,
|
|
65
|
-
trim: true
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
processingStatus: {
|
|
70
|
-
type: String,
|
|
71
|
-
enum: ["queued", "processing", "published", "failed", "transcoding_complete","uploaded"], // Added new status
|
|
72
|
-
default: "uploaded",
|
|
73
|
-
index: true,
|
|
74
|
-
},
|
|
75
|
-
visibility: {
|
|
76
|
-
type: String,
|
|
77
|
-
enum: ["public", "private", "deleted"],
|
|
78
|
-
default: "public",
|
|
79
|
-
index: true,
|
|
80
|
-
},
|
|
81
|
-
thumbnailBlobName: {
|
|
82
|
-
type: String,
|
|
83
|
-
default: null,
|
|
84
|
-
},
|
|
85
|
-
originalVideoBlobName: {
|
|
86
|
-
type: String,
|
|
87
|
-
default: null,
|
|
88
|
-
},
|
|
89
|
-
originalFileSize: {
|
|
90
|
-
type: Number,
|
|
91
|
-
default: null,
|
|
92
|
-
},
|
|
93
|
-
optimizedKey: {
|
|
94
|
-
type: String,
|
|
95
|
-
default: null,
|
|
96
|
-
},
|
|
97
|
-
processingError: {
|
|
98
|
-
type: String,
|
|
99
|
-
default: null,
|
|
100
|
-
},
|
|
101
|
-
optimizedSize: {
|
|
102
|
-
type: Number,
|
|
103
|
-
default: null,
|
|
104
|
-
},
|
|
105
|
-
durationSeconds: {
|
|
106
|
-
type: Number,
|
|
107
|
-
default: null,
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
// === NEW FIELDS FOR VIDEO PROCESSING CALLBACK ===
|
|
111
|
-
renditions: {
|
|
112
|
-
type: [RenditionSchema], // Array of rendition objects
|
|
113
|
-
default: [],
|
|
114
|
-
},
|
|
115
|
-
videoId: { // Optimized video URL for playback from other db
|
|
116
|
-
type: String,
|
|
117
|
-
default: null,
|
|
118
|
-
trim: true,
|
|
119
|
-
},
|
|
120
|
-
optimizationStatus: { // Status of optimization process
|
|
121
|
-
type: String,
|
|
122
|
-
enum: ["success", "failed","progress"],
|
|
123
|
-
default: "progress",
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
durationSeconds: {
|
|
127
|
-
type: Number,
|
|
128
|
-
default: null,
|
|
129
|
-
},
|
|
130
|
-
reductionPercentage:{
|
|
131
|
-
type:String,
|
|
132
|
-
default: null,
|
|
133
|
-
trim: true,
|
|
134
|
-
},
|
|
135
|
-
masterPlaylistKey: { // Key for the master playlist in the public container
|
|
136
|
-
type: String,
|
|
137
|
-
default: null,
|
|
138
|
-
trim: true,
|
|
139
|
-
},
|
|
140
|
-
durationTook: {
|
|
141
|
-
type: String, // Duration took for the optimization process
|
|
142
|
-
trim: true,
|
|
143
|
-
default: null, // Duration in seconds for the optimization process
|
|
144
|
-
},
|
|
145
|
-
commentsCount: {
|
|
146
|
-
type: Number,
|
|
147
|
-
default: 0
|
|
148
|
-
},
|
|
149
|
-
shares: {
|
|
150
|
-
type: Number,
|
|
151
|
-
default: 0
|
|
152
|
-
},
|
|
153
|
-
// Analytics new fields
|
|
154
|
-
viewCount: {
|
|
155
|
-
type: Number,
|
|
156
|
-
default: 0
|
|
157
|
-
},
|
|
158
|
-
uniqueViewCount: {
|
|
159
|
-
type: Number,
|
|
160
|
-
default: 0
|
|
161
|
-
},
|
|
162
|
-
totalWatchDuration: {
|
|
163
|
-
type: Number,
|
|
164
|
-
default: 0
|
|
165
|
-
},
|
|
166
|
-
totalCompletionPercentageSum: {
|
|
167
|
-
type: Number,
|
|
168
|
-
default: 0
|
|
169
|
-
},
|
|
170
|
-
// Admin blocking fields
|
|
171
|
-
isBlocked: {
|
|
172
|
-
type: Boolean,
|
|
173
|
-
default: false,
|
|
174
|
-
index: true // For efficient queries of blocked videos
|
|
175
|
-
},
|
|
176
|
-
blockedBy: {
|
|
177
|
-
type: Schema.Types.ObjectId,
|
|
178
|
-
ref: 'Admin',
|
|
179
|
-
default: null
|
|
180
|
-
},
|
|
181
|
-
blockReason: {
|
|
182
|
-
type: String,
|
|
183
|
-
default: null,
|
|
184
|
-
trim: true
|
|
185
|
-
},
|
|
186
|
-
blockedAt: {
|
|
187
|
-
type: Date,
|
|
188
|
-
default: null
|
|
189
|
-
},
|
|
190
|
-
isEligibleToPlay: {
|
|
191
|
-
type: Boolean,
|
|
192
|
-
default: false, // Default to true, can be set to false if video is not eligible for playback
|
|
193
|
-
index: true // Index for quick lookups
|
|
194
|
-
},
|
|
195
|
-
// Admin Approval Fields
|
|
196
|
-
approvalStatus: {
|
|
197
|
-
type: String,
|
|
198
|
-
enum: ['pending', 'approved', 'rejected'],
|
|
199
|
-
default: 'pending',
|
|
200
|
-
index: true
|
|
201
|
-
},
|
|
202
|
-
approvedBy: {
|
|
203
|
-
type: Schema.Types.ObjectId,
|
|
204
|
-
ref: 'Admin',
|
|
205
|
-
default: null
|
|
206
|
-
},
|
|
207
|
-
approvedAt: {
|
|
208
|
-
type: Date,
|
|
209
|
-
default: null
|
|
210
|
-
},
|
|
211
|
-
rejectionReason: {
|
|
212
|
-
type: String,
|
|
213
|
-
default: null,
|
|
214
|
-
trim: true
|
|
215
|
-
},
|
|
216
|
-
rejectedBy: {
|
|
217
|
-
type: Schema.Types.ObjectId,
|
|
218
|
-
ref: 'Admin',
|
|
219
|
-
default: null
|
|
220
|
-
},
|
|
221
|
-
rejectedAt: {
|
|
222
|
-
type: Date,
|
|
223
|
-
default: null
|
|
224
|
-
},
|
|
225
|
-
|
|
226
|
-
},
|
|
227
|
-
{ timestamps: true }
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
// Index for querying videos that need processing status updates
|
|
231
|
-
ShoppableVideoSchema.index({ processingStatus: 1, updatedAt: 1 });
|
|
232
|
-
// Index for host and their videos
|
|
233
|
-
ShoppableVideoSchema.index({ host: 1, hostModel: 1 });
|
|
234
|
-
|
|
235
|
-
const ShoppableVideo = mongoose.models.shoppablevideos || mongoose.model("shoppablevideos", ShoppableVideoSchema);
|
|
236
|
-
|
|
237
|
-
export default ShoppableVideo;
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import mongoose, { Schema, model } from "mongoose";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
// Define the Rendition sub-schema
|
|
8
|
+
const RenditionSchema = new Schema({
|
|
9
|
+
resolution: { type: String, required: false }, // e.g. "1080p"
|
|
10
|
+
bitrate: { type: Number, required: false }, // e.g. 3000000 (bps)
|
|
11
|
+
playlistKey: { type: String, required: false }, // e.g. "video123/1080p.m3u8"
|
|
12
|
+
hlsUrl: { type: String, required: false }, // Full HLS URL for this rendition
|
|
13
|
+
size: { type: Number, required: false }, // bytes of all .ts + playlist
|
|
14
|
+
ratio: { type: Number, required: false }, // size/originalSize
|
|
15
|
+
}, { _id: false }); // No separate _id for subdocuments unless needed
|
|
16
|
+
|
|
17
|
+
const ShoppableVideoSchema = new Schema(
|
|
18
|
+
{
|
|
19
|
+
host: {
|
|
20
|
+
type: Schema.Types.ObjectId,
|
|
21
|
+
required: true,
|
|
22
|
+
refPath: 'hostModel'
|
|
23
|
+
},
|
|
24
|
+
hostModel: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true,
|
|
27
|
+
enum: ['sellers', 'dropshippers'],
|
|
28
|
+
index: true
|
|
29
|
+
},
|
|
30
|
+
title: {
|
|
31
|
+
type: String,
|
|
32
|
+
trim: true,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
description: {
|
|
36
|
+
type: String,
|
|
37
|
+
required: false,
|
|
38
|
+
trim: true,
|
|
39
|
+
},
|
|
40
|
+
category: { type: String, required: false, trim: false},
|
|
41
|
+
subcategory: { type: String, required: false, trim: false },
|
|
42
|
+
// thumbnailURL might be set initially or updated by the processing service
|
|
43
|
+
isThumbnailEnabled: {
|
|
44
|
+
type: Boolean,
|
|
45
|
+
default: false, // toggle OFF by default
|
|
46
|
+
},
|
|
47
|
+
thumbnailURL: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: null
|
|
50
|
+
},
|
|
51
|
+
isProductsAvailable : { type : Boolean, required : true, default : false },
|
|
52
|
+
productsListed: {
|
|
53
|
+
type: [
|
|
54
|
+
{
|
|
55
|
+
type: Schema.Types.ObjectId,
|
|
56
|
+
ref: "productlistings",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
default: [],
|
|
60
|
+
},
|
|
61
|
+
hashTags: {
|
|
62
|
+
type: [
|
|
63
|
+
{
|
|
64
|
+
type: String,
|
|
65
|
+
trim: true
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
processingStatus: {
|
|
70
|
+
type: String,
|
|
71
|
+
enum: ["queued", "processing", "published", "failed", "transcoding_complete","uploaded"], // Added new status
|
|
72
|
+
default: "uploaded",
|
|
73
|
+
index: true,
|
|
74
|
+
},
|
|
75
|
+
visibility: {
|
|
76
|
+
type: String,
|
|
77
|
+
enum: ["public", "private", "deleted"],
|
|
78
|
+
default: "public",
|
|
79
|
+
index: true,
|
|
80
|
+
},
|
|
81
|
+
thumbnailBlobName: {
|
|
82
|
+
type: String,
|
|
83
|
+
default: null,
|
|
84
|
+
},
|
|
85
|
+
originalVideoBlobName: {
|
|
86
|
+
type: String,
|
|
87
|
+
default: null,
|
|
88
|
+
},
|
|
89
|
+
originalFileSize: {
|
|
90
|
+
type: Number,
|
|
91
|
+
default: null,
|
|
92
|
+
},
|
|
93
|
+
optimizedKey: {
|
|
94
|
+
type: String,
|
|
95
|
+
default: null,
|
|
96
|
+
},
|
|
97
|
+
processingError: {
|
|
98
|
+
type: String,
|
|
99
|
+
default: null,
|
|
100
|
+
},
|
|
101
|
+
optimizedSize: {
|
|
102
|
+
type: Number,
|
|
103
|
+
default: null,
|
|
104
|
+
},
|
|
105
|
+
durationSeconds: {
|
|
106
|
+
type: Number,
|
|
107
|
+
default: null,
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// === NEW FIELDS FOR VIDEO PROCESSING CALLBACK ===
|
|
111
|
+
renditions: {
|
|
112
|
+
type: [RenditionSchema], // Array of rendition objects
|
|
113
|
+
default: [],
|
|
114
|
+
},
|
|
115
|
+
videoId: { // Optimized video URL for playback from other db
|
|
116
|
+
type: String,
|
|
117
|
+
default: null,
|
|
118
|
+
trim: true,
|
|
119
|
+
},
|
|
120
|
+
optimizationStatus: { // Status of optimization process
|
|
121
|
+
type: String,
|
|
122
|
+
enum: ["success", "failed","progress"],
|
|
123
|
+
default: "progress",
|
|
124
|
+
|
|
125
|
+
},
|
|
126
|
+
durationSeconds: {
|
|
127
|
+
type: Number,
|
|
128
|
+
default: null,
|
|
129
|
+
},
|
|
130
|
+
reductionPercentage:{
|
|
131
|
+
type:String,
|
|
132
|
+
default: null,
|
|
133
|
+
trim: true,
|
|
134
|
+
},
|
|
135
|
+
masterPlaylistKey: { // Key for the master playlist in the public container
|
|
136
|
+
type: String,
|
|
137
|
+
default: null,
|
|
138
|
+
trim: true,
|
|
139
|
+
},
|
|
140
|
+
durationTook: {
|
|
141
|
+
type: String, // Duration took for the optimization process
|
|
142
|
+
trim: true,
|
|
143
|
+
default: null, // Duration in seconds for the optimization process
|
|
144
|
+
},
|
|
145
|
+
commentsCount: {
|
|
146
|
+
type: Number,
|
|
147
|
+
default: 0
|
|
148
|
+
},
|
|
149
|
+
shares: {
|
|
150
|
+
type: Number,
|
|
151
|
+
default: 0
|
|
152
|
+
},
|
|
153
|
+
// Analytics new fields
|
|
154
|
+
viewCount: {
|
|
155
|
+
type: Number,
|
|
156
|
+
default: 0
|
|
157
|
+
},
|
|
158
|
+
uniqueViewCount: {
|
|
159
|
+
type: Number,
|
|
160
|
+
default: 0
|
|
161
|
+
},
|
|
162
|
+
totalWatchDuration: {
|
|
163
|
+
type: Number,
|
|
164
|
+
default: 0
|
|
165
|
+
},
|
|
166
|
+
totalCompletionPercentageSum: {
|
|
167
|
+
type: Number,
|
|
168
|
+
default: 0
|
|
169
|
+
},
|
|
170
|
+
// Admin blocking fields
|
|
171
|
+
isBlocked: {
|
|
172
|
+
type: Boolean,
|
|
173
|
+
default: false,
|
|
174
|
+
index: true // For efficient queries of blocked videos
|
|
175
|
+
},
|
|
176
|
+
blockedBy: {
|
|
177
|
+
type: Schema.Types.ObjectId,
|
|
178
|
+
ref: 'Admin',
|
|
179
|
+
default: null
|
|
180
|
+
},
|
|
181
|
+
blockReason: {
|
|
182
|
+
type: String,
|
|
183
|
+
default: null,
|
|
184
|
+
trim: true
|
|
185
|
+
},
|
|
186
|
+
blockedAt: {
|
|
187
|
+
type: Date,
|
|
188
|
+
default: null
|
|
189
|
+
},
|
|
190
|
+
isEligibleToPlay: {
|
|
191
|
+
type: Boolean,
|
|
192
|
+
default: false, // Default to true, can be set to false if video is not eligible for playback
|
|
193
|
+
index: true // Index for quick lookups
|
|
194
|
+
},
|
|
195
|
+
// Admin Approval Fields
|
|
196
|
+
approvalStatus: {
|
|
197
|
+
type: String,
|
|
198
|
+
enum: ['pending', 'approved', 'rejected'],
|
|
199
|
+
default: 'pending',
|
|
200
|
+
index: true
|
|
201
|
+
},
|
|
202
|
+
approvedBy: {
|
|
203
|
+
type: Schema.Types.ObjectId,
|
|
204
|
+
ref: 'Admin',
|
|
205
|
+
default: null
|
|
206
|
+
},
|
|
207
|
+
approvedAt: {
|
|
208
|
+
type: Date,
|
|
209
|
+
default: null
|
|
210
|
+
},
|
|
211
|
+
rejectionReason: {
|
|
212
|
+
type: String,
|
|
213
|
+
default: null,
|
|
214
|
+
trim: true
|
|
215
|
+
},
|
|
216
|
+
rejectedBy: {
|
|
217
|
+
type: Schema.Types.ObjectId,
|
|
218
|
+
ref: 'Admin',
|
|
219
|
+
default: null
|
|
220
|
+
},
|
|
221
|
+
rejectedAt: {
|
|
222
|
+
type: Date,
|
|
223
|
+
default: null
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
},
|
|
227
|
+
{ timestamps: true }
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// Index for querying videos that need processing status updates
|
|
231
|
+
ShoppableVideoSchema.index({ processingStatus: 1, updatedAt: 1 });
|
|
232
|
+
// Index for host and their videos
|
|
233
|
+
ShoppableVideoSchema.index({ host: 1, hostModel: 1 });
|
|
234
|
+
|
|
235
|
+
const ShoppableVideo = mongoose.models.shoppablevideos || mongoose.model("shoppablevideos", ShoppableVideoSchema);
|
|
236
|
+
|
|
237
|
+
export default ShoppableVideo;
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
-
|
|
3
|
-
const ShoppableVideoCommentSchema = new mongoose.Schema({
|
|
4
|
-
videoId: {
|
|
5
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
6
|
-
ref: "ShoppableVideo",
|
|
7
|
-
required: true
|
|
8
|
-
},
|
|
9
|
-
userId: {
|
|
10
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
11
|
-
ref: "users", // Must match exactly with your model name
|
|
12
|
-
required: true
|
|
13
|
-
},
|
|
14
|
-
text: {
|
|
15
|
-
type: String,
|
|
16
|
-
required: true,
|
|
17
|
-
trim: true
|
|
18
|
-
},
|
|
19
|
-
likes: {
|
|
20
|
-
type: Number,
|
|
21
|
-
default: 0
|
|
22
|
-
},
|
|
23
|
-
likedBy: [{
|
|
24
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
25
|
-
ref: "users"
|
|
26
|
-
}],
|
|
27
|
-
isReply: {
|
|
28
|
-
type: Boolean,
|
|
29
|
-
default: false
|
|
30
|
-
},
|
|
31
|
-
parentCommentId: {
|
|
32
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
33
|
-
ref: "ShoppableVideoComment"
|
|
34
|
-
},
|
|
35
|
-
repliesCount: {
|
|
36
|
-
type: Number,
|
|
37
|
-
default: 0
|
|
38
|
-
}
|
|
39
|
-
}, {
|
|
40
|
-
timestamps: true,
|
|
41
|
-
toJSON: { virtuals: true },
|
|
42
|
-
toObject: { virtuals: true }
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Corrected virtual field
|
|
46
|
-
ShoppableVideoCommentSchema.virtual('isLiked').get(function() {
|
|
47
|
-
return this.likedBy ? this.likedBy.includes(this.userId) : false;
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Indexes
|
|
51
|
-
ShoppableVideoCommentSchema.index({ videoId: 1, createdAt: -1 });
|
|
52
|
-
ShoppableVideoCommentSchema.index({ parentCommentId: 1, createdAt: -1 });
|
|
53
|
-
ShoppableVideoCommentSchema.index({ userId: 1 });
|
|
54
|
-
ShoppableVideoCommentSchema.index({ videoId: 1, isReply: 1 });
|
|
55
|
-
|
|
56
|
-
const ShoppableVideoComment = mongoose.models.ShoppableVideoComment || mongoose.model("ShoppableVideoComment", ShoppableVideoCommentSchema);
|
|
57
|
-
export default ShoppableVideoComment;
|
|
1
|
+
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
const ShoppableVideoCommentSchema = new mongoose.Schema({
|
|
4
|
+
videoId: {
|
|
5
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
6
|
+
ref: "ShoppableVideo",
|
|
7
|
+
required: true
|
|
8
|
+
},
|
|
9
|
+
userId: {
|
|
10
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
11
|
+
ref: "users", // Must match exactly with your model name
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
text: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: true,
|
|
17
|
+
trim: true
|
|
18
|
+
},
|
|
19
|
+
likes: {
|
|
20
|
+
type: Number,
|
|
21
|
+
default: 0
|
|
22
|
+
},
|
|
23
|
+
likedBy: [{
|
|
24
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
25
|
+
ref: "users"
|
|
26
|
+
}],
|
|
27
|
+
isReply: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false
|
|
30
|
+
},
|
|
31
|
+
parentCommentId: {
|
|
32
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
33
|
+
ref: "ShoppableVideoComment"
|
|
34
|
+
},
|
|
35
|
+
repliesCount: {
|
|
36
|
+
type: Number,
|
|
37
|
+
default: 0
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
timestamps: true,
|
|
41
|
+
toJSON: { virtuals: true },
|
|
42
|
+
toObject: { virtuals: true }
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Corrected virtual field
|
|
46
|
+
ShoppableVideoCommentSchema.virtual('isLiked').get(function() {
|
|
47
|
+
return this.likedBy ? this.likedBy.includes(this.userId) : false;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Indexes
|
|
51
|
+
ShoppableVideoCommentSchema.index({ videoId: 1, createdAt: -1 });
|
|
52
|
+
ShoppableVideoCommentSchema.index({ parentCommentId: 1, createdAt: -1 });
|
|
53
|
+
ShoppableVideoCommentSchema.index({ userId: 1 });
|
|
54
|
+
ShoppableVideoCommentSchema.index({ videoId: 1, isReply: 1 });
|
|
55
|
+
|
|
56
|
+
const ShoppableVideoComment = mongoose.models.ShoppableVideoComment || mongoose.model("ShoppableVideoComment", ShoppableVideoCommentSchema);
|
|
57
|
+
export default ShoppableVideoComment;
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
-
|
|
3
|
-
const shoppableVideoLikeSchema = new mongoose.Schema(
|
|
4
|
-
{
|
|
5
|
-
videoId: {
|
|
6
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
7
|
-
ref: "ShoppableVideo",
|
|
8
|
-
required: true,
|
|
9
|
-
},
|
|
10
|
-
userId: {
|
|
11
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
12
|
-
ref: "User", // Adjust to your User model name
|
|
13
|
-
required: true,
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
timestamps: true,
|
|
18
|
-
}
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
// Create compound index to ensure one like per user per video
|
|
22
|
-
shoppableVideoLikeSchema.index({ videoId: 1, userId: 1 }, { unique: true });
|
|
23
|
-
|
|
24
|
-
// Index for efficient queries
|
|
25
|
-
shoppableVideoLikeSchema.index({ videoId: 1, createdAt: -1 });
|
|
26
|
-
shoppableVideoLikeSchema.index({ userId: 1, createdAt: -1 });
|
|
27
|
-
|
|
28
|
-
const ShoppableVideoLike = mongoose.models.ShoppableVideoLike || mongoose.model("ShoppableVideoLike", shoppableVideoLikeSchema);
|
|
29
|
-
export default ShoppableVideoLike;
|
|
1
|
+
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
const shoppableVideoLikeSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
videoId: {
|
|
6
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
7
|
+
ref: "ShoppableVideo",
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
userId: {
|
|
11
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
12
|
+
ref: "User", // Adjust to your User model name
|
|
13
|
+
required: true,
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
timestamps: true,
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Create compound index to ensure one like per user per video
|
|
22
|
+
shoppableVideoLikeSchema.index({ videoId: 1, userId: 1 }, { unique: true });
|
|
23
|
+
|
|
24
|
+
// Index for efficient queries
|
|
25
|
+
shoppableVideoLikeSchema.index({ videoId: 1, createdAt: -1 });
|
|
26
|
+
shoppableVideoLikeSchema.index({ userId: 1, createdAt: -1 });
|
|
27
|
+
|
|
28
|
+
const ShoppableVideoLike = mongoose.models.ShoppableVideoLike || mongoose.model("ShoppableVideoLike", shoppableVideoLikeSchema);
|
|
29
|
+
export default ShoppableVideoLike;
|