feat: remove global admin, open registration, clear DB seed

- All users are equal — no is_admin superuser
- Removed AdminPanel, Shield button from sidebar
- isOwnerOrAdmin checks only by chat role (owner/admin)
- Removed auto-seed of admin user on startup
- DB already cleared on server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ai
2026-05-25 15:45:59 +03:00
parent 2fd6b14e1a
commit dbf328b197
5 changed files with 7 additions and 26 deletions

View File

@@ -1,5 +1,4 @@
import { Pool } from 'pg';
import bcrypt from 'bcryptjs';
export const pool = new Pool({ connectionString: process.env.DATABASE_URL });
@@ -94,14 +93,5 @@ export async function initDB() {
ALTER TABLE chat_members ADD COLUMN IF NOT EXISTS is_pinned BOOLEAN DEFAULT FALSE;
`);
// Seed admin if no users
const { rows } = await pool.query('SELECT COUNT(*) FROM users');
if (parseInt(rows[0].count) === 0) {
const hash = await bcrypt.hash('admin123', 10);
await pool.query(
`INSERT INTO users (username, display_name, password_hash, is_admin) VALUES ($1,$2,$3,TRUE)`,
['admin', 'Администратор', hash]
);
console.log('Created admin user: admin / admin123');
}
// No auto-seed — users register themselves
}

View File

@@ -339,13 +339,13 @@ export default async function chatRoutes(app: FastifyInstance) {
// Delete chat (owner only)
app.delete('/:id', async (req, reply) => {
const { id: userId, isAdmin } = req.user as { id: string; isAdmin: boolean };
const { id: userId } = req.user as { id: string };
const { id } = req.params as { id: string };
const { rows: [member] } = await pool.query(
'SELECT role FROM chat_members WHERE chat_id = $1 AND user_id = $2', [id, userId]
);
if (!member || (member.role !== 'owner' && !isAdmin)) {
if (!member || member.role !== 'owner') {
return reply.status(403).send({ error: 'No permission' });
}

View File

@@ -42,7 +42,7 @@ export default function ChatHeader({ chat, onBack, onRefresh, onShowInfo }: Prop
subtitle = `${chat.memberCount} участников`;
}
const isOwnerOrAdmin = chat.myRole === 'owner' || chat.myRole === 'admin' || user?.isAdmin;
const isOwnerOrAdmin = chat.myRole === 'owner' || chat.myRole === 'admin';
async function handleLeave() {
if (!confirm('Выйти из чата?')) return;

View File

@@ -23,7 +23,7 @@ export default function ChatInfoPanel({ chat, onClose, onRefresh }: Props) {
const [uploadingAvatar, setUploadingAvatar] = useState(false);
const fileRef = useRef<HTMLInputElement>(null);
const isOwnerOrAdmin = chat.myRole === 'owner' || chat.myRole === 'admin' || me?.isAdmin;
const isOwnerOrAdmin = chat.myRole === 'owner' || chat.myRole === 'admin';
useEffect(() => {
if (addMode) {

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Search, Edit, Settings, Shield, Wifi, WifiOff, MessageCircle } from 'lucide-react';
import { Search, Edit, Settings, Wifi, WifiOff, MessageCircle } from 'lucide-react';
import { useStore } from '../store';
import { wsClient } from '../api/ws';
import api from '../api/client';
@@ -9,7 +9,6 @@ import MessageList from '../components/MessageList';
import ChatHeader from '../components/ChatHeader';
import ChatInfoPanel from '../components/ChatInfoPanel';
import NewChatModal from '../components/NewChatModal';
import AdminPanel from '../components/admin/AdminPanel';
import ProfileModal from '../components/ProfileModal';
import { usePushNotifications } from '../hooks/usePushNotifications';
import { Chat } from '../types';
@@ -19,7 +18,6 @@ export default function MainLayout() {
const [search, setSearch] = useState('');
const [searchUsers, setSearchUsers] = useState<any[]>([]);
const [showNew, setShowNew] = useState(false);
const [showAdmin, setShowAdmin] = useState(false);
const [showInfo, setShowInfo] = useState(false);
const [showProfile, setShowProfile] = useState(false);
const [mobileChatOpen, setMobileChatOpen] = useState(false);
@@ -132,7 +130,7 @@ export default function MainLayout() {
if (!activeChat) return false;
if (activeChat.type === 'private') return true;
if (activeChat.type === 'group') return activeChat.canSendMessages !== false;
if (activeChat.type === 'channel') return activeChat.myRole === 'owner' || activeChat.myRole === 'admin' || !!user?.isAdmin;
if (activeChat.type === 'channel') return activeChat.myRole === 'owner' || activeChat.myRole === 'admin';
return false;
})();
@@ -155,12 +153,6 @@ export default function MainLayout() {
</div>
</div>
<div className="flex items-center gap-1">
{user?.isAdmin && (
<button onClick={() => setShowAdmin(true)}
className="p-1.5 rounded-lg hover:bg-gray-100 text-gray-400 hover:text-gray-600" title="Панель администратора">
<Shield className="w-4 h-4" />
</button>
)}
<button onClick={() => setShowProfile(true)}
className="p-1.5 rounded-lg hover:bg-gray-100 text-gray-400 hover:text-gray-600" title="Профиль">
<Settings className="w-4 h-4" />
@@ -297,7 +289,6 @@ export default function MainLayout() {
if (found) openChat(found);
} catch {}
}} />}
{showAdmin && <AdminPanel onClose={() => setShowAdmin(false)} />}
{showProfile && <ProfileModal onClose={() => setShowProfile(false)} />}
</div>
);