@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.
Files changed (101) hide show
  1. package/dist/controllers/auth/index.d.ts +65 -0
  2. package/dist/controllers/auth/index.js +525 -0
  3. package/dist/controllers/employees/index.d.ts +38 -0
  4. package/dist/controllers/employees/index.js +185 -0
  5. package/dist/controllers/health/index.d.ts +9 -0
  6. package/dist/controllers/health/index.js +42 -0
  7. package/dist/controllers/index.d.ts +16 -0
  8. package/dist/controllers/index.js +19 -0
  9. package/dist/controllers/meetings/index.d.ts +23 -0
  10. package/dist/controllers/meetings/index.js +233 -0
  11. package/dist/controllers/modules/index.d.ts +5 -0
  12. package/dist/controllers/modules/index.js +104 -0
  13. package/dist/controllers/users/index.d.ts +103 -0
  14. package/dist/controllers/users/index.js +841 -0
  15. package/dist/data/modules.json +94 -0
  16. package/dist/database/config/index.d.ts +2 -0
  17. package/dist/database/config/index.js +32 -0
  18. package/dist/database/index.d.ts +9 -0
  19. package/dist/database/index.js +9 -0
  20. package/dist/database/seeder/employees/index.d.ts +1 -0
  21. package/dist/database/seeder/employees/index.js +40 -0
  22. package/dist/database/seeder/index.d.ts +4 -0
  23. package/dist/database/seeder/index.js +20 -0
  24. package/dist/database/seeder/users/index.d.ts +1 -0
  25. package/dist/database/seeder/users/index.js +46 -0
  26. package/dist/index.d.ts +9 -0
  27. package/dist/index.js +23 -0
  28. package/dist/jobs/index.d.ts +1 -0
  29. package/dist/jobs/index.js +18 -0
  30. package/dist/jobs/mailer/index.d.ts +4 -0
  31. package/dist/jobs/mailer/index.js +186 -0
  32. package/dist/jobs/mailer/templates/auth.d.ts +11 -0
  33. package/dist/jobs/mailer/templates/auth.js +117 -0
  34. package/dist/jobs/mailer/templates/index.d.ts +1 -0
  35. package/dist/jobs/mailer/templates/index.js +17 -0
  36. package/dist/jobs/queues/index.d.ts +3 -0
  37. package/dist/jobs/queues/index.js +115 -0
  38. package/dist/middlewares/audit/index.d.ts +0 -0
  39. package/dist/middlewares/audit/index.js +1 -0
  40. package/dist/middlewares/guard/index.d.ts +11 -0
  41. package/dist/middlewares/guard/index.js +53 -0
  42. package/dist/middlewares/index.d.ts +2 -0
  43. package/dist/middlewares/index.js +7 -0
  44. package/dist/middlewares/meeting.d.ts +9 -0
  45. package/dist/middlewares/meeting.js +34 -0
  46. package/dist/models/employees/index.d.ts +83 -0
  47. package/dist/models/employees/index.js +70 -0
  48. package/dist/models/index.d.ts +570 -0
  49. package/dist/models/index.js +17 -0
  50. package/dist/models/meetings/index.d.ts +227 -0
  51. package/dist/models/meetings/index.js +112 -0
  52. package/dist/models/passkeys/index.d.ts +77 -0
  53. package/dist/models/passkeys/index.js +55 -0
  54. package/dist/models/queues/index.d.ts +77 -0
  55. package/dist/models/queues/index.js +57 -0
  56. package/dist/models/users/index.d.ts +107 -0
  57. package/dist/models/users/index.js +92 -0
  58. package/dist/queues/index.d.ts +1 -0
  59. package/dist/queues/index.js +17 -0
  60. package/dist/queues/mailer/index.d.ts +4 -0
  61. package/dist/queues/mailer/index.js +74 -0
  62. package/dist/types/index.d.ts +33 -0
  63. package/dist/types/index.js +2 -0
  64. package/dist/utils/notifications.d.ts +2 -0
  65. package/dist/utils/notifications.js +51 -0
  66. package/package.json +39 -0
  67. package/public/health.html +215 -0
  68. package/src/controllers/auth/index.ts +609 -0
  69. package/src/controllers/employees/index.ts +210 -0
  70. package/src/controllers/health/index.ts +41 -0
  71. package/src/controllers/index.ts +9 -0
  72. package/src/controllers/meetings/index.ts +251 -0
  73. package/src/controllers/modules/index.ts +74 -0
  74. package/src/controllers/users/index.ts +981 -0
  75. package/src/data/modules.json +94 -0
  76. package/src/database/config/index.ts +26 -0
  77. package/src/database/index.ts +5 -0
  78. package/src/database/seeder/employees/index.ts +35 -0
  79. package/src/database/seeder/index.ts +18 -0
  80. package/src/database/seeder/users/index.ts +44 -0
  81. package/src/index.ts +10 -0
  82. package/src/jobs/index.ts +2 -0
  83. package/src/jobs/mailer/index.ts +154 -0
  84. package/src/jobs/mailer/templates/auth.ts +113 -0
  85. package/src/jobs/mailer/templates/index.ts +1 -0
  86. package/src/jobs/queues/index.ts +125 -0
  87. package/src/middlewares/audit/index.ts +0 -0
  88. package/src/middlewares/guard/index.ts +64 -0
  89. package/src/middlewares/index.ts +5 -0
  90. package/src/middlewares/meeting.ts +45 -0
  91. package/src/models/employees/index.ts +70 -0
  92. package/src/models/index.ts +8 -0
  93. package/src/models/meetings/index.ts +112 -0
  94. package/src/models/passkeys/index.ts +53 -0
  95. package/src/models/queues/index.ts +55 -0
  96. package/src/models/users/index.ts +92 -0
  97. package/src/queues/index.ts +1 -0
  98. package/src/queues/mailer/index.ts +80 -0
  99. package/src/types/index.ts +38 -0
  100. package/src/utils/notifications.ts +66 -0
  101. 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,3 @@
1
+ export declare const processEmailQueue: () => Promise<void>;
2
+ export declare const processPasswordResetQueue: () => Promise<void>;
3
+ export declare const addToQueue: (type: string, data: any) => Promise<void>;
@@ -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,2 @@
1
+ import { authenticateToken, requireRole } from './guard';
2
+ export { authenticateToken, requireRole };
@@ -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);