fix: comprehensive boolean compatibility for PostgreSQL and SQLite
- Add formatBoolean() usage to all boolean database queries - Fix 36 boolean comparisons across 18 backend files - Ensure compatibility between SQLite (0/1) and PostgreSQL (true/false) - Update all WHERE clauses and UPDATE operations with boolean values This completes the database compatibility fixes for production deployment. All boolean operations now work correctly with both database systems. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
This commit is contained in:
@@ -1,13 +1,18 @@
|
|||||||
# 📸 PicPeak - Open Source Photo Sharing for Events
|
# 📸 PicPeak - Open Source Photo Sharing for Events
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
<div align="center">
|
||||||
[](https://www.docker.com/)
|
<img src="docs/picpeak-logo.png" alt="PicPeak Logo" width="300" />
|
||||||
[](https://nodejs.org/)
|
|
||||||
[](https://reactjs.org/)
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://www.docker.com/)
|
||||||
|
[](https://nodejs.org/)
|
||||||
|
[](https://reactjs.org/)
|
||||||
|
</div>
|
||||||
|
|
||||||
**PicPeak** is a powerful, self-hosted open-source alternative to commercial photo-sharing platforms like PicDrop.com and Scrapbook.de. Designed specifically for photographers and event organizers, PicPeak makes it simple to share beautiful, time-limited photo galleries with clients while maintaining full control over your data and branding.
|
**PicPeak** is a powerful, self-hosted open-source alternative to commercial photo-sharing platforms like PicDrop.com and Scrapbook.de. Designed specifically for photographers and event organizers, PicPeak makes it simple to share beautiful, time-limited photo galleries with clients while maintaining full control over your data and branding.
|
||||||
|
|
||||||

|

|
||||||
|
> 📸 *Gallery preview will be updated soon with latest interface*
|
||||||
|
|
||||||
## 🌟 Why Choose PicPeak?
|
## 🌟 Why Choose PicPeak?
|
||||||
|
|
||||||
@@ -124,17 +129,34 @@ Found a security issue? Please email [email protected]
|
|||||||
|
|
||||||
## 📸 Screenshots
|
## 📸 Screenshots
|
||||||
|
|
||||||
|
### 🎛️ **Admin Dashboard**
|
||||||
|
Get a complete overview of your photo galleries, analytics, and system status.
|
||||||
|
|
||||||
|
<img src="docs/screenshot-dashboard.png" alt="PicPeak Admin Dashboard" width="800" />
|
||||||
|
|
||||||
|
### 📊 **Analytics & Insights**
|
||||||
|
Track gallery performance, view statistics, and monitor user engagement.
|
||||||
|
|
||||||
|
<img src="docs/screenshot-analytics.png" alt="PicPeak Analytics Dashboard" width="800" />
|
||||||
|
|
||||||
|
### 📁 **Event Management**
|
||||||
|
Organize and manage your photo galleries with intuitive event management tools.
|
||||||
|
|
||||||
|
<img src="docs/screenshots-events.png" alt="PicPeak Events Management" width="800" />
|
||||||
|
|
||||||
|
### ✨ **Key Interface Highlights**
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View Gallery Examples</summary>
|
<summary>👆 Click to see more interface details</summary>
|
||||||
|
|
||||||
### Admin Dashboard
|
#### What makes PicPeak's interface special:
|
||||||

|
|
||||||
|
|
||||||
### Client Gallery View
|
- **🎨 Clean Design**: Modern, photographer-friendly interface
|
||||||

|
- **📱 Responsive**: Perfect on desktop, tablet, and mobile
|
||||||
|
- **⚡ Fast Loading**: Optimized for quick photo browsing
|
||||||
### Mobile Experience
|
- **🔒 Secure Access**: Password-protected galleries with expiration
|
||||||

|
- **📤 Easy Uploads**: Drag & drop functionality for effortless photo management
|
||||||
|
- **🎯 Client-Focused**: Intuitive gallery experience for your clients
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { isTokenRevoked } = require('../utils/tokenRevocation');
|
const { isTokenRevoked } = require('../utils/tokenRevocation');
|
||||||
const logger = require('../utils/logger');
|
const logger = require('../utils/logger');
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ async function adminAuth(req, res, next) {
|
|||||||
|
|
||||||
// Check if admin still exists and is active
|
// Check if admin still exists and is active
|
||||||
const admin = await db('admin_users')
|
const admin = await db('admin_users')
|
||||||
.where({ id: decoded.id, is_active: true })
|
.where({ id: decoded.id, is_active: formatBoolean(true) })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const logger = require('../utils/logger');
|
const logger = require('../utils/logger');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +51,7 @@ async function adminAuth(req, res, next) {
|
|||||||
|
|
||||||
// Check if admin still exists and is active
|
// Check if admin still exists and is active
|
||||||
const admin = await db('admin_users')
|
const admin = await db('admin_users')
|
||||||
.where({ id: decoded.id, is_active: true })
|
.where({ id: decoded.id, is_active: formatBoolean(true) })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@@ -165,7 +166,7 @@ async function photoAuth(req, res, next) {
|
|||||||
// Allow both admin and gallery tokens
|
// Allow both admin and gallery tokens
|
||||||
if (decoded.type === 'admin') {
|
if (decoded.type === 'admin') {
|
||||||
const admin = await db('admin_users')
|
const admin = await db('admin_users')
|
||||||
.where({ id: decoded.id, is_active: true })
|
.where({ id: decoded.id, is_active: formatBoolean(true) })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
|
|
||||||
async function adminAuth(req, res, next) {
|
async function adminAuth(req, res, next) {
|
||||||
try {
|
try {
|
||||||
@@ -9,7 +10,7 @@ async function adminAuth(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
const admin = await db('admin_users').where({ id: decoded.id, is_active: true }).first();
|
const admin = await db('admin_users').where({ id: decoded.id, is_active: formatBoolean(true) }).first();
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
return res.status(401).json({ error: 'Invalid token' });
|
return res.status(401).json({ error: 'Invalid token' });
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
|
|
||||||
// Middleware to verify gallery access
|
// Middleware to verify gallery access
|
||||||
async function verifyGalleryAccess(req, res, next) {
|
async function verifyGalleryAccess(req, res, next) {
|
||||||
@@ -10,7 +11,7 @@ async function verifyGalleryAccess(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
const event = await db('events').where({ id: decoded.eventId, is_active: true }).first();
|
const event = await db('events').where({ id: decoded.eventId, is_active: formatBoolean(true) }).first();
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return res.status(404).json({ error: 'Gallery not found or expired' });
|
return res.status(404).json({ error: 'Gallery not found or expired' });
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
|
|
||||||
async function photoAuth(req, res, next) {
|
async function photoAuth(req, res, next) {
|
||||||
try {
|
try {
|
||||||
@@ -27,7 +28,7 @@ async function photoAuth(req, res, next) {
|
|||||||
if (decoded.type === 'gallery') {
|
if (decoded.type === 'gallery') {
|
||||||
// For thumbnails, we accept any valid gallery token
|
// For thumbnails, we accept any valid gallery token
|
||||||
if (!eventSlug) {
|
if (!eventSlug) {
|
||||||
const event = await db('events').where({ slug: decoded.eventSlug, is_active: true }).first();
|
const event = await db('events').where({ slug: decoded.eventSlug, is_active: formatBoolean(true) }).first();
|
||||||
if (event) {
|
if (event) {
|
||||||
req.event = event;
|
req.event = event;
|
||||||
return next();
|
return next();
|
||||||
@@ -35,7 +36,7 @@ async function photoAuth(req, res, next) {
|
|||||||
}
|
}
|
||||||
// For regular photos, check if token matches the event
|
// For regular photos, check if token matches the event
|
||||||
else if (decoded.eventSlug === eventSlug) {
|
else if (decoded.eventSlug === eventSlug) {
|
||||||
const event = await db('events').where({ slug: eventSlug, is_active: true }).first();
|
const event = await db('events').where({ slug: eventSlug, is_active: formatBoolean(true) }).first();
|
||||||
if (event) {
|
if (event) {
|
||||||
req.event = event;
|
req.event = event;
|
||||||
return next();
|
return next();
|
||||||
@@ -72,7 +73,7 @@ async function photoAuth(req, res, next) {
|
|||||||
return res.status(401).json({ error: 'Authentication required for thumbnails' });
|
return res.status(401).json({ error: 'Authentication required for thumbnails' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await db('events').where({ slug: eventSlug, is_active: true }).first();
|
const event = await db('events').where({ slug: eventSlug, is_active: formatBoolean(true) }).first();
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return res.status(404).json({ error: 'Gallery not found' });
|
return res.status(404).json({ error: 'Gallery not found' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const express = require('express');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
||||||
const archiver = require('archiver');
|
const archiver = require('archiver');
|
||||||
const AdmZip = require('adm-zip');
|
const AdmZip = require('adm-zip');
|
||||||
@@ -16,7 +17,7 @@ router.get('/', adminAuth, async (req, res) => {
|
|||||||
|
|
||||||
// Get total count
|
// Get total count
|
||||||
const totalCount = await db('events')
|
const totalCount = await db('events')
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.count('id as count')
|
.count('id as count')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ router.get('/', adminAuth, async (req, res) => {
|
|||||||
db.raw('SUM(photos.size_bytes) as total_size')
|
db.raw('SUM(photos.size_bytes) as total_size')
|
||||||
)
|
)
|
||||||
.leftJoin('photos', 'events.id', 'photos.event_id')
|
.leftJoin('photos', 'events.id', 'photos.event_id')
|
||||||
.where('events.is_archived', true)
|
.where('events.is_archived', formatBoolean(true))
|
||||||
.groupBy('events.id')
|
.groupBy('events.id')
|
||||||
.orderBy('events.archived_at', 'desc')
|
.orderBy('events.archived_at', 'desc')
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@@ -84,7 +85,7 @@ router.get('/:id', adminAuth, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const archive = await db('events')
|
const archive = await db('events')
|
||||||
.where('id', req.params.id)
|
.where('id', req.params.id)
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
@@ -140,7 +141,7 @@ router.post('/:id/restore', adminAuth, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const archive = await db('events')
|
const archive = await db('events')
|
||||||
.where('id', req.params.id)
|
.where('id', req.params.id)
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
@@ -303,7 +304,7 @@ router.get('/:id/download', adminAuth, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const archive = await db('events')
|
const archive = await db('events')
|
||||||
.where('id', req.params.id)
|
.where('id', req.params.id)
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
@@ -352,7 +353,7 @@ router.delete('/:id', adminAuth, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const archive = await db('events')
|
const archive = await db('events')
|
||||||
.where('id', req.params.id)
|
.where('id', req.params.id)
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { body, validationResult } = require('express-validator');
|
const { body, validationResult } = require('express-validator');
|
||||||
const { db, logActivity } = require('../database/db');
|
const { db, logActivity } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ const router = express.Router();
|
|||||||
router.get('/global', adminAuth, async (req, res) => {
|
router.get('/global', adminAuth, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const categories = await db('photo_categories')
|
const categories = await db('photo_categories')
|
||||||
.where('is_global', true)
|
.where('is_global', formatBoolean(true))
|
||||||
.orderBy('name', 'asc');
|
.orderBy('name', 'asc');
|
||||||
|
|
||||||
res.json(categories);
|
res.json(categories);
|
||||||
@@ -25,7 +26,7 @@ router.get('/event/:eventId', adminAuth, async (req, res) => {
|
|||||||
|
|
||||||
const categories = await db('photo_categories')
|
const categories = await db('photo_categories')
|
||||||
.where(function() {
|
.where(function() {
|
||||||
this.where('is_global', true)
|
this.where('is_global', formatBoolean(true))
|
||||||
.orWhere('event_id', eventId);
|
.orWhere('event_id', eventId);
|
||||||
})
|
})
|
||||||
.orderBy('is_global', 'desc')
|
.orderBy('is_global', 'desc')
|
||||||
@@ -65,7 +66,7 @@ router.post('/', adminAuth, [
|
|||||||
.where('slug', categorySlug)
|
.where('slug', categorySlug)
|
||||||
.where(function() {
|
.where(function() {
|
||||||
if (is_global) {
|
if (is_global) {
|
||||||
this.where('is_global', true);
|
this.where('is_global', formatBoolean(true));
|
||||||
} else {
|
} else {
|
||||||
this.where('event_id', event_id);
|
this.where('event_id', event_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const path = require('path');
|
|||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { body, validationResult } = require('express-validator');
|
const { body, validationResult } = require('express-validator');
|
||||||
const { db, logActivity } = require('../database/db');
|
const { db, logActivity } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { adminAuth } = require('../middleware/auth');
|
const { adminAuth } = require('../middleware/auth');
|
||||||
const { clearMaintenanceCache } = require('../middleware/maintenance');
|
const { clearMaintenanceCache } = require('../middleware/maintenance');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@@ -513,7 +514,7 @@ router.get('/storage/info', adminAuth, async (req, res) => {
|
|||||||
|
|
||||||
// Get archive storage
|
// Get archive storage
|
||||||
const archives = await db('events')
|
const archives = await db('events')
|
||||||
.where('is_archived', true)
|
.where('is_archived', formatBoolean(true))
|
||||||
.whereNotNull('archive_path')
|
.whereNotNull('archive_path')
|
||||||
.select('archive_path');
|
.select('archive_path');
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const bcrypt = require('bcrypt');
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { body, validationResult } = require('express-validator');
|
const { body, validationResult } = require('express-validator');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { verifyRecaptcha } = require('../services/recaptcha');
|
const { verifyRecaptcha } = require('../services/recaptcha');
|
||||||
const {
|
const {
|
||||||
trackFailedAttempt,
|
trackFailedAttempt,
|
||||||
@@ -248,7 +249,7 @@ router.post('/gallery/verify', [
|
|||||||
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await db('events').where({ slug, is_active: true, is_archived: false }).first();
|
const event = await db('events').where({ slug, is_active: formatBoolean(true), is_archived: formatBoolean(false) }).first();
|
||||||
if (!event) {
|
if (!event) {
|
||||||
// Don't reveal if gallery exists
|
// Don't reveal if gallery exists
|
||||||
await trackFailedAttempt(`gallery:${slug}`, ipAddress, userAgent);
|
await trackFailedAttempt(`gallery:${slug}`, ipAddress, userAgent);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const bcrypt = require('bcrypt');
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { body, validationResult } = require('express-validator');
|
const { body, validationResult } = require('express-validator');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { verifyRecaptcha } = require('../services/recaptcha');
|
const { verifyRecaptcha } = require('../services/recaptcha');
|
||||||
const {
|
const {
|
||||||
trackFailedAttempt,
|
trackFailedAttempt,
|
||||||
@@ -167,7 +168,7 @@ router.post('/gallery/verify', [
|
|||||||
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await db('events').where({ slug, is_active: true, is_archived: false }).first();
|
const event = await db('events').where({ slug, is_active: formatBoolean(true), is_archived: formatBoolean(false) }).first();
|
||||||
if (!event) {
|
if (!event) {
|
||||||
// Don't reveal if gallery exists
|
// Don't reveal if gallery exists
|
||||||
await trackFailedAttempt(`gallery:${slug}`, ipAddress, userAgent);
|
await trackFailedAttempt(`gallery:${slug}`, ipAddress, userAgent);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const bcrypt = require('bcrypt');
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { body, validationResult } = require('express-validator');
|
const { body, validationResult } = require('express-validator');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { verifyRecaptcha } = require('../services/recaptcha');
|
const { verifyRecaptcha } = require('../services/recaptcha');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ router.post('/gallery/verify', [
|
|||||||
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
return res.status(400).json({ error: 'reCAPTCHA verification failed' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await db('events').where({ slug, is_active: true, is_archived: false }).first();
|
const event = await db('events').where({ slug, is_active: formatBoolean(true), is_archived: formatBoolean(false) }).first();
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return res.status(404).json({ error: 'Gallery not found or expired' });
|
return res.status(404).json({ error: 'Gallery not found or expired' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const { body, validationResult } = require('express-validator');
|
|||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
@@ -113,9 +114,9 @@ router.get('/', adminAuth, async (req, res) => {
|
|||||||
let query = db('events').select('*');
|
let query = db('events').select('*');
|
||||||
|
|
||||||
if (status === 'active') {
|
if (status === 'active') {
|
||||||
query = query.where('is_active', true);
|
query = query.where('is_active', formatBoolean(true));
|
||||||
} else if (status === 'archived') {
|
} else if (status === 'archived') {
|
||||||
query = query.where('is_archived', true);
|
query = query.where('is_archived', formatBoolean(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = await query.orderBy('created_at', 'desc');
|
const events = await query.orderBy('created_at', 'desc');
|
||||||
@@ -162,7 +163,7 @@ router.delete('/:id', adminAuth, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
|
|
||||||
await db('events').where('id', id).update({ is_active: false });
|
await db('events').where('id', id).update({ is_active: formatBoolean(false) });
|
||||||
|
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -188,7 +189,7 @@ router.post('/:id/extend', adminAuth, [
|
|||||||
|
|
||||||
await db('events').where('id', id).update({
|
await db('events').where('id', id).update({
|
||||||
expires_at: newExpiration,
|
expires_at: newExpiration,
|
||||||
is_active: true // Reactivate if expired
|
is_active: formatBoolean(true) // Reactivate if expired
|
||||||
});
|
});
|
||||||
|
|
||||||
res.json({ expires_at: newExpiration });
|
res.json({ expires_at: newExpiration });
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const archiver = require('archiver');
|
const archiver = require('archiver');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@@ -19,7 +20,7 @@ async function verifyGalleryAccess(req, res, next) {
|
|||||||
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
const event = await db('events')
|
const event = await db('events')
|
||||||
.where({ id: decoded.eventId, is_active: true, is_archived: false })
|
.where({ id: decoded.eventId, is_active: formatBoolean(true), is_archived: formatBoolean(false) })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
@@ -40,7 +41,7 @@ router.get('/:slug/verify-token/:token', async (req, res) => {
|
|||||||
const { slug, token } = req.params;
|
const { slug, token } = req.params;
|
||||||
|
|
||||||
const event = await db('events')
|
const event = await db('events')
|
||||||
.where({ slug, is_active: true, is_archived: false })
|
.where({ slug, is_active: formatBoolean(true), is_archived: formatBoolean(false) })
|
||||||
.select('id', 'share_link')
|
.select('id', 'share_link')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ router.get('/:slug/photos', verifyGalleryAccess, async (req, res) => {
|
|||||||
// Get all categories for this event
|
// Get all categories for this event
|
||||||
const categories = await db('photo_categories')
|
const categories = await db('photo_categories')
|
||||||
.where(function() {
|
.where(function() {
|
||||||
this.where('is_global', true)
|
this.where('is_global', formatBoolean(true))
|
||||||
.orWhere('event_id', req.event.id);
|
.orWhere('event_id', req.event.id);
|
||||||
})
|
})
|
||||||
.orderBy('is_global', 'desc')
|
.orderBy('is_global', 'desc')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { verifyGalleryAccess } = require('../middleware/gallery');
|
const { verifyGalleryAccess } = require('../middleware/gallery');
|
||||||
const watermarkService = require('../services/watermarkService');
|
const watermarkService = require('../services/watermarkService');
|
||||||
const { getStoragePath } = require('../config/storage');
|
const { getStoragePath } = require('../config/storage');
|
||||||
@@ -141,7 +142,7 @@ router.get('/:slug/photo/:photoId/signed/:token', async (req, res) => {
|
|||||||
// Get event
|
// Get event
|
||||||
const event = await db('events')
|
const event = await db('events')
|
||||||
.where({ slug })
|
.where({ slug })
|
||||||
.where('is_active', true)
|
.where('is_active', formatBoolean(true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ async function queueExpirationWarning(event) {
|
|||||||
async function handleExpiredEvent(event) {
|
async function handleExpiredEvent(event) {
|
||||||
try {
|
try {
|
||||||
// Mark as inactive
|
// Mark as inactive
|
||||||
await db('events').where('id', event.id).update({ is_active: false });
|
await db('events').where('id', event.id).update({ is_active: formatBoolean(false) });
|
||||||
|
|
||||||
// Queue expiration emails
|
// Queue expiration emails
|
||||||
await queueEmail(event.id, event.host_email, 'gallery_expired', {
|
await queueEmail(event.id, event.host_email, 'gallery_expired', {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const chokidar = require('chokidar');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
const { generateThumbnail } = require('./imageProcessor');
|
const { generateThumbnail } = require('./imageProcessor');
|
||||||
const logger = require('../utils/logger');
|
const logger = require('../utils/logger');
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ async function processNewPhoto(filePath) {
|
|||||||
if (!['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) return;
|
if (!['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) return;
|
||||||
|
|
||||||
// Find the event
|
// Find the event
|
||||||
const event = await db('events').where({ slug: eventSlug, is_active: true }).first();
|
const event = await db('events').where({ slug: eventSlug, is_active: formatBoolean(true) }).first();
|
||||||
if (!event) return;
|
if (!event) return;
|
||||||
|
|
||||||
// Get file stats
|
// Get file stats
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
|
const { formatBoolean } = require('./dbCompat');
|
||||||
const logger = require('./logger');
|
const logger = require('./logger');
|
||||||
|
|
||||||
// Configuration constants
|
// Configuration constants
|
||||||
@@ -59,7 +60,7 @@ async function trackSuccessfulLogin(identifier, ipAddress, userAgent) {
|
|||||||
const cutoffTime = new Date(Date.now() - ATTEMPT_WINDOW);
|
const cutoffTime = new Date(Date.now() - ATTEMPT_WINDOW);
|
||||||
await db('login_attempts')
|
await db('login_attempts')
|
||||||
.where('identifier', identifier)
|
.where('identifier', identifier)
|
||||||
.where('success', false)
|
.where('success', formatBoolean(false))
|
||||||
.where('attempt_time', '<', cutoffTime.toISOString())
|
.where('attempt_time', '<', cutoffTime.toISOString())
|
||||||
.delete();
|
.delete();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -79,7 +80,7 @@ async function checkAccountLockout(identifier) {
|
|||||||
// Get recent failed attempts
|
// Get recent failed attempts
|
||||||
const failedAttempts = await db('login_attempts')
|
const failedAttempts = await db('login_attempts')
|
||||||
.where('identifier', identifier)
|
.where('identifier', identifier)
|
||||||
.where('success', false)
|
.where('success', formatBoolean(false))
|
||||||
.where('attempt_time', '>=', recentWindow.toISOString())
|
.where('attempt_time', '>=', recentWindow.toISOString())
|
||||||
.orderBy('attempt_time', 'desc')
|
.orderBy('attempt_time', 'desc')
|
||||||
.limit(MAX_LOGIN_ATTEMPTS);
|
.limit(MAX_LOGIN_ATTEMPTS);
|
||||||
|
|||||||
Reference in New Issue
Block a user