flykup_model_production 1.0.15 → 1.0.17
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 -381
- package/models/orderPayment.model.js +219 -105
- package/models/productListing.model.js +322 -318
- package/models/profileInteractions.model.js +44 -44
- package/models/registerShow.model.js +29 -29
- package/models/sellerDraft.model.js +27 -27
- package/models/seller_settlements_2025-11-18 (1).csv +4 -0
- package/models/seller_settlements_2025-11-18.csv +4 -0
- 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 -570
- package/models/stock.model.js +105 -105
- package/models/ticket.model.js +115 -115
- package/models/user.model.js +7 -0
- package/package.json +18 -18
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
-
|
|
3
|
-
const productInteractionSchema = new mongoose.Schema({
|
|
4
|
-
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
|
|
5
|
-
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
|
|
6
|
-
seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
|
|
7
|
-
location: {
|
|
8
|
-
city: String,
|
|
9
|
-
region: String,
|
|
10
|
-
country: String
|
|
11
|
-
},
|
|
12
|
-
platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
|
|
13
|
-
device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
|
|
14
|
-
browser: String,
|
|
15
|
-
os: String,
|
|
16
|
-
ip: { type: String, required: true },
|
|
17
|
-
isIndianRegion: { type: Boolean, default: false },
|
|
18
|
-
rating: {
|
|
19
|
-
type: Number,
|
|
20
|
-
min: 1,
|
|
21
|
-
max: 5,
|
|
22
|
-
validate: {
|
|
23
|
-
validator: Number.isInteger,
|
|
24
|
-
message: '{VALUE} is not an integer value'
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
review: {
|
|
28
|
-
type: String,
|
|
29
|
-
maxlength: 500
|
|
30
|
-
},
|
|
31
|
-
viewCount: { type: Number, default: 1 },
|
|
32
|
-
// NEW: Trust signals tracking
|
|
33
|
-
trustSignals: {
|
|
34
|
-
reviewViews: { type: Number, default: 0 }, // How many times user viewed reviews
|
|
35
|
-
reviewViewDuration: { type: Number, default: 0 }, // Total time spent on reviews (seconds)
|
|
36
|
-
comparisonViews: { type: Number, default: 0 }, // How many times user compared with other products
|
|
37
|
-
priceCheckCount: { type: Number, default: 0 }, // How many times user checked pricing
|
|
38
|
-
lastTrustSignalAt: { type: Date } // When the last trust signal was recorded
|
|
39
|
-
},
|
|
40
|
-
// NEW: Engagement status for sellers
|
|
41
|
-
engagementStatus: {
|
|
42
|
-
type: String,
|
|
43
|
-
enum: ['new', 'interested', 'hesitant', 'contacted', 'converted'],
|
|
44
|
-
default: 'new'
|
|
45
|
-
},
|
|
46
|
-
sellerNotes: [{
|
|
47
|
-
note: String,
|
|
48
|
-
createdAt: { type: Date, default: Date.now },
|
|
49
|
-
updatedAt: { type: Date, default: Date.now }
|
|
50
|
-
}]
|
|
51
|
-
}, { timestamps: true });
|
|
52
|
-
|
|
53
|
-
// Ensures a user's view is counted only once per product
|
|
54
|
-
productInteractionSchema.index({ product: 1, user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } });
|
|
55
|
-
|
|
56
|
-
// Additional indexes for performance
|
|
57
|
-
productInteractionSchema.index({ createdAt: -1 });
|
|
58
|
-
|
|
59
|
-
// Safe export to prevent OverwriteModelError
|
|
60
|
-
const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
|
|
61
|
-
export default ProductInteraction;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// import mongoose, { Schema, model } from 'mongoose';
|
|
67
|
-
|
|
68
|
-
// const productInteractionSchema = new mongoose.Schema({
|
|
69
|
-
// product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
|
|
70
|
-
// user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
|
|
71
|
-
// seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
|
|
72
|
-
// location: {
|
|
73
|
-
// city: String,
|
|
74
|
-
// region: String,
|
|
75
|
-
// country: String
|
|
76
|
-
// },
|
|
77
|
-
// // --- NEW FIELD ---
|
|
78
|
-
// platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
|
|
79
|
-
// device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
|
|
80
|
-
// browser: String,
|
|
81
|
-
// os: String,
|
|
82
|
-
// ip: { type: String, required: true },
|
|
83
|
-
// isIndianRegion: { type: Boolean, default: false },
|
|
84
|
-
// rating: {
|
|
85
|
-
// type: Number,
|
|
86
|
-
// min: 1,
|
|
87
|
-
// max: 5,
|
|
88
|
-
// validate: {
|
|
89
|
-
// validator: Number.isInteger,
|
|
90
|
-
// message: '{VALUE} is not an integer value'
|
|
91
|
-
// }
|
|
92
|
-
// },
|
|
93
|
-
// review: {
|
|
94
|
-
// type: String,
|
|
95
|
-
// maxlength: 500
|
|
96
|
-
// },
|
|
97
|
-
// viewCount: { type: Number, default: 1 }
|
|
98
|
-
// }, { timestamps: true });
|
|
99
|
-
|
|
100
|
-
// // Ensures a user's view is counted only once per product
|
|
101
|
-
// productInteractionSchema.index({ product: 1, user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } });
|
|
102
|
-
|
|
103
|
-
// // Additional indexes for performance
|
|
104
|
-
// productInteractionSchema.index({ createdAt: -1 });
|
|
105
|
-
|
|
106
|
-
// // Safe export to prevent OverwriteModelError
|
|
107
|
-
// const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
|
|
108
|
-
// export default ProductInteraction;
|
|
1
|
+
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
const productInteractionSchema = new mongoose.Schema({
|
|
4
|
+
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
|
|
5
|
+
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
|
|
6
|
+
seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
|
|
7
|
+
location: {
|
|
8
|
+
city: String,
|
|
9
|
+
region: String,
|
|
10
|
+
country: String
|
|
11
|
+
},
|
|
12
|
+
platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
|
|
13
|
+
device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
|
|
14
|
+
browser: String,
|
|
15
|
+
os: String,
|
|
16
|
+
ip: { type: String, required: true },
|
|
17
|
+
isIndianRegion: { type: Boolean, default: false },
|
|
18
|
+
rating: {
|
|
19
|
+
type: Number,
|
|
20
|
+
min: 1,
|
|
21
|
+
max: 5,
|
|
22
|
+
validate: {
|
|
23
|
+
validator: Number.isInteger,
|
|
24
|
+
message: '{VALUE} is not an integer value'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
review: {
|
|
28
|
+
type: String,
|
|
29
|
+
maxlength: 500
|
|
30
|
+
},
|
|
31
|
+
viewCount: { type: Number, default: 1 },
|
|
32
|
+
// NEW: Trust signals tracking
|
|
33
|
+
trustSignals: {
|
|
34
|
+
reviewViews: { type: Number, default: 0 }, // How many times user viewed reviews
|
|
35
|
+
reviewViewDuration: { type: Number, default: 0 }, // Total time spent on reviews (seconds)
|
|
36
|
+
comparisonViews: { type: Number, default: 0 }, // How many times user compared with other products
|
|
37
|
+
priceCheckCount: { type: Number, default: 0 }, // How many times user checked pricing
|
|
38
|
+
lastTrustSignalAt: { type: Date } // When the last trust signal was recorded
|
|
39
|
+
},
|
|
40
|
+
// NEW: Engagement status for sellers
|
|
41
|
+
engagementStatus: {
|
|
42
|
+
type: String,
|
|
43
|
+
enum: ['new', 'interested', 'hesitant', 'contacted', 'converted'],
|
|
44
|
+
default: 'new'
|
|
45
|
+
},
|
|
46
|
+
sellerNotes: [{
|
|
47
|
+
note: String,
|
|
48
|
+
createdAt: { type: Date, default: Date.now },
|
|
49
|
+
updatedAt: { type: Date, default: Date.now }
|
|
50
|
+
}]
|
|
51
|
+
}, { timestamps: true });
|
|
52
|
+
|
|
53
|
+
// Ensures a user's view is counted only once per product
|
|
54
|
+
productInteractionSchema.index({ product: 1, user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } });
|
|
55
|
+
|
|
56
|
+
// Additional indexes for performance
|
|
57
|
+
productInteractionSchema.index({ createdAt: -1 });
|
|
58
|
+
|
|
59
|
+
// Safe export to prevent OverwriteModelError
|
|
60
|
+
const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
|
|
61
|
+
export default ProductInteraction;
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
// import mongoose, { Schema, model } from 'mongoose';
|
|
67
|
+
|
|
68
|
+
// const productInteractionSchema = new mongoose.Schema({
|
|
69
|
+
// product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
|
|
70
|
+
// user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
|
|
71
|
+
// seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
|
|
72
|
+
// location: {
|
|
73
|
+
// city: String,
|
|
74
|
+
// region: String,
|
|
75
|
+
// country: String
|
|
76
|
+
// },
|
|
77
|
+
// // --- NEW FIELD ---
|
|
78
|
+
// platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
|
|
79
|
+
// device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
|
|
80
|
+
// browser: String,
|
|
81
|
+
// os: String,
|
|
82
|
+
// ip: { type: String, required: true },
|
|
83
|
+
// isIndianRegion: { type: Boolean, default: false },
|
|
84
|
+
// rating: {
|
|
85
|
+
// type: Number,
|
|
86
|
+
// min: 1,
|
|
87
|
+
// max: 5,
|
|
88
|
+
// validate: {
|
|
89
|
+
// validator: Number.isInteger,
|
|
90
|
+
// message: '{VALUE} is not an integer value'
|
|
91
|
+
// }
|
|
92
|
+
// },
|
|
93
|
+
// review: {
|
|
94
|
+
// type: String,
|
|
95
|
+
// maxlength: 500
|
|
96
|
+
// },
|
|
97
|
+
// viewCount: { type: Number, default: 1 }
|
|
98
|
+
// }, { timestamps: true });
|
|
99
|
+
|
|
100
|
+
// // Ensures a user's view is counted only once per product
|
|
101
|
+
// productInteractionSchema.index({ product: 1, user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } });
|
|
102
|
+
|
|
103
|
+
// // Additional indexes for performance
|
|
104
|
+
// productInteractionSchema.index({ createdAt: -1 });
|
|
105
|
+
|
|
106
|
+
// // Safe export to prevent OverwriteModelError
|
|
107
|
+
// const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
|
|
108
|
+
// export default ProductInteraction;
|
package/models/Review.model.js
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import mongoose from "mongoose";
|
|
2
|
-
const { Schema } = mongoose;
|
|
3
|
-
|
|
4
|
-
// Define the ReviewType enum
|
|
5
|
-
const ReviewType = {
|
|
6
|
-
PRODUCT: "product",
|
|
7
|
-
SELLER: "seller"
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const ReviewSchema = new Schema(
|
|
11
|
-
{
|
|
12
|
-
userId: {
|
|
13
|
-
type: Schema.Types.ObjectId,
|
|
14
|
-
ref: "users",
|
|
15
|
-
required: true
|
|
16
|
-
},
|
|
17
|
-
reviewType: {
|
|
18
|
-
type: String,
|
|
19
|
-
enum: Object.values(ReviewType),
|
|
20
|
-
required: true
|
|
21
|
-
},
|
|
22
|
-
productId: {
|
|
23
|
-
type: Schema.Types.ObjectId,
|
|
24
|
-
ref: "productlistings",
|
|
25
|
-
required: function() {
|
|
26
|
-
return this.reviewType === ReviewType.PRODUCT;
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
sellerId: {
|
|
30
|
-
type: Schema.Types.ObjectId,
|
|
31
|
-
ref: "sellers",
|
|
32
|
-
required: function() {
|
|
33
|
-
return this.reviewType === ReviewType.SELLER;
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
rating: {
|
|
37
|
-
type: Number,
|
|
38
|
-
required: true,
|
|
39
|
-
min: 1,
|
|
40
|
-
max: 5
|
|
41
|
-
},
|
|
42
|
-
content: {
|
|
43
|
-
type: String,
|
|
44
|
-
required: true,
|
|
45
|
-
trim: true,
|
|
46
|
-
maxlength: 1000
|
|
47
|
-
},
|
|
48
|
-
helpfulVotes: {
|
|
49
|
-
type: [{
|
|
50
|
-
userId: {
|
|
51
|
-
type: Schema.Types.ObjectId,
|
|
52
|
-
ref: "users",
|
|
53
|
-
required: true
|
|
54
|
-
},
|
|
55
|
-
voteType: {
|
|
56
|
-
type: String,
|
|
57
|
-
enum: ["helpful", "not_helpful"],
|
|
58
|
-
required: true
|
|
59
|
-
},
|
|
60
|
-
createdAt: {
|
|
61
|
-
type: Date,
|
|
62
|
-
default: Date.now
|
|
63
|
-
}
|
|
64
|
-
}],
|
|
65
|
-
default: []
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
helpfulCount: {
|
|
69
|
-
type: Number,
|
|
70
|
-
default: 0,
|
|
71
|
-
min: 0
|
|
72
|
-
},
|
|
73
|
-
notHelpfulCount: {
|
|
74
|
-
type: Number,
|
|
75
|
-
default: 0,
|
|
76
|
-
min: 0
|
|
77
|
-
},
|
|
78
|
-
images: {
|
|
79
|
-
type: [String], // Array of image URLs
|
|
80
|
-
default: [],
|
|
81
|
-
validate: {
|
|
82
|
-
validator: function(array) {
|
|
83
|
-
return array.length <= 5;
|
|
84
|
-
},
|
|
85
|
-
message: 'Cannot upload more than 5 images per review'
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
timestamps: true,
|
|
91
|
-
toJSON: { virtuals: true },
|
|
92
|
-
toObject: { virtuals: true }
|
|
93
|
-
}
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// Indexes
|
|
97
|
-
ReviewSchema.index({ productId: 1 });
|
|
98
|
-
ReviewSchema.index({ sellerId: 1 });
|
|
99
|
-
ReviewSchema.index({ userId: 1 });
|
|
100
|
-
ReviewSchema.index({ reviewType: 1 });
|
|
101
|
-
ReviewSchema.index({ "helpfulVotes.userId": 1 });
|
|
102
|
-
|
|
103
|
-
// Virtual for total feedback count
|
|
104
|
-
ReviewSchema.virtual('totalFeedback').get(function() {
|
|
105
|
-
return this.helpfulCount + this.notHelpfulCount;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Method to check if a user has voted
|
|
109
|
-
ReviewSchema.methods.hasUserVoted = function(userId) {
|
|
110
|
-
return this.helpfulVotes.some(vote => vote.userId.equals(userId));
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// Method to get user's vote type
|
|
114
|
-
ReviewSchema.methods.getUserVoteType = function(userId) {
|
|
115
|
-
const vote = this.helpfulVotes.find(vote => vote.userId.equals(userId));
|
|
116
|
-
return vote ? vote.voteType : null;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Safe export to prevent OverwriteModelError
|
|
120
|
-
const Review = mongoose.models.reviews || mongoose.model("reviews", ReviewSchema);
|
|
121
|
-
export { Review, ReviewType };
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
const { Schema } = mongoose;
|
|
3
|
+
|
|
4
|
+
// Define the ReviewType enum
|
|
5
|
+
const ReviewType = {
|
|
6
|
+
PRODUCT: "product",
|
|
7
|
+
SELLER: "seller"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const ReviewSchema = new Schema(
|
|
11
|
+
{
|
|
12
|
+
userId: {
|
|
13
|
+
type: Schema.Types.ObjectId,
|
|
14
|
+
ref: "users",
|
|
15
|
+
required: true
|
|
16
|
+
},
|
|
17
|
+
reviewType: {
|
|
18
|
+
type: String,
|
|
19
|
+
enum: Object.values(ReviewType),
|
|
20
|
+
required: true
|
|
21
|
+
},
|
|
22
|
+
productId: {
|
|
23
|
+
type: Schema.Types.ObjectId,
|
|
24
|
+
ref: "productlistings",
|
|
25
|
+
required: function() {
|
|
26
|
+
return this.reviewType === ReviewType.PRODUCT;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
sellerId: {
|
|
30
|
+
type: Schema.Types.ObjectId,
|
|
31
|
+
ref: "sellers",
|
|
32
|
+
required: function() {
|
|
33
|
+
return this.reviewType === ReviewType.SELLER;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
rating: {
|
|
37
|
+
type: Number,
|
|
38
|
+
required: true,
|
|
39
|
+
min: 1,
|
|
40
|
+
max: 5
|
|
41
|
+
},
|
|
42
|
+
content: {
|
|
43
|
+
type: String,
|
|
44
|
+
required: true,
|
|
45
|
+
trim: true,
|
|
46
|
+
maxlength: 1000
|
|
47
|
+
},
|
|
48
|
+
helpfulVotes: {
|
|
49
|
+
type: [{
|
|
50
|
+
userId: {
|
|
51
|
+
type: Schema.Types.ObjectId,
|
|
52
|
+
ref: "users",
|
|
53
|
+
required: true
|
|
54
|
+
},
|
|
55
|
+
voteType: {
|
|
56
|
+
type: String,
|
|
57
|
+
enum: ["helpful", "not_helpful"],
|
|
58
|
+
required: true
|
|
59
|
+
},
|
|
60
|
+
createdAt: {
|
|
61
|
+
type: Date,
|
|
62
|
+
default: Date.now
|
|
63
|
+
}
|
|
64
|
+
}],
|
|
65
|
+
default: []
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
helpfulCount: {
|
|
69
|
+
type: Number,
|
|
70
|
+
default: 0,
|
|
71
|
+
min: 0
|
|
72
|
+
},
|
|
73
|
+
notHelpfulCount: {
|
|
74
|
+
type: Number,
|
|
75
|
+
default: 0,
|
|
76
|
+
min: 0
|
|
77
|
+
},
|
|
78
|
+
images: {
|
|
79
|
+
type: [String], // Array of image URLs
|
|
80
|
+
default: [],
|
|
81
|
+
validate: {
|
|
82
|
+
validator: function(array) {
|
|
83
|
+
return array.length <= 5;
|
|
84
|
+
},
|
|
85
|
+
message: 'Cannot upload more than 5 images per review'
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
timestamps: true,
|
|
91
|
+
toJSON: { virtuals: true },
|
|
92
|
+
toObject: { virtuals: true }
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Indexes
|
|
97
|
+
ReviewSchema.index({ productId: 1 });
|
|
98
|
+
ReviewSchema.index({ sellerId: 1 });
|
|
99
|
+
ReviewSchema.index({ userId: 1 });
|
|
100
|
+
ReviewSchema.index({ reviewType: 1 });
|
|
101
|
+
ReviewSchema.index({ "helpfulVotes.userId": 1 });
|
|
102
|
+
|
|
103
|
+
// Virtual for total feedback count
|
|
104
|
+
ReviewSchema.virtual('totalFeedback').get(function() {
|
|
105
|
+
return this.helpfulCount + this.notHelpfulCount;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Method to check if a user has voted
|
|
109
|
+
ReviewSchema.methods.hasUserVoted = function(userId) {
|
|
110
|
+
return this.helpfulVotes.some(vote => vote.userId.equals(userId));
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Method to get user's vote type
|
|
114
|
+
ReviewSchema.methods.getUserVoteType = function(userId) {
|
|
115
|
+
const vote = this.helpfulVotes.find(vote => vote.userId.equals(userId));
|
|
116
|
+
return vote ? vote.voteType : null;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Safe export to prevent OverwriteModelError
|
|
120
|
+
const Review = mongoose.models.reviews || mongoose.model("reviews", ReviewSchema);
|
|
121
|
+
export { Review, ReviewType };
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
-
|
|
3
|
-
const searchAnalyticsSchema = new mongoose.Schema({
|
|
4
|
-
searchTerm: { type: String, required: true, trim: true },
|
|
5
|
-
category: {
|
|
6
|
-
type: String,
|
|
7
|
-
enum: ["shows", "videos", "products", "users", "all"],
|
|
8
|
-
default: "all"
|
|
9
|
-
},
|
|
10
|
-
userId: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: false },
|
|
11
|
-
resultCount: { type: Number, default: 0 },
|
|
12
|
-
ipAddress: { type: String },
|
|
13
|
-
deviceInfo: { type: String },
|
|
14
|
-
location: {
|
|
15
|
-
city: { type: String },
|
|
16
|
-
region: { type: String },
|
|
17
|
-
country: { type: String }
|
|
18
|
-
},
|
|
19
|
-
createdAt: { type: Date, default: Date.now }
|
|
20
|
-
});
|
|
21
|
-
// Safe export to prevent OverwriteModelError
|
|
22
|
-
const SearchAnalytics = mongoose.models.SearchAnalytics || mongoose.model("SearchAnalytics", searchAnalyticsSchema);
|
|
23
|
-
export default SearchAnalytics;
|
|
1
|
+
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
const searchAnalyticsSchema = new mongoose.Schema({
|
|
4
|
+
searchTerm: { type: String, required: true, trim: true },
|
|
5
|
+
category: {
|
|
6
|
+
type: String,
|
|
7
|
+
enum: ["shows", "videos", "products", "users", "all"],
|
|
8
|
+
default: "all"
|
|
9
|
+
},
|
|
10
|
+
userId: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: false },
|
|
11
|
+
resultCount: { type: Number, default: 0 },
|
|
12
|
+
ipAddress: { type: String },
|
|
13
|
+
deviceInfo: { type: String },
|
|
14
|
+
location: {
|
|
15
|
+
city: { type: String },
|
|
16
|
+
region: { type: String },
|
|
17
|
+
country: { type: String }
|
|
18
|
+
},
|
|
19
|
+
createdAt: { type: Date, default: Date.now }
|
|
20
|
+
});
|
|
21
|
+
// Safe export to prevent OverwriteModelError
|
|
22
|
+
const SearchAnalytics = mongoose.models.SearchAnalytics || mongoose.model("SearchAnalytics", searchAnalyticsSchema);
|
|
23
|
+
export default SearchAnalytics;
|