fix: slide image upload - clear image_url when image_id set, fix slides.image_url column type to TEXT, add bed amenities (Queen, 2 Queen)
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { requireRole } from '@/lib/auth';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const { rows } = await db.query(
|
||||
'SELECT id, language, title, version, updated_at FROM terms_content ORDER BY language, updated_at DESC'
|
||||
);
|
||||
return NextResponse.json({ data: rows });
|
||||
} catch (error) {
|
||||
console.error('Error fetching all terms:', error);
|
||||
return NextResponse.json({ error: 'Failed to fetch terms' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
await requireRole('admin');
|
||||
const body = await request.json();
|
||||
const { language, title, content, version = '1.0' } = body;
|
||||
|
||||
if (!language || !title || !content) {
|
||||
return NextResponse.json({ error: 'Language, title, and content are required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { rows } = await db.query(
|
||||
'INSERT INTO terms_content (language, title, content, version) VALUES ($1, $2, $3, $4) RETURNING id, language, title, version, updated_at',
|
||||
[language, title, content, version]
|
||||
);
|
||||
|
||||
return NextResponse.json({ data: rows[0] });
|
||||
} catch (error: any) {
|
||||
console.error('Error creating terms:', error);
|
||||
if (error.code === '23505') {
|
||||
return NextResponse.json({ error: 'Terms with this language and version already exists' }, { status: 409 });
|
||||
}
|
||||
return NextResponse.json({ error: error.message || 'Failed to create terms' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
await requireRole('admin');
|
||||
const body = await request.json();
|
||||
const { id, title, content } = body;
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'Terms ID is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { rows } = await db.query(
|
||||
'UPDATE terms_content SET title = $1, content = $2, updated_at = NOW() WHERE id = $3 RETURNING id, language, title, version, updated_at',
|
||||
[title, content, id]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return NextResponse.json({ error: 'Terms not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: rows[0] });
|
||||
} catch (error: any) {
|
||||
console.error('Error updating terms:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to update terms' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { db } from '@/lib/db';
|
||||
export async function GET() {
|
||||
try {
|
||||
await requireRole('admin');
|
||||
const { rows } = await db.query('SELECT id, username, role, comments_disabled, first_name, last_name, created_at FROM users ORDER BY created_at DESC');
|
||||
const { rows } = await db.query('SELECT id, username, role, comments_disabled, first_name, last_name, preferred_language, terms_accepted_at, email, phone, country, created_at FROM users ORDER BY created_at DESC');
|
||||
return NextResponse.json({ data: rows });
|
||||
} catch (err: any) {
|
||||
return NextResponse.json({ error: err.message || 'Failed to fetch users' }, { status: err.message === 'Unauthorized' ? 401 : 500 });
|
||||
@@ -16,7 +16,7 @@ export async function POST(request: NextRequest) {
|
||||
try {
|
||||
await requireRole('admin');
|
||||
const body = await request.json();
|
||||
const { username, password, role = 'user' } = body;
|
||||
const { username, password, role = 'user', first_name, last_name, email, phone, country, preferred_language = 'es' } = body;
|
||||
|
||||
if (!username || !password) {
|
||||
return NextResponse.json({ error: 'Username and password are required' }, { status: 400 });
|
||||
@@ -26,8 +26,8 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Role must be admin or user' }, { status: 400 });
|
||||
}
|
||||
|
||||
const user = await createUser(username, password, role as 'admin' | 'user');
|
||||
return NextResponse.json({ ok: true, user: { id: user.id, username: user.username, role: user.role } });
|
||||
const user = await createUser(username, password, role as 'admin' | 'user', { first_name, last_name, email, phone, country, preferred_language });
|
||||
return NextResponse.json({ ok: true, user: { id: user.id, username: user.username, role: user.role, first_name: user.first_name, last_name: user.last_name } });
|
||||
} catch (err: any) {
|
||||
return NextResponse.json({ error: err.message || 'Failed to create user' }, { status: err.message === 'Unauthorized' ? 401 : 500 });
|
||||
}
|
||||
@@ -37,11 +37,55 @@ export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
await requireRole('admin');
|
||||
const body = await request.json();
|
||||
const { id, first_name, last_name, comments_disabled } = body;
|
||||
const { id, first_name, last_name, comments_disabled, preferred_language, email, phone, country, password } = body;
|
||||
|
||||
// Build dynamic update query
|
||||
const updates: string[] = [];
|
||||
const values: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (first_name !== undefined) {
|
||||
updates.push(`first_name = $${paramIndex++}`);
|
||||
values.push(first_name || null);
|
||||
}
|
||||
if (last_name !== undefined) {
|
||||
updates.push(`last_name = $${paramIndex++}`);
|
||||
values.push(last_name || null);
|
||||
}
|
||||
if (comments_disabled !== undefined) {
|
||||
updates.push(`comments_disabled = $${paramIndex++}`);
|
||||
values.push(comments_disabled === true);
|
||||
}
|
||||
if (preferred_language !== undefined) {
|
||||
updates.push(`preferred_language = $${paramIndex++}`);
|
||||
values.push(preferred_language || 'es');
|
||||
}
|
||||
if (email !== undefined) {
|
||||
updates.push(`email = $${paramIndex++}`);
|
||||
values.push(email || null);
|
||||
}
|
||||
if (phone !== undefined) {
|
||||
updates.push(`phone = $${paramIndex++}`);
|
||||
values.push(phone || null);
|
||||
}
|
||||
if (country !== undefined) {
|
||||
updates.push(`country = $${paramIndex++}`);
|
||||
values.push(country || null);
|
||||
}
|
||||
if (password !== undefined && password) {
|
||||
const { hashPassword } = await import('@/lib/auth');
|
||||
updates.push(`password_hash = $${paramIndex++}`);
|
||||
values.push(await hashPassword(password));
|
||||
}
|
||||
|
||||
if (updates.length === 0) {
|
||||
return NextResponse.json({ error: 'No fields to update' }, { status: 400 });
|
||||
}
|
||||
|
||||
values.push(id);
|
||||
const { rows } = await db.query(
|
||||
'UPDATE users SET first_name = $1, last_name = $2, comments_disabled = $3 WHERE id = $4 RETURNING id, username, role, first_name, last_name, comments_disabled, created_at',
|
||||
[first_name || null, last_name || null, comments_disabled === true, id]
|
||||
`UPDATE users SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING id, username, role, first_name, last_name, comments_disabled, preferred_language, email, phone, country, created_at`,
|
||||
values
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
|
||||
@@ -17,7 +17,14 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
await createSession(user);
|
||||
|
||||
return NextResponse.json({ role: user.role, username: user.username });
|
||||
return NextResponse.json({
|
||||
role: user.role,
|
||||
username: user.username,
|
||||
preferred_language: user.preferred_language,
|
||||
terms_accepted_at: user.terms_accepted_at,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { createUser } from '@/lib/auth';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { username, password, preferred_language, first_name, last_name, email, phone, country, accept_terms } = body;
|
||||
|
||||
if (!username || !password) {
|
||||
return NextResponse.json({ error: 'Username and password are required' }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!accept_terms) {
|
||||
return NextResponse.json({ error: 'You must accept the terms of service' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Check if username already exists
|
||||
const { rows: existing } = await db.query('SELECT id FROM users WHERE username = $1', [username]);
|
||||
if (existing.length > 0) {
|
||||
return NextResponse.json({ error: 'Username already exists' }, { status: 409 });
|
||||
}
|
||||
|
||||
// Create user with role 'user' and terms_accepted_at
|
||||
const user = await createUser(username, password, 'user');
|
||||
|
||||
// Update with additional profile fields
|
||||
await db.query(
|
||||
'UPDATE users SET preferred_language = $1, first_name = $2, last_name = $3, email = $4, phone = $5, country = $6, terms_accepted_at = NOW() WHERE id = $7',
|
||||
[preferred_language || 'es', first_name || null, last_name || null, email || null, phone || null, country || null, user.id]
|
||||
);
|
||||
|
||||
const { rows } = await db.query(
|
||||
'SELECT id, username, role, preferred_language, first_name, last_name, email, phone, country, terms_accepted_at FROM users WHERE id = $1',
|
||||
[user.id]
|
||||
);
|
||||
|
||||
return NextResponse.json({ ok: true, user: rows[0] });
|
||||
} catch (error: any) {
|
||||
console.error('Registration error:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to register user' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const language = searchParams.get('language') || 'es';
|
||||
|
||||
// Get the latest terms for the requested language
|
||||
const { rows } = await db.query(
|
||||
'SELECT id, language, title, content, version, updated_at FROM terms_content WHERE language = $1 ORDER BY updated_at DESC LIMIT 1',
|
||||
[language]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
// Return default English terms if no terms found for requested language
|
||||
const { rows: enRows } = await db.query(
|
||||
'SELECT id, language, title, content, version, updated_at FROM terms_content WHERE language = $1 ORDER BY updated_at DESC LIMIT 1',
|
||||
['en']
|
||||
);
|
||||
|
||||
if (enRows.length === 0) {
|
||||
// Return empty terms if nothing exists yet
|
||||
return NextResponse.json({ data: { title: '', content: '', version: '1.0', language } });
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: enRows[0] });
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: rows[0] });
|
||||
} catch (error) {
|
||||
console.error('Error fetching terms:', error);
|
||||
return NextResponse.json({ error: 'Failed to fetch terms' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { requireAuth, hashPassword } from '@/lib/auth';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await requireAuth();
|
||||
const { rows } = await db.query(
|
||||
'SELECT id, username, role, first_name, last_name, preferred_language, terms_accepted_at, email, phone, country, created_at FROM users WHERE id = $1',
|
||||
[session.id]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: rows[0] });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message || 'Failed to fetch profile' }, { status: error.message === 'Unauthorized' ? 401 : 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const session = await requireAuth();
|
||||
const body = await request.json();
|
||||
const { first_name, last_name, preferred_language, email, phone, country, password, accept_terms } = body;
|
||||
|
||||
// Build dynamic update query
|
||||
const updates: string[] = [];
|
||||
const values: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (first_name !== undefined) {
|
||||
updates.push(`first_name = $${paramIndex++}`);
|
||||
values.push(first_name || null);
|
||||
}
|
||||
if (last_name !== undefined) {
|
||||
updates.push(`last_name = $${paramIndex++}`);
|
||||
values.push(last_name || null);
|
||||
}
|
||||
if (preferred_language !== undefined) {
|
||||
updates.push(`preferred_language = $${paramIndex++}`);
|
||||
values.push(preferred_language || 'es');
|
||||
}
|
||||
if (email !== undefined) {
|
||||
updates.push(`email = $${paramIndex++}`);
|
||||
values.push(email || null);
|
||||
}
|
||||
if (phone !== undefined) {
|
||||
updates.push(`phone = $${paramIndex++}`);
|
||||
values.push(phone || null);
|
||||
}
|
||||
if (country !== undefined) {
|
||||
updates.push(`country = $${paramIndex++}`);
|
||||
values.push(country || null);
|
||||
}
|
||||
if (password !== undefined && password) {
|
||||
updates.push(`password_hash = $${paramIndex++}`);
|
||||
values.push(await hashPassword(password));
|
||||
}
|
||||
if (accept_terms === true) {
|
||||
updates.push(`terms_accepted_at = NOW()`);
|
||||
}
|
||||
|
||||
if (updates.length === 0) {
|
||||
return NextResponse.json({ error: 'No fields to update' }, { status: 400 });
|
||||
}
|
||||
|
||||
values.push(session.id);
|
||||
const { rows } = await db.query(
|
||||
`UPDATE users SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING id, username, role, first_name, last_name, preferred_language, terms_accepted_at, email, phone, country, created_at`,
|
||||
values
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: rows[0] });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message || 'Failed to update profile' }, { status: error.message === 'Unauthorized' ? 401 : 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user