@organizasyon/meeting-nanaman-app-backend 1.0.0
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/dist/controllers/auth/index.d.ts +65 -0
- package/dist/controllers/auth/index.js +525 -0
- package/dist/controllers/employees/index.d.ts +38 -0
- package/dist/controllers/employees/index.js +185 -0
- package/dist/controllers/health/index.d.ts +9 -0
- package/dist/controllers/health/index.js +42 -0
- package/dist/controllers/index.d.ts +16 -0
- package/dist/controllers/index.js +19 -0
- package/dist/controllers/meetings/index.d.ts +23 -0
- package/dist/controllers/meetings/index.js +233 -0
- package/dist/controllers/modules/index.d.ts +5 -0
- package/dist/controllers/modules/index.js +104 -0
- package/dist/controllers/users/index.d.ts +103 -0
- package/dist/controllers/users/index.js +841 -0
- package/dist/data/modules.json +94 -0
- package/dist/database/config/index.d.ts +2 -0
- package/dist/database/config/index.js +32 -0
- package/dist/database/index.d.ts +9 -0
- package/dist/database/index.js +9 -0
- package/dist/database/seeder/employees/index.d.ts +1 -0
- package/dist/database/seeder/employees/index.js +40 -0
- package/dist/database/seeder/index.d.ts +4 -0
- package/dist/database/seeder/index.js +20 -0
- package/dist/database/seeder/users/index.d.ts +1 -0
- package/dist/database/seeder/users/index.js +46 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +23 -0
- package/dist/jobs/index.d.ts +1 -0
- package/dist/jobs/index.js +18 -0
- package/dist/jobs/mailer/index.d.ts +4 -0
- package/dist/jobs/mailer/index.js +186 -0
- package/dist/jobs/mailer/templates/auth.d.ts +11 -0
- package/dist/jobs/mailer/templates/auth.js +117 -0
- package/dist/jobs/mailer/templates/index.d.ts +1 -0
- package/dist/jobs/mailer/templates/index.js +17 -0
- package/dist/jobs/queues/index.d.ts +3 -0
- package/dist/jobs/queues/index.js +115 -0
- package/dist/middlewares/audit/index.d.ts +0 -0
- package/dist/middlewares/audit/index.js +1 -0
- package/dist/middlewares/guard/index.d.ts +11 -0
- package/dist/middlewares/guard/index.js +53 -0
- package/dist/middlewares/index.d.ts +2 -0
- package/dist/middlewares/index.js +7 -0
- package/dist/middlewares/meeting.d.ts +9 -0
- package/dist/middlewares/meeting.js +34 -0
- package/dist/models/employees/index.d.ts +83 -0
- package/dist/models/employees/index.js +70 -0
- package/dist/models/index.d.ts +570 -0
- package/dist/models/index.js +17 -0
- package/dist/models/meetings/index.d.ts +227 -0
- package/dist/models/meetings/index.js +112 -0
- package/dist/models/passkeys/index.d.ts +77 -0
- package/dist/models/passkeys/index.js +55 -0
- package/dist/models/queues/index.d.ts +77 -0
- package/dist/models/queues/index.js +57 -0
- package/dist/models/users/index.d.ts +107 -0
- package/dist/models/users/index.js +92 -0
- package/dist/queues/index.d.ts +1 -0
- package/dist/queues/index.js +17 -0
- package/dist/queues/mailer/index.d.ts +4 -0
- package/dist/queues/mailer/index.js +74 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/notifications.d.ts +2 -0
- package/dist/utils/notifications.js +51 -0
- package/package.json +39 -0
- package/public/health.html +215 -0
- package/src/controllers/auth/index.ts +609 -0
- package/src/controllers/employees/index.ts +210 -0
- package/src/controllers/health/index.ts +41 -0
- package/src/controllers/index.ts +9 -0
- package/src/controllers/meetings/index.ts +251 -0
- package/src/controllers/modules/index.ts +74 -0
- package/src/controllers/users/index.ts +981 -0
- package/src/data/modules.json +94 -0
- package/src/database/config/index.ts +26 -0
- package/src/database/index.ts +5 -0
- package/src/database/seeder/employees/index.ts +35 -0
- package/src/database/seeder/index.ts +18 -0
- package/src/database/seeder/users/index.ts +44 -0
- package/src/index.ts +10 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/mailer/index.ts +154 -0
- package/src/jobs/mailer/templates/auth.ts +113 -0
- package/src/jobs/mailer/templates/index.ts +1 -0
- package/src/jobs/queues/index.ts +125 -0
- package/src/middlewares/audit/index.ts +0 -0
- package/src/middlewares/guard/index.ts +64 -0
- package/src/middlewares/index.ts +5 -0
- package/src/middlewares/meeting.ts +45 -0
- package/src/models/employees/index.ts +70 -0
- package/src/models/index.ts +8 -0
- package/src/models/meetings/index.ts +112 -0
- package/src/models/passkeys/index.ts +53 -0
- package/src/models/queues/index.ts +55 -0
- package/src/models/users/index.ts +92 -0
- package/src/queues/index.ts +1 -0
- package/src/queues/mailer/index.ts +80 -0
- package/src/types/index.ts +38 -0
- package/src/utils/notifications.ts +66 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./auth"), exports);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addToQueue = exports.processPasswordResetQueue = exports.processEmailQueue = void 0;
|
|
7
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
|
+
const mailer_1 = require("../mailer");
|
|
9
|
+
const queues_1 = __importDefault(require("../../models/queues"));
|
|
10
|
+
const redis = new ioredis_1.default({
|
|
11
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
12
|
+
port: Number(process.env.REDIS_PORT) || 6379,
|
|
13
|
+
password: process.env.REDIS_PASSWORD,
|
|
14
|
+
db: 0,
|
|
15
|
+
});
|
|
16
|
+
const processEmailQueue = async () => {
|
|
17
|
+
try {
|
|
18
|
+
const pendingEmails = await queues_1.default.find({
|
|
19
|
+
type: 'email',
|
|
20
|
+
status: 'pending',
|
|
21
|
+
deleted_at: null
|
|
22
|
+
})
|
|
23
|
+
.sort({ created_at: 1 })
|
|
24
|
+
.limit(10)
|
|
25
|
+
.lean()
|
|
26
|
+
.exec();
|
|
27
|
+
for (const emailJob of pendingEmails) {
|
|
28
|
+
try {
|
|
29
|
+
const { data } = emailJob;
|
|
30
|
+
if (data.action === 'password_changed') {
|
|
31
|
+
await (0, mailer_1.sendPasswordChangedEmail)(data.email, data.name);
|
|
32
|
+
}
|
|
33
|
+
else if (data.action === 'passkey_registered') {
|
|
34
|
+
await (0, mailer_1.sendPasskeyRegisteredEmail)(data.email, data.name, data.device_name || 'Unknown Device');
|
|
35
|
+
}
|
|
36
|
+
// Update queue status
|
|
37
|
+
await queues_1.default.updateOne({ _id: emailJob._id }, {
|
|
38
|
+
status: 'completed',
|
|
39
|
+
processed_at: Date.now(),
|
|
40
|
+
updated_at: Date.now()
|
|
41
|
+
});
|
|
42
|
+
console.log(`Email sent successfully to ${data.email}`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error(`Failed to send email to ${emailJob.data.email}:`, error);
|
|
46
|
+
// Update queue status to failed
|
|
47
|
+
await queues_1.default.updateOne({ _id: emailJob._id }, {
|
|
48
|
+
status: 'failed',
|
|
49
|
+
error_message: String(error),
|
|
50
|
+
attempts: emailJob.attempts + 1,
|
|
51
|
+
updated_at: Date.now()
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error('Error processing email queue:', error);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.processEmailQueue = processEmailQueue;
|
|
61
|
+
const processPasswordResetQueue = async () => {
|
|
62
|
+
try {
|
|
63
|
+
const pendingResets = await queues_1.default.find({
|
|
64
|
+
type: 'password_reset',
|
|
65
|
+
status: 'pending',
|
|
66
|
+
deleted_at: null
|
|
67
|
+
})
|
|
68
|
+
.sort({ created_at: 1 })
|
|
69
|
+
.limit(10)
|
|
70
|
+
.lean()
|
|
71
|
+
.exec();
|
|
72
|
+
for (const resetJob of pendingResets) {
|
|
73
|
+
try {
|
|
74
|
+
const { data } = resetJob;
|
|
75
|
+
await (0, mailer_1.sendPasswordResetEmail)(data.email, data.name, data.reset_token);
|
|
76
|
+
// Update queue status
|
|
77
|
+
await queues_1.default.updateOne({ _id: resetJob._id }, {
|
|
78
|
+
status: 'completed',
|
|
79
|
+
processed_at: Date.now(),
|
|
80
|
+
updated_at: Date.now()
|
|
81
|
+
});
|
|
82
|
+
console.log(`Password reset email sent successfully to ${data.email}`);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error(`Failed to send password reset email to ${resetJob.data.email}:`, error);
|
|
86
|
+
// Update queue status to failed
|
|
87
|
+
await queues_1.default.updateOne({ _id: resetJob._id }, {
|
|
88
|
+
status: 'failed',
|
|
89
|
+
error_message: String(error),
|
|
90
|
+
attempts: resetJob.attempts + 1,
|
|
91
|
+
updated_at: Date.now()
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error('Error processing password reset queue:', error);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
exports.processPasswordResetQueue = processPasswordResetQueue;
|
|
101
|
+
const addToQueue = async (type, data) => {
|
|
102
|
+
try {
|
|
103
|
+
await queues_1.default.create({
|
|
104
|
+
type,
|
|
105
|
+
data,
|
|
106
|
+
status: 'pending',
|
|
107
|
+
created_at: Date.now()
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error('Error adding to queue:', error);
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
exports.addToQueue = addToQueue;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
interface AuthenticatedRequest extends Request {
|
|
3
|
+
user?: {
|
|
4
|
+
userId: string;
|
|
5
|
+
email: string;
|
|
6
|
+
role: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare const authenticateToken: (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
|
|
10
|
+
export declare const requireRole: (roles: string[]) => (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
|
|
11
|
+
export default authenticateToken;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.requireRole = exports.authenticateToken = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const authenticateToken = (req, res, next) => {
|
|
9
|
+
const authHeader = req.headers['authorization'];
|
|
10
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
11
|
+
if (!token) {
|
|
12
|
+
res.status(401).json({ message: 'Access token required' });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const jwtSecret = process.env.JWT_SECRET;
|
|
16
|
+
if (!jwtSecret) {
|
|
17
|
+
console.error('JWT_SECRET environment variable is required');
|
|
18
|
+
res.status(500).json({ message: 'Server configuration error' });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
jsonwebtoken_1.default.verify(token, jwtSecret, (err, decoded) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
if (err.name === 'TokenExpiredError') {
|
|
24
|
+
res.status(401).json({ message: 'Token expired' });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
res.status(403).json({ message: 'Invalid token' });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
req.user = {
|
|
31
|
+
userId: decoded.userId,
|
|
32
|
+
email: decoded.email,
|
|
33
|
+
role: decoded.role
|
|
34
|
+
};
|
|
35
|
+
next();
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
exports.authenticateToken = authenticateToken;
|
|
39
|
+
const requireRole = (roles) => {
|
|
40
|
+
return (req, res, next) => {
|
|
41
|
+
if (!req.user) {
|
|
42
|
+
res.status(401).json({ message: 'Authentication required' });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!roles.includes(req.user.role)) {
|
|
46
|
+
res.status(403).json({ message: 'Insufficient permissions' });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
next();
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
exports.requireRole = requireRole;
|
|
53
|
+
exports.default = exports.authenticateToken;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireRole = exports.authenticateToken = void 0;
|
|
4
|
+
// Import middleware modules when they are implemented
|
|
5
|
+
const guard_1 = require("./guard");
|
|
6
|
+
Object.defineProperty(exports, "authenticateToken", { enumerable: true, get: function () { return guard_1.authenticateToken; } });
|
|
7
|
+
Object.defineProperty(exports, "requireRole", { enumerable: true, get: function () { return guard_1.requireRole; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
export declare const canJoinMeeting: (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Request {
|
|
6
|
+
meeting?: any;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canJoinMeeting = void 0;
|
|
4
|
+
const models_1 = require("../models");
|
|
5
|
+
const canJoinMeeting = async (req, res, next) => {
|
|
6
|
+
try {
|
|
7
|
+
const { meetingId } = req.params;
|
|
8
|
+
const userId = req.user?._id;
|
|
9
|
+
const meeting = await models_1.Meetings.findById(meetingId);
|
|
10
|
+
if (!meeting) {
|
|
11
|
+
return res.status(404).json({ error: 'Meeting not found' });
|
|
12
|
+
}
|
|
13
|
+
if (!meeting.is_active) {
|
|
14
|
+
return res.status(403).json({ error: 'Meeting is not active' });
|
|
15
|
+
}
|
|
16
|
+
// Check if user is host or participant
|
|
17
|
+
const isHost = meeting.host_id.toString() === userId;
|
|
18
|
+
const isParticipant = meeting.participants.some((p) => p.user_id.toString() === userId);
|
|
19
|
+
if (!isHost && !isParticipant) {
|
|
20
|
+
return res.status(403).json({ error: 'You are not authorized to join this meeting' });
|
|
21
|
+
}
|
|
22
|
+
// Check meeting capacity
|
|
23
|
+
if (meeting.participant_count >= meeting.max_participants && !isHost) {
|
|
24
|
+
return res.status(403).json({ error: 'Meeting is full' });
|
|
25
|
+
}
|
|
26
|
+
req.meeting = meeting;
|
|
27
|
+
next();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Error in canJoinMeeting middleware:', error);
|
|
31
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
exports.canJoinMeeting = canJoinMeeting;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
declare const _default: mongoose.Model<{
|
|
3
|
+
first_name: string;
|
|
4
|
+
last_name: string;
|
|
5
|
+
created_at: number;
|
|
6
|
+
updated_at: number;
|
|
7
|
+
deleted_at: number;
|
|
8
|
+
middle_name?: string | null | undefined;
|
|
9
|
+
address?: string | null | undefined;
|
|
10
|
+
contact_number?: string | null | undefined;
|
|
11
|
+
email?: string | null | undefined;
|
|
12
|
+
position?: string | null | undefined;
|
|
13
|
+
department?: string | null | undefined;
|
|
14
|
+
}, {}, {}, {}, mongoose.Document<unknown, {}, {
|
|
15
|
+
first_name: string;
|
|
16
|
+
last_name: string;
|
|
17
|
+
created_at: number;
|
|
18
|
+
updated_at: number;
|
|
19
|
+
deleted_at: number;
|
|
20
|
+
middle_name?: string | null | undefined;
|
|
21
|
+
address?: string | null | undefined;
|
|
22
|
+
contact_number?: string | null | undefined;
|
|
23
|
+
email?: string | null | undefined;
|
|
24
|
+
position?: string | null | undefined;
|
|
25
|
+
department?: string | null | undefined;
|
|
26
|
+
}, {}, mongoose.DefaultSchemaOptions> & {
|
|
27
|
+
first_name: string;
|
|
28
|
+
last_name: string;
|
|
29
|
+
created_at: number;
|
|
30
|
+
updated_at: number;
|
|
31
|
+
deleted_at: number;
|
|
32
|
+
middle_name?: string | null | undefined;
|
|
33
|
+
address?: string | null | undefined;
|
|
34
|
+
contact_number?: string | null | undefined;
|
|
35
|
+
email?: string | null | undefined;
|
|
36
|
+
position?: string | null | undefined;
|
|
37
|
+
department?: string | null | undefined;
|
|
38
|
+
} & {
|
|
39
|
+
_id: mongoose.Types.ObjectId;
|
|
40
|
+
} & {
|
|
41
|
+
__v: number;
|
|
42
|
+
}, mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, {
|
|
43
|
+
first_name: string;
|
|
44
|
+
last_name: string;
|
|
45
|
+
created_at: number;
|
|
46
|
+
updated_at: number;
|
|
47
|
+
deleted_at: number;
|
|
48
|
+
middle_name?: string | null | undefined;
|
|
49
|
+
address?: string | null | undefined;
|
|
50
|
+
contact_number?: string | null | undefined;
|
|
51
|
+
email?: string | null | undefined;
|
|
52
|
+
position?: string | null | undefined;
|
|
53
|
+
department?: string | null | undefined;
|
|
54
|
+
}, mongoose.Document<unknown, {}, mongoose.FlatRecord<{
|
|
55
|
+
first_name: string;
|
|
56
|
+
last_name: string;
|
|
57
|
+
created_at: number;
|
|
58
|
+
updated_at: number;
|
|
59
|
+
deleted_at: number;
|
|
60
|
+
middle_name?: string | null | undefined;
|
|
61
|
+
address?: string | null | undefined;
|
|
62
|
+
contact_number?: string | null | undefined;
|
|
63
|
+
email?: string | null | undefined;
|
|
64
|
+
position?: string | null | undefined;
|
|
65
|
+
department?: string | null | undefined;
|
|
66
|
+
}>, {}, mongoose.ResolveSchemaOptions<mongoose.DefaultSchemaOptions>> & mongoose.FlatRecord<{
|
|
67
|
+
first_name: string;
|
|
68
|
+
last_name: string;
|
|
69
|
+
created_at: number;
|
|
70
|
+
updated_at: number;
|
|
71
|
+
deleted_at: number;
|
|
72
|
+
middle_name?: string | null | undefined;
|
|
73
|
+
address?: string | null | undefined;
|
|
74
|
+
contact_number?: string | null | undefined;
|
|
75
|
+
email?: string | null | undefined;
|
|
76
|
+
position?: string | null | undefined;
|
|
77
|
+
department?: string | null | undefined;
|
|
78
|
+
}> & {
|
|
79
|
+
_id: mongoose.Types.ObjectId;
|
|
80
|
+
} & {
|
|
81
|
+
__v: number;
|
|
82
|
+
}>>;
|
|
83
|
+
export default _default;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
7
|
+
const employeeSchema = new mongoose_1.default.Schema({
|
|
8
|
+
first_name: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
trim: true,
|
|
12
|
+
},
|
|
13
|
+
middle_name: {
|
|
14
|
+
type: String,
|
|
15
|
+
trim: true,
|
|
16
|
+
},
|
|
17
|
+
last_name: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true,
|
|
20
|
+
trim: true,
|
|
21
|
+
},
|
|
22
|
+
address: {
|
|
23
|
+
type: String,
|
|
24
|
+
trim: true,
|
|
25
|
+
},
|
|
26
|
+
contact_number: {
|
|
27
|
+
type: String,
|
|
28
|
+
trim: true,
|
|
29
|
+
},
|
|
30
|
+
email: {
|
|
31
|
+
type: String,
|
|
32
|
+
trim: true,
|
|
33
|
+
index: true,
|
|
34
|
+
},
|
|
35
|
+
position: {
|
|
36
|
+
type: String,
|
|
37
|
+
trim: true,
|
|
38
|
+
},
|
|
39
|
+
department: {
|
|
40
|
+
type: String,
|
|
41
|
+
trim: true,
|
|
42
|
+
},
|
|
43
|
+
created_at: {
|
|
44
|
+
type: Number,
|
|
45
|
+
default: () => Date.now(),
|
|
46
|
+
},
|
|
47
|
+
updated_at: {
|
|
48
|
+
type: Number,
|
|
49
|
+
default: () => Date.now(),
|
|
50
|
+
},
|
|
51
|
+
deleted_at: {
|
|
52
|
+
type: Number,
|
|
53
|
+
default: null,
|
|
54
|
+
index: true,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// Virtual for full name
|
|
58
|
+
employeeSchema.virtual('full_name').get(function () {
|
|
59
|
+
let fullName = `${this.first_name} ${this.last_name}`;
|
|
60
|
+
if (this.middle_name) {
|
|
61
|
+
fullName = `${this.first_name} ${this.middle_name} ${this.last_name}`;
|
|
62
|
+
}
|
|
63
|
+
return fullName;
|
|
64
|
+
});
|
|
65
|
+
// Ensure virtual fields are included in JSON output
|
|
66
|
+
employeeSchema.set('toJSON', { virtuals: true });
|
|
67
|
+
employeeSchema.set('toObject', { virtuals: true });
|
|
68
|
+
// Compound indexes for better query performance
|
|
69
|
+
employeeSchema.index({ first_name: 1, last_name: 1 });
|
|
70
|
+
exports.default = mongoose_1.default.model('_employees', employeeSchema);
|