forked from admin/zeropost-tool
feat: photo-search, system settings, ROADMAP
- PhotoSearchModal: Yandex photo-search с профилями доменов - SystemSettings: управление app_settings (admin-only, /system) - ROADMAP.md: актуальный план фич P1-P10 - Header, ChannelView, session: поддержка is_admin
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { requireAdmin } from '@/lib/session';
|
||||
import { engine } from '@/lib/engine';
|
||||
|
||||
export async function PUT(req, { params }) {
|
||||
const admin = await requireAdmin();
|
||||
if (!admin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||
try {
|
||||
const { key } = await params;
|
||||
const body = await req.json();
|
||||
const row = await engine.updateSetting(key, body?.value);
|
||||
return NextResponse.json(row);
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: err.message }, { status: err.status || 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { requireAdmin } from '@/lib/session';
|
||||
import { engine } from '@/lib/engine';
|
||||
|
||||
// GET /api/admin/settings?category=photo_search
|
||||
export async function GET(req) {
|
||||
const admin = await requireAdmin();
|
||||
if (!admin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||
try {
|
||||
const { searchParams } = new URL(req.url);
|
||||
const category = searchParams.get('category') || undefined;
|
||||
const rows = await engine.listSettings(category);
|
||||
return NextResponse.json(rows);
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: err.message }, { status: err.status || 500 });
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,23 @@ export async function POST(req) {
|
||||
}
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
const { rows } = await q(
|
||||
`INSERT INTO users (email,password) VALUES ($1,$2) RETURNING id,email,name`,
|
||||
`INSERT INTO users (email,password) VALUES ($1,$2) RETURNING id,email,name,is_admin`,
|
||||
[email, hash]
|
||||
);
|
||||
const user = rows[0];
|
||||
const s = await getSession();
|
||||
s.userId = user.id;
|
||||
s.email = user.email;
|
||||
s.isAdmin = !!user.is_admin;
|
||||
await s.save();
|
||||
return NextResponse.json({ ok: true, user });
|
||||
}
|
||||
|
||||
// login
|
||||
const { rows } = await q(`SELECT id,email,password,name FROM users WHERE email=$1`, [email]);
|
||||
const { rows } = await q(
|
||||
`SELECT id,email,password,name,is_admin FROM users WHERE email=$1`,
|
||||
[email]
|
||||
);
|
||||
if (!rows.length) {
|
||||
return NextResponse.json({ error: 'Неверный email или пароль' }, { status: 401 });
|
||||
}
|
||||
@@ -41,6 +45,10 @@ export async function POST(req) {
|
||||
s.userId = user.id;
|
||||
s.email = user.email;
|
||||
s.name = user.name;
|
||||
s.isAdmin = !!user.is_admin;
|
||||
await s.save();
|
||||
return NextResponse.json({ ok: true, user: { id: user.id, email: user.email, name: user.name } });
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
user: { id: user.id, email: user.email, name: user.name, isAdmin: !!user.is_admin },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { requireUser } from '@/lib/session';
|
||||
import { engine } from '@/lib/engine';
|
||||
|
||||
export async function POST(req) {
|
||||
const user = await requireUser();
|
||||
if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
try {
|
||||
const body = await req.json();
|
||||
const data = await engine.photoSearchByQuery(body);
|
||||
return NextResponse.json(data);
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: err.message, code: err.code },
|
||||
{ status: err.status || 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { requireUser } from '@/lib/session';
|
||||
import { engine } from '@/lib/engine';
|
||||
|
||||
export async function GET() {
|
||||
const user = await requireUser();
|
||||
if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
try {
|
||||
const data = await engine.photoSearchProfiles();
|
||||
return NextResponse.json(data);
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: err.message }, { status: err.status || 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { requireUser } from '@/lib/session';
|
||||
import { engine } from '@/lib/engine';
|
||||
|
||||
export async function GET() {
|
||||
const user = await requireUser();
|
||||
if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
try {
|
||||
const data = await engine.photoSearchQuota();
|
||||
return NextResponse.json(data);
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: err.message }, { status: err.status || 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user