other
This commit is contained in:
14
backend/models/BlockedUser.model.js
Normal file
14
backend/models/BlockedUser.model.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const BlockedUserSchema = new mongoose.Schema({
|
||||
telegramUserId: { type: Number, required: true, unique: true },
|
||||
reason: { type: String },
|
||||
blockedBy: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Staff",
|
||||
required: true
|
||||
},
|
||||
blockedAt: { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
export default mongoose.model("BlockedUser", BlockedUserSchema);
|
||||
10
backend/models/Buyer.model.js
Normal file
10
backend/models/Buyer.model.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
const BuyerSchema = new mongoose.Schema({
|
||||
telegramId: { type: Number, required: true, unique: true },
|
||||
username: { type: String, required: true },
|
||||
createdAt: { type: Date, default: Date.now },
|
||||
banned: { type: Boolean, default: false }
|
||||
});
|
||||
|
||||
export default mongoose.model('Buyer', BuyerSchema);
|
||||
68
backend/models/Chat.model.js
Normal file
68
backend/models/Chat.model.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const MessageSchema = new mongoose.Schema({
|
||||
sender: {
|
||||
type: String,
|
||||
enum: ["buyer", "vendor"],
|
||||
required: true
|
||||
},
|
||||
buyerId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
vendorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Vendor",
|
||||
required: true
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
attachments: [{
|
||||
type: String,
|
||||
required: false
|
||||
}],
|
||||
read: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
}
|
||||
});
|
||||
|
||||
const ChatSchema = new mongoose.Schema({
|
||||
buyerId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
vendorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Vendor",
|
||||
required: true
|
||||
},
|
||||
storeId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Store",
|
||||
required: true
|
||||
},
|
||||
messages: [MessageSchema],
|
||||
orderId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Order",
|
||||
required: false
|
||||
},
|
||||
lastUpdated: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
}
|
||||
});
|
||||
|
||||
// Create indexes for faster queries
|
||||
ChatSchema.index({ buyerId: 1, vendorId: 1 });
|
||||
ChatSchema.index({ vendorId: 1, lastUpdated: -1 });
|
||||
ChatSchema.index({ buyerId: 1, lastUpdated: -1 });
|
||||
|
||||
export default mongoose.model("Chat", ChatSchema);
|
||||
43
backend/models/Escrow.model.js
Normal file
43
backend/models/Escrow.model.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const EscrowSchema = new mongoose.Schema({
|
||||
orderId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Order",
|
||||
required: true,
|
||||
},
|
||||
buyerId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Buyer",
|
||||
required: true,
|
||||
},
|
||||
vendorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Vendor",
|
||||
required: true,
|
||||
},
|
||||
amount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0.01,
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
enum: ["ltc", "btc", "xmr"],
|
||||
required: true,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: ["held", "released", "disputed"],
|
||||
default: "held",
|
||||
},
|
||||
releaseDate: {
|
||||
type: Date,
|
||||
required: true,
|
||||
default: function () {
|
||||
return new Date(Date.now() + 8 * 24 * 60 * 60 * 1000); // Auto set to 8 days from now
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default mongoose.model("Escrow", EscrowSchema);
|
||||
40
backend/models/Invitation.model.js
Normal file
40
backend/models/Invitation.model.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const InvitationSchema = new mongoose.Schema({
|
||||
code: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
createdBy: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Staffs',
|
||||
required: true,
|
||||
},
|
||||
isUsed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
usedBy: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Vendor',
|
||||
default: null,
|
||||
},
|
||||
expiresAt: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
usedAt: {
|
||||
type: Date,
|
||||
default: null,
|
||||
}
|
||||
});
|
||||
|
||||
InvitationSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
||||
InvitationSchema.index({ code: 1 });
|
||||
|
||||
export default mongoose.model("Invitation", InvitationSchema);
|
||||
100
backend/models/Order.model.js
Normal file
100
backend/models/Order.model.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import mongoose from "mongoose";
|
||||
import AutoIncrement from "mongoose-sequence";
|
||||
|
||||
const connection = mongoose.connection;
|
||||
|
||||
const OrderSchema = new mongoose.Schema({
|
||||
orderId: { type: Number, unique: true },
|
||||
|
||||
vendorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Vendor",
|
||||
required: true,
|
||||
},
|
||||
storeId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Store",
|
||||
required: true,
|
||||
},
|
||||
|
||||
pgpAddress: { type: String, required: true },
|
||||
orderDate: { type: Date, default: Date.now, },
|
||||
txid: { type: Array, default: [] },
|
||||
|
||||
products: [
|
||||
{
|
||||
productId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Product",
|
||||
required: true,
|
||||
},
|
||||
quantity: { type: Number, required: true, min: 0.1 },
|
||||
pricePerUnit: { type: Number, required: true, min: 0.01 },
|
||||
totalItemPrice: { type: Number, required: true, min: 0.01 },
|
||||
},
|
||||
],
|
||||
|
||||
shippingMethod: { type: Object },
|
||||
|
||||
totalPrice: { type: Number, required: true, min: 0.01 },
|
||||
|
||||
// Promotion fields
|
||||
promotion: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Promotion",
|
||||
default: null
|
||||
},
|
||||
promotionCode: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
discountAmount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
min: 0
|
||||
},
|
||||
subtotalBeforeDiscount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
min: 0
|
||||
},
|
||||
|
||||
status: {
|
||||
type: String,
|
||||
enum: [
|
||||
"unpaid",
|
||||
"cancelled",
|
||||
"confirming",
|
||||
"paid",
|
||||
"shipped",
|
||||
"disputed",
|
||||
"completed",
|
||||
"acknowledged"
|
||||
],
|
||||
default: "unpaid",
|
||||
},
|
||||
|
||||
paymentAddress: { type: String, required: true },
|
||||
|
||||
wallet: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Wallet",
|
||||
},
|
||||
|
||||
cryptoTotal: { type: Number, required: true, default: 0 },
|
||||
//txid: { type: String, default: null },
|
||||
|
||||
telegramChatId: { type: String, default: null },
|
||||
telegramBuyerId: { type: String, default: null },
|
||||
telegramUsername: { type: String, default: null },
|
||||
trackingNumber: { type: String, default: null },
|
||||
|
||||
escrowExpiresAt: {
|
||||
type: Date,
|
||||
required: true,
|
||||
default: () => new Date(Date.now() + 8 * 24 * 60 * 60 * 1000),
|
||||
},
|
||||
});
|
||||
|
||||
OrderSchema.plugin(AutoIncrement(connection), { inc_field: "orderId" });
|
||||
export default mongoose.model("Order", OrderSchema);
|
||||
69
backend/models/Product.model.js
Normal file
69
backend/models/Product.model.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const ProductSchema = new mongoose.Schema({
|
||||
storeId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Store",
|
||||
required: true,
|
||||
},
|
||||
category: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
required: true,
|
||||
ref: "Store.categories"
|
||||
},
|
||||
|
||||
name: { type: String, required: true },
|
||||
description: { type: String },
|
||||
|
||||
unitType: {
|
||||
type: String,
|
||||
enum: ["pcs", "gr", "kg"],
|
||||
required: true,
|
||||
},
|
||||
|
||||
// Add inventory tracking fields
|
||||
stockTracking: { type: Boolean, default: true },
|
||||
currentStock: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validate: {
|
||||
validator: function(value) {
|
||||
return !this.stockTracking || value >= 0;
|
||||
},
|
||||
message: "Stock cannot be negative"
|
||||
}
|
||||
},
|
||||
lowStockThreshold: { type: Number, default: 10 },
|
||||
stockStatus: {
|
||||
type: String,
|
||||
enum: ["in_stock", "low_stock", "out_of_stock"],
|
||||
default: "out_of_stock"
|
||||
},
|
||||
|
||||
pricing: [
|
||||
{
|
||||
minQuantity: {
|
||||
type: Number,
|
||||
required: true,
|
||||
validate: {
|
||||
validator: function(value) {
|
||||
if (this.parent().unitType === "gr") {
|
||||
return value >= 0.1;
|
||||
}
|
||||
return value >= 1;
|
||||
},
|
||||
message: "Invalid minQuantity for unitType"
|
||||
}
|
||||
},
|
||||
pricePerUnit: {
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0.01
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
image: { type: String },
|
||||
});
|
||||
|
||||
export default mongoose.model("Product", ProductSchema);
|
||||
126
backend/models/Promotion.model.js
Normal file
126
backend/models/Promotion.model.js
Normal file
@@ -0,0 +1,126 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const PromotionSchema = new mongoose.Schema(
|
||||
{
|
||||
storeId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Store",
|
||||
required: [true, "Store ID is required"]
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
required: [true, "Promotion code is required"],
|
||||
trim: true,
|
||||
uppercase: true,
|
||||
minlength: [3, "Promotion code must be at least 3 characters"],
|
||||
maxlength: [20, "Promotion code cannot exceed 20 characters"]
|
||||
},
|
||||
discountType: {
|
||||
type: String,
|
||||
required: [true, "Discount type is required"],
|
||||
enum: {
|
||||
values: ["percentage", "fixed"],
|
||||
message: "Discount type must be either percentage or fixed"
|
||||
}
|
||||
},
|
||||
discountValue: {
|
||||
type: Number,
|
||||
required: [true, "Discount value is required"],
|
||||
validate: {
|
||||
validator: function(value) {
|
||||
if (this.discountType === "percentage") {
|
||||
return value > 0 && value <= 100;
|
||||
}
|
||||
return value > 0;
|
||||
},
|
||||
message: props =>
|
||||
props.value <= 0
|
||||
? "Discount value must be greater than 0"
|
||||
: "Percentage discount cannot exceed 100%"
|
||||
}
|
||||
},
|
||||
minOrderAmount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
min: [0, "Minimum order amount cannot be negative"]
|
||||
},
|
||||
maxUsage: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
usageCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
startDate: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
},
|
||||
endDate: {
|
||||
type: Date,
|
||||
default: null
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
trim: true,
|
||||
maxlength: [200, "Description cannot exceed 200 characters"]
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
// Compound index to ensure unique promo codes per store
|
||||
PromotionSchema.index({ storeId: 1, code: 1 }, { unique: true });
|
||||
|
||||
// Check if a promotion is valid and can be applied
|
||||
PromotionSchema.methods.isValid = function() {
|
||||
const now = new Date();
|
||||
|
||||
// Check if promotion is active
|
||||
if (!this.isActive) return false;
|
||||
|
||||
// Check if promotion has expired
|
||||
if (this.endDate && now > this.endDate) return false;
|
||||
|
||||
// Check if promotion has reached max usage (if set)
|
||||
if (this.maxUsage !== null && this.usageCount >= this.maxUsage) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Calculate discount amount for a given order total
|
||||
PromotionSchema.methods.calculateDiscount = function(orderTotal) {
|
||||
if (!this.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (orderTotal < this.minOrderAmount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let discountAmount = 0;
|
||||
|
||||
if (this.discountType === "percentage") {
|
||||
discountAmount = (orderTotal * this.discountValue) / 100;
|
||||
} else {
|
||||
// Fixed amount discount
|
||||
discountAmount = this.discountValue;
|
||||
|
||||
// Ensure discount doesn't exceed order total
|
||||
if (discountAmount > orderTotal) {
|
||||
discountAmount = orderTotal;
|
||||
}
|
||||
}
|
||||
|
||||
return parseFloat(discountAmount.toFixed(2));
|
||||
};
|
||||
|
||||
const Promotion = mongoose.model("Promotion", PromotionSchema);
|
||||
|
||||
export default Promotion;
|
||||
54
backend/models/PromotionUse.model.js
Normal file
54
backend/models/PromotionUse.model.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
const PromotionUseSchema = new mongoose.Schema(
|
||||
{
|
||||
promotionId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Promotion',
|
||||
required: [true, 'Promotion ID is required']
|
||||
},
|
||||
orderId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Order',
|
||||
required: [true, 'Order ID is required']
|
||||
},
|
||||
userId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'User',
|
||||
required: [true, 'User ID is required']
|
||||
},
|
||||
storeId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Store',
|
||||
required: [true, 'Store ID is required']
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
required: [true, 'Promotion code is required']
|
||||
},
|
||||
discountType: {
|
||||
type: String,
|
||||
enum: ['percentage', 'fixed'],
|
||||
required: [true, 'Discount type is required']
|
||||
},
|
||||
discountValue: {
|
||||
type: Number,
|
||||
required: [true, 'Discount value is required']
|
||||
},
|
||||
discountAmount: {
|
||||
type: Number,
|
||||
required: [true, 'Discount amount is required']
|
||||
},
|
||||
orderTotal: {
|
||||
type: Number,
|
||||
required: [true, 'Order total is required']
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
const PromotionUse = mongoose.model('PromotionUse', PromotionUseSchema);
|
||||
|
||||
export default PromotionUse;
|
||||
11
backend/models/Staff.model.js
Normal file
11
backend/models/Staff.model.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const StaffSchema = new mongoose.Schema({
|
||||
username: { type: String, required: true, unique: true },
|
||||
passwordHash: { type: String, required: true },
|
||||
role: { type: String, enum: ["admin", "moderator"], default: "moderator" },
|
||||
currentToken: { type: String, default: null },
|
||||
createdAt: { type: Date, default: Date.now },
|
||||
});
|
||||
|
||||
export default mongoose.model("Staff", StaffSchema);
|
||||
132
backend/models/Store.model.js
Normal file
132
backend/models/Store.model.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import mongoose from "mongoose";
|
||||
import { type } from "os";
|
||||
|
||||
const CategorySchema = new mongoose.Schema({
|
||||
_id: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
auto: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
parentId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
default: null
|
||||
}
|
||||
}, { _id: true });
|
||||
|
||||
const StoreSchema = new mongoose.Schema({
|
||||
vendorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Vendor",
|
||||
required: true
|
||||
},
|
||||
storeName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
welcomeMessage: {
|
||||
type: String,
|
||||
default: "Welcome to my store!"
|
||||
},
|
||||
telegramToken: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
pgpKey: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
},
|
||||
shipsFrom: {
|
||||
type: String,
|
||||
default: "UK",
|
||||
},
|
||||
shipsTo: {
|
||||
type: String,
|
||||
default: "UK",
|
||||
},
|
||||
categories: [CategorySchema],
|
||||
|
||||
shippingOptions: [
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
price: {
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
wallets:{
|
||||
type: Object,
|
||||
default: {
|
||||
"litecoin": "",
|
||||
"bitcoin": "",
|
||||
"monero":""
|
||||
}
|
||||
},
|
||||
|
||||
feeRate:{
|
||||
type: Number,
|
||||
default: 2
|
||||
}
|
||||
});
|
||||
|
||||
// Add a method to get category hierarchy
|
||||
StoreSchema.methods.getCategoryHierarchy = function() {
|
||||
const categories = this.categories.toObject();
|
||||
|
||||
// Helper function to build tree structure
|
||||
const buildTree = (parentId = null) => {
|
||||
return categories
|
||||
.filter(cat =>
|
||||
(!parentId && !cat.parentId) ||
|
||||
(cat.parentId?.toString() === parentId?.toString())
|
||||
)
|
||||
.map(cat => ({
|
||||
...cat,
|
||||
children: buildTree(cat._id)
|
||||
}));
|
||||
};
|
||||
|
||||
return buildTree();
|
||||
};
|
||||
|
||||
// Add validation to prevent circular references
|
||||
CategorySchema.pre('save', function(next) {
|
||||
if (!this.parentId) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const checkCircular = (categoryId, parentId) => {
|
||||
if (!parentId) return false;
|
||||
if (categoryId.toString() === parentId.toString()) return true;
|
||||
|
||||
const parent = this.parent().categories.id(parentId);
|
||||
if (!parent) return false;
|
||||
|
||||
return checkCircular(categoryId, parent.parentId);
|
||||
};
|
||||
|
||||
if (checkCircular(this._id, this.parentId)) {
|
||||
next(new Error('Circular reference detected in category hierarchy'));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
// Add index for better query performance
|
||||
StoreSchema.index({ 'categories.name': 1, 'categories.parentId': 1 });
|
||||
|
||||
const Store = mongoose.model("Store", StoreSchema);
|
||||
|
||||
export default Store;
|
||||
22
backend/models/TelegramUser.model.js
Normal file
22
backend/models/TelegramUser.model.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const { Schema, model, Types } = mongoose;
|
||||
|
||||
/**
|
||||
* Defines the schema for Telegram users.
|
||||
* - `telegramUserId`: Unique Telegram user ID.
|
||||
* - `stores`: Array of objects storing store references and chat IDs.
|
||||
* - `createdAt`: Timestamp for when the user was added.
|
||||
*/
|
||||
const TelegramUserSchema = new Schema({
|
||||
telegramUserId: { type: Number, required: true, unique: true },
|
||||
stores: [
|
||||
{
|
||||
store: { type: Types.ObjectId, ref: "Store", required: true },
|
||||
chatId: { type: Number, required: true }
|
||||
}
|
||||
],
|
||||
createdAt: { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
export default model("TelegramUser", TelegramUserSchema);
|
||||
13
backend/models/Vendor.model.js
Normal file
13
backend/models/Vendor.model.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const VendorSchema = new mongoose.Schema({
|
||||
username: { type: String, required: true, unique: true },
|
||||
passwordHash: { type: String, required: true },
|
||||
currentToken: { type: String, default: null },
|
||||
storeId: { type: mongoose.Schema.Types.ObjectId, ref: "Store", default: null },
|
||||
pgpKey: { type: String, default: ""},
|
||||
lastOnline: { type: Date, default: Date.now },
|
||||
createdAt: { type: Date, default: Date.now },
|
||||
});
|
||||
|
||||
export default mongoose.model("Vendor", VendorSchema);
|
||||
56
backend/models/Wallet.model.js
Normal file
56
backend/models/Wallet.model.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import mongoose from "mongoose";
|
||||
import crypto from "crypto";
|
||||
|
||||
// Set default values if environment variables are not available
|
||||
const encryptionKeyHex = process.env.ENCRYPTION_KEY || '48c66ee5a54e596e2029ea832a512401099533ece34cb0fbbb8c4023ca68ba8e';
|
||||
const encryptionIvHex = process.env.ENCRYPTION_IV || '539e26d426cd4bac9844a8e446d63ab1';
|
||||
|
||||
const algorithm = "aes-256-cbc";
|
||||
const encryptionKey = Buffer.from(encryptionKeyHex, "hex");
|
||||
const iv = Buffer.from(encryptionIvHex, "hex");
|
||||
|
||||
function encrypt(text) {
|
||||
const cipher = crypto.createCipheriv(algorithm, encryptionKey, iv);
|
||||
let encrypted = cipher.update(text, "utf8", "hex");
|
||||
encrypted += cipher.final("hex");
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
function decrypt(text) {
|
||||
const decipher = crypto.createDecipheriv(algorithm, encryptionKey, iv);
|
||||
let decrypted = decipher.update(text, "hex", "utf8");
|
||||
decrypted += decipher.final("utf8");
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
const WalletSchema = new mongoose.Schema({
|
||||
walletName: {
|
||||
type: String,
|
||||
},
|
||||
orderId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Order",
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
encryptedPrivateKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
WalletSchema.pre("save", function (next) {
|
||||
if (!this.isModified("encryptedPrivateKey")) return next();
|
||||
this.encryptedPrivateKey = encrypt(this.encryptedPrivateKey);
|
||||
next();
|
||||
});
|
||||
|
||||
WalletSchema.methods.getDecryptedPrivateKey = function () {
|
||||
return decrypt(this.encryptedPrivateKey);
|
||||
};
|
||||
|
||||
export default mongoose.model("Wallet", WalletSchema);
|
||||
Reference in New Issue
Block a user