Mark-Lasfar commited on
Commit
fe9d07e
ยท
1 Parent(s): 57b7b7d

Add GraphQL

Browse files
Files changed (1) hide show
  1. server.js +141 -44
server.js CHANGED
@@ -1465,7 +1465,10 @@ const postSchema = new mongoose.Schema({
1465
  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1466
  text: String,
1467
  createdAt: { type: Date, default: Date.now },
1468
- likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
 
 
 
1469
  edited: { type: Boolean, default: false },
1470
  editedAt: Date,
1471
 
@@ -1476,30 +1479,36 @@ const postSchema = new mongoose.Schema({
1476
  }],
1477
  reportCount: { type: Number, default: 0 },
1478
  hidden: { type: Boolean, default: false },
1479
- replies: [{
1480
- userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1481
- text: String,
1482
- createdAt: { type: Date, default: Date.now },
1483
- likes: [{
1484
- userId: {
1485
- type: mongoose.Schema.Types.ObjectId,
1486
- ref: 'User'
1487
- },
1488
- likedAt: {
1489
- type: Date,
1490
- default: Date.now
1491
- }
1492
- }],
1493
- edited: { type: Boolean, default: false },
1494
- editedAt: Date,
1495
- reports: [{
1496
- userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1497
- reason: { type: String, default: 'No reason provided' },
1498
- reportedAt: { type: Date, default: Date.now }
1499
- }],
1500
- reportCount: { type: Number, default: 0 },
1501
- hidden: { type: Boolean, default: false }
1502
- }]
 
 
 
 
 
 
1503
 
1504
 
1505
  }],
@@ -1537,6 +1546,7 @@ const postSchema = new mongoose.Schema({
1537
  updatedAt: { type: Date, default: Date.now }
1538
  });
1539
 
 
1540
  // Indexes for performance
1541
  postSchema.index({ userId: 1, createdAt: -1 });
1542
  postSchema.index({ createdAt: -1 });
@@ -1976,8 +1986,7 @@ const storySchema = new mongoose.Schema({
1976
  },
1977
  expiresAt: {
1978
  type: Date,
1979
- default: () => new Date(Date.now() + 24 * 60 * 60 * 1000),
1980
- index: true
1981
  }
1982
  });
1983
 
@@ -2275,8 +2284,7 @@ const storeSettingsSchema = new mongoose.Schema({
2275
  },
2276
  enabled: {
2277
  type: Boolean,
2278
- default: false,
2279
- index: true
2280
  },
2281
 
2282
  // ============================================
@@ -7038,10 +7046,31 @@ app.use('/api/login', loginLimiter);
7038
  async function generateTokens(user) {
7039
  user.refreshTokens = user.refreshTokens.filter(t => new Date(t.createdAt) > new Date(Date.now() - 30 * 24 * 60 * 60 * 1000));
7040
  if (user.refreshTokens.length >= 10) {
7041
- user.refreshTokens.shift(); // ุฅุฒุงู„ุฉ ุฃู‚ุฏู… token ู„ูˆ ูˆุตู„ุช ู„ู„ุญุฏ ุงู„ุฃู‚ุตู‰
7042
  }
7043
- const token = jwt.sign({ userId: user._id, isAdmin: user.isAdmin }, JWT_SECRET, { expiresIn: '30d' });
7044
- const refreshToken = jwt.sign({ userId: user._id }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '90d' });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7045
  user.refreshTokens.push({ token: refreshToken, createdAt: new Date() });
7046
  await user.save();
7047
  return { token, refreshToken };
@@ -7470,6 +7499,9 @@ app.post('/api/upload', authenticateToken, upload.single('file'), async (req, re
7470
  }
7471
  });
7472
 
 
 
 
7473
  app.post('/api/login', [
7474
  body('email').isEmail().withMessage('Invalid email format'),
7475
  body('password').notEmpty().withMessage('Password is required')
@@ -7487,8 +7519,25 @@ app.post('/api/login', [
7487
 
7488
  // โœ… ู„ูˆ ูƒุงู† ุฃุฏู…ู† โ†’ ุชุฎุทูŠ OTP
7489
  if (user.isAdmin) {
7490
- const token = jwt.sign({ userId: user._id, isAdmin: user.isAdmin }, JWT_SECRET, { expiresIn: '30d' });
7491
- const refreshToken = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '90d' });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7492
  user.refreshTokens.push({ token: refreshToken });
7493
  await user.save();
7494
  logger.info(`Admin login: ${email} - Token issued without OTP`);
@@ -7502,7 +7551,6 @@ app.post('/api/login', [
7502
  user.otpExpires = Date.now() + 10 * 60 * 1000;
7503
  await user.save();
7504
 
7505
- // ู†ุฑุณู„ ุงู„ู€ response ุนู„ู‰ ุทูˆู„
7506
  res.status(403).json({
7507
  error: 'Email not verified',
7508
  requiresVerification: true,
@@ -7510,7 +7558,6 @@ app.post('/api/login', [
7510
  message: 'Verification code sent to your email'
7511
  });
7512
 
7513
- // ุฅุฑุณุงู„ ุงู„ุฅูŠู…ูŠู„ ุนุจุฑ Brevo ููŠ ุงู„ุฎู„ููŠุฉ
7514
  setTimeout(async () => {
7515
  try {
7516
  await sendEmailWithBrevo(
@@ -7540,8 +7587,25 @@ app.post('/api/login', [
7540
  }
7541
 
7542
  // โœ… ุงู„ุฅูŠู…ูŠู„ ู…ูุนู„ โ†’ ุชูˆูƒู† ู…ุจุงุดุฑ
7543
- const token = jwt.sign({ userId: user._id, isAdmin: user.isAdmin }, JWT_SECRET, { expiresIn: '30d' });
7544
- const refreshToken = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '90d' });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7545
  user.refreshTokens.push({ token: refreshToken });
7546
  await user.save();
7547
  res.json({ token, refreshToken });
@@ -7552,6 +7616,7 @@ app.post('/api/login', [
7552
  }
7553
  });
7554
 
 
7555
  // ============================================
7556
  // POST /api/verify-email - ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ
7557
  // ============================================
@@ -7572,15 +7637,30 @@ app.post('/api/verify-email', [
7572
  return res.status(400).json({ error: 'Invalid or expired verification code' });
7573
  }
7574
 
7575
- // โœ… ุชูุนูŠู„ ุงู„ุญุณุงุจ
7576
  user.emailVerified = true;
7577
  user.otp = null;
7578
  user.otpExpires = null;
7579
  await user.save();
7580
 
7581
- // โœ… ุฅุตุฏุงุฑ ุชูˆูƒู† ู„ู„ู…ุณุชุฎุฏู…
7582
- const token = jwt.sign({ userId: user._id, isAdmin: user.isAdmin }, JWT_SECRET, { expiresIn: '30d' });
7583
- const refreshToken = jwt.sign({ userId: user._id }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '90d' });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7584
  user.refreshTokens.push({ token: refreshToken });
7585
  await user.save();
7586
 
@@ -7683,8 +7763,25 @@ app.post('/api/login/verify-otp', otpVerifyLimiter, async (req, res) => {
7683
  if (!user) {
7684
  return res.status(401).json({ error: 'Invalid or expired OTP' });
7685
  }
7686
- const token = jwt.sign({ userId: user._id, isAdmin: user.isAdmin }, JWT_SECRET, { expiresIn: '1h' });
7687
- const refreshToken = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '7d' });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7688
  user.refreshTokens.push({ token: refreshToken });
7689
  user.otp = null;
7690
  user.otpExpires = null;
 
1465
  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1466
  text: String,
1467
  createdAt: { type: Date, default: Date.now },
1468
+ likes: [{
1469
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1470
+ likedAt: { type: Date, default: Date.now }
1471
+ }],
1472
  edited: { type: Boolean, default: false },
1473
  editedAt: Date,
1474
 
 
1479
  }],
1480
  reportCount: { type: Number, default: 0 },
1481
  hidden: { type: Boolean, default: false },
1482
+ replies: [{
1483
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1484
+ text: String,
1485
+ createdAt: { type: Date, default: Date.now },
1486
+ likes: [{
1487
+ userId: {
1488
+ type: mongoose.Schema.Types.ObjectId,
1489
+ ref: 'User'
1490
+ },
1491
+ likedAt: {
1492
+ type: Date,
1493
+ default: Date.now
1494
+ }
1495
+ }],
1496
+ edited: { type: Boolean, default: false },
1497
+ editedAt: Date,
1498
+ reports: [{
1499
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
1500
+ reason: { type: String, default: 'No reason provided' },
1501
+ reportedAt: { type: Date, default: Date.now }
1502
+ }],
1503
+ reportCount: { type: Number, default: 0 },
1504
+ hidden: { type: Boolean, default: false },
1505
+
1506
+ // โœ… โœ… โœ… ุงู„ู…ูุชุงุญ: ุงู„ุฑุฏูˆุฏ ุชุญุช ุงู„ุฑุฏูˆุฏ (Self-Referencing)
1507
+ replies: {
1508
+ type: Array,
1509
+ default: []
1510
+ }
1511
+ }]
1512
 
1513
 
1514
  }],
 
1546
  updatedAt: { type: Date, default: Date.now }
1547
  });
1548
 
1549
+
1550
  // Indexes for performance
1551
  postSchema.index({ userId: 1, createdAt: -1 });
1552
  postSchema.index({ createdAt: -1 });
 
1986
  },
1987
  expiresAt: {
1988
  type: Date,
1989
+ default: () => new Date(Date.now() + 24 * 60 * 60 * 1000)
 
1990
  }
1991
  });
1992
 
 
2284
  },
2285
  enabled: {
2286
  type: Boolean,
2287
+ default: false
 
2288
  },
2289
 
2290
  // ============================================
 
7046
  async function generateTokens(user) {
7047
  user.refreshTokens = user.refreshTokens.filter(t => new Date(t.createdAt) > new Date(Date.now() - 30 * 24 * 60 * 60 * 1000));
7048
  if (user.refreshTokens.length >= 10) {
7049
+ user.refreshTokens.shift();
7050
  }
7051
+
7052
+ // โœ… โœ… โœ… ุฃุถู username ูˆ profile.nickname ููŠ ุงู„ู€ JWT
7053
+ const token = jwt.sign(
7054
+ {
7055
+ userId: user._id,
7056
+ isAdmin: user.isAdmin,
7057
+ username: user.username,
7058
+ 'profile.nickname': user.profile?.nickname || user.username
7059
+ },
7060
+ JWT_SECRET,
7061
+ { expiresIn: '30d' }
7062
+ );
7063
+
7064
+ const refreshToken = jwt.sign(
7065
+ {
7066
+ userId: user._id,
7067
+ username: user.username,
7068
+ 'profile.nickname': user.profile?.nickname || user.username
7069
+ },
7070
+ process.env.REFRESH_TOKEN_SECRET,
7071
+ { expiresIn: '90d' }
7072
+ );
7073
+
7074
  user.refreshTokens.push({ token: refreshToken, createdAt: new Date() });
7075
  await user.save();
7076
  return { token, refreshToken };
 
7499
  }
7500
  });
7501
 
7502
+ // ============================================
7503
+ // POST /api/login
7504
+ // ============================================
7505
  app.post('/api/login', [
7506
  body('email').isEmail().withMessage('Invalid email format'),
7507
  body('password').notEmpty().withMessage('Password is required')
 
7519
 
7520
  // โœ… ู„ูˆ ูƒุงู† ุฃุฏู…ู† โ†’ ุชุฎุทูŠ OTP
7521
  if (user.isAdmin) {
7522
+ const token = jwt.sign(
7523
+ {
7524
+ userId: user._id,
7525
+ isAdmin: user.isAdmin,
7526
+ username: user.username,
7527
+ 'profile.nickname': user.profile?.nickname || user.username
7528
+ },
7529
+ JWT_SECRET,
7530
+ { expiresIn: '30d' }
7531
+ );
7532
+ const refreshToken = jwt.sign(
7533
+ {
7534
+ userId: user._id,
7535
+ username: user.username,
7536
+ 'profile.nickname': user.profile?.nickname || user.username
7537
+ },
7538
+ JWT_SECRET,
7539
+ { expiresIn: '90d' }
7540
+ );
7541
  user.refreshTokens.push({ token: refreshToken });
7542
  await user.save();
7543
  logger.info(`Admin login: ${email} - Token issued without OTP`);
 
7551
  user.otpExpires = Date.now() + 10 * 60 * 1000;
7552
  await user.save();
7553
 
 
7554
  res.status(403).json({
7555
  error: 'Email not verified',
7556
  requiresVerification: true,
 
7558
  message: 'Verification code sent to your email'
7559
  });
7560
 
 
7561
  setTimeout(async () => {
7562
  try {
7563
  await sendEmailWithBrevo(
 
7587
  }
7588
 
7589
  // โœ… ุงู„ุฅูŠู…ูŠู„ ู…ูุนู„ โ†’ ุชูˆูƒู† ู…ุจุงุดุฑ
7590
+ const token = jwt.sign(
7591
+ {
7592
+ userId: user._id,
7593
+ isAdmin: user.isAdmin,
7594
+ username: user.username,
7595
+ 'profile.nickname': user.profile?.nickname || user.username
7596
+ },
7597
+ JWT_SECRET,
7598
+ { expiresIn: '30d' }
7599
+ );
7600
+ const refreshToken = jwt.sign(
7601
+ {
7602
+ userId: user._id,
7603
+ username: user.username,
7604
+ 'profile.nickname': user.profile?.nickname || user.username
7605
+ },
7606
+ JWT_SECRET,
7607
+ { expiresIn: '90d' }
7608
+ );
7609
  user.refreshTokens.push({ token: refreshToken });
7610
  await user.save();
7611
  res.json({ token, refreshToken });
 
7616
  }
7617
  });
7618
 
7619
+
7620
  // ============================================
7621
  // POST /api/verify-email - ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ
7622
  // ============================================
 
7637
  return res.status(400).json({ error: 'Invalid or expired verification code' });
7638
  }
7639
 
 
7640
  user.emailVerified = true;
7641
  user.otp = null;
7642
  user.otpExpires = null;
7643
  await user.save();
7644
 
7645
+ const token = jwt.sign(
7646
+ {
7647
+ userId: user._id,
7648
+ isAdmin: user.isAdmin,
7649
+ username: user.username,
7650
+ 'profile.nickname': user.profile?.nickname || user.username
7651
+ },
7652
+ JWT_SECRET,
7653
+ { expiresIn: '30d' }
7654
+ );
7655
+ const refreshToken = jwt.sign(
7656
+ {
7657
+ userId: user._id,
7658
+ username: user.username,
7659
+ 'profile.nickname': user.profile?.nickname || user.username
7660
+ },
7661
+ process.env.REFRESH_TOKEN_SECRET,
7662
+ { expiresIn: '90d' }
7663
+ );
7664
  user.refreshTokens.push({ token: refreshToken });
7665
  await user.save();
7666
 
 
7763
  if (!user) {
7764
  return res.status(401).json({ error: 'Invalid or expired OTP' });
7765
  }
7766
+ const token = jwt.sign(
7767
+ {
7768
+ userId: user._id,
7769
+ isAdmin: user.isAdmin,
7770
+ username: user.username,
7771
+ 'profile.nickname': user.profile?.nickname || user.username
7772
+ },
7773
+ JWT_SECRET,
7774
+ { expiresIn: '1h' }
7775
+ );
7776
+ const refreshToken = jwt.sign(
7777
+ {
7778
+ userId: user._id,
7779
+ username: user.username,
7780
+ 'profile.nickname': user.profile?.nickname || user.username
7781
+ },
7782
+ JWT_SECRET,
7783
+ { expiresIn: '7d' }
7784
+ );
7785
  user.refreshTokens.push({ token: refreshToken });
7786
  user.otp = null;
7787
  user.otpExpires = null;