diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..85d5f67 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.env +*.log +data/* +!data/branding/ +!data/branding/** +frontend/node_modules/ +frontend/.next/ +backend/__pycache__/ +**/__pycache__/ +**/*.pyc diff --git a/.gitignore b/.gitignore index 5c8cad8..916a6bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .env .venv/ data/ +!data/branding/ +!data/branding/** backend/__pycache__/ **/__pycache__/ *.pyc diff --git a/backend/Dockerfile b/backend/Dockerfile index 93712a6..af986e3 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -9,6 +9,7 @@ COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app ./app +COPY data/branding /app/data/branding EXPOSE 8000 diff --git a/data/branding/favicon.ico b/data/branding/favicon.ico new file mode 100644 index 0000000..68b4d3d Binary files /dev/null and b/data/branding/favicon.ico differ diff --git a/data/branding/logo.png b/data/branding/logo.png new file mode 100644 index 0000000..d76a78a Binary files /dev/null and b/data/branding/logo.png differ diff --git a/docker-compose.yml b/docker-compose.yml index aeb4a12..97b0ead 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ services: backend: build: - context: ./backend - dockerfile: Dockerfile + context: . + dockerfile: backend/Dockerfile env_file: - ./.env ports: diff --git a/frontend/app/users/page.tsx b/frontend/app/users/page.tsx index d0a8bc7..0171d4a 100644 --- a/frontend/app/users/page.tsx +++ b/frontend/app/users/page.tsx @@ -25,8 +25,6 @@ export default function UsersPage() { const [users, setUsers] = useState([]) const [error, setError] = useState(null) const [loading, setLoading] = useState(true) - const [passwordInputs, setPasswordInputs] = useState>({}) - const [passwordStatus, setPasswordStatus] = useState>({}) const loadUsers = async () => { try { @@ -105,42 +103,6 @@ export default function UsersPage() { } } - const updateUserPassword = async (username: string) => { - const newPassword = passwordInputs[username] || '' - if (!newPassword || newPassword.length < 8) { - setPasswordStatus((current) => ({ - ...current, - [username]: 'Password must be at least 8 characters.', - })) - return - } - try { - const baseUrl = getApiBase() - const response = await authFetch( - `${baseUrl}/admin/users/${encodeURIComponent(username)}/password`, - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ password: newPassword }), - } - ) - if (!response.ok) { - const text = await response.text() - throw new Error(text || 'Update failed') - } - setPasswordInputs((current) => ({ ...current, [username]: '' })) - setPasswordStatus((current) => ({ - ...current, - [username]: 'Password updated.', - })) - } catch (err) { - console.error(err) - setPasswordStatus((current) => ({ - ...current, - [username]: 'Could not update password.', - })) - } - } useEffect(() => { if (!getToken()) { @@ -197,27 +159,6 @@ export default function UsersPage() { {user.isBlocked ? 'Allow access' : 'Block access'} - {user.authProvider === 'local' && ( -
- - setPasswordInputs((current) => ({ - ...current, - [user.username]: event.target.value, - })) - } - /> - -
- )} - {passwordStatus[user.username] && ( -
{passwordStatus[user.username]}
- )} ))}