Merge branch 'fea/dat-24042026-submission-management' of https://gits.techvanguard.vn/UKSOURCE/cms.lams into merge/toan-24042026

This commit is contained in:
2026-04-24 23:33:12 +07:00
18 changed files with 1534 additions and 54 deletions
+58
View File
@@ -0,0 +1,58 @@
const mongoose = require("mongoose");
const STATUSES = ["subscribed", "unsubscribed"];
const emailPattern = /^\S+@\S+\.\S+$/;
const newsletterSubscriptionSchema = new mongoose.Schema(
{
email: {
type: String,
required: [true, "Email is required"],
trim: true,
lowercase: true,
validate: {
validator(value) {
return emailPattern.test(value);
},
message: "Please enter a valid email",
},
},
status: {
type: String,
enum: STATUSES,
default: "subscribed",
},
pageUrl: {
type: String,
trim: true,
default: "",
},
ipAddress: {
type: String,
default: "",
},
userAgent: {
type: String,
default: "",
},
internalNote: {
type: String,
trim: true,
default: "",
maxlength: [2000, "Internal note cannot exceed 2000 characters"],
},
},
{
collection: "newsletter_subscriptions",
timestamps: true,
autoCreate: false,
autoIndex: false,
},
);
newsletterSubscriptionSchema.statics.STATUSES = STATUSES;
module.exports = mongoose.model(
"NewsletterSubscription",
newsletterSubscriptionSchema,
);
+85
View File
@@ -0,0 +1,85 @@
const mongoose = require("mongoose");
const SOURCES = ["home", "request", "contact", "partnership"];
const STATUSES = ["new", "contacted", "info_provided", "closed"];
const emailPattern = /^\S+@\S+\.\S+$/;
const phonePattern = /^[+()\d\s.-]{7,20}$/;
const submissionSchema = new mongoose.Schema(
{
source: {
type: String,
enum: SOURCES,
required: [true, "Source is required"],
},
pageUrl: {
type: String,
trim: true,
default: "",
},
name: {
type: String,
required: [true, "Name is required"],
trim: true,
maxlength: [160, "Name cannot exceed 160 characters"],
},
email: {
type: String,
default: "",
trim: true,
lowercase: true,
validate: {
validator(value) {
return !value || emailPattern.test(value);
},
message: "Please enter a valid email",
},
},
phone: {
type: String,
trim: true,
default: "",
validate: {
validator(value) {
return !value || phonePattern.test(value);
},
message: "Please enter a valid phone number",
},
},
payload: {
type: mongoose.Schema.Types.Mixed,
default: {},
},
status: {
type: String,
enum: STATUSES,
default: "new",
},
internalNote: {
type: String,
trim: true,
default: "",
maxlength: [2000, "Internal note cannot exceed 2000 characters"],
},
ipAddress: {
type: String,
default: "",
},
userAgent: {
type: String,
default: "",
},
},
{
collection: "submissions",
timestamps: true,
autoCreate: false,
autoIndex: false,
},
);
submissionSchema.statics.SOURCES = SOURCES;
submissionSchema.statics.STATUSES = STATUSES;
module.exports = mongoose.model("Submission", submissionSchema);