Add NextSnap PWA with photo gallery viewer and continuous capture

Offline-first photo capture app for Nextcloud with:
- Camera capture with continuous mode (auto-reopens after each photo)
- File browser with fullscreen image gallery, swipe navigation, and rename
- Upload queue with background sync engine
- Admin panel for Nextcloud user management
- Service worker for offline-first caching (v13)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 04:53:13 -06:00
commit cad4118f72
55 changed files with 9038 additions and 0 deletions

133
tests/test_auth.py Normal file
View File

@@ -0,0 +1,133 @@
import pytest
from app import create_app
from unittest.mock import patch, MagicMock
import tempfile
import os
@pytest.fixture
def app():
"""Create application for testing."""
app = create_app('development')
app.config['TESTING'] = True
# Use simple session for testing
app.config['SECRET_KEY'] = 'test-secret-key'
app.config['SESSION_TYPE'] = 'null' # Disable server-side sessions for testing
return app
@pytest.fixture
def client(app):
"""Create test client with session support."""
with app.test_client() as client:
with client.session_transaction() as sess:
# Initialize session
pass
yield client
def test_login_missing_credentials(client):
"""Test login with missing credentials."""
response = client.post('/api/auth/login', json={})
assert response.status_code == 400
data = response.get_json()
assert 'error' in data
def test_login_empty_credentials(client):
"""Test login with empty credentials."""
response = client.post('/api/auth/login', json={'username': '', 'password': ''})
assert response.status_code == 400
data = response.get_json()
assert 'error' in data
@patch('app.routes.auth.NextcloudClient')
def test_login_invalid_credentials(mock_nc_client, client):
"""Test login with invalid credentials."""
# Mock NextcloudClient to return False for verify_credentials
mock_instance = MagicMock()
mock_instance.verify_credentials.return_value = False
mock_nc_client.return_value = mock_instance
response = client.post('/api/auth/login', json={'username': 'testuser', 'password': 'wrongpass'})
assert response.status_code == 401
data = response.get_json()
assert 'error' in data
@patch('app.routes.auth.NextcloudClient')
def test_login_success(mock_nc_client, client):
"""Test successful login."""
# Mock NextcloudClient to return True for verify_credentials
mock_instance = MagicMock()
mock_instance.verify_credentials.return_value = True
mock_instance.check_admin.return_value = False
mock_nc_client.return_value = mock_instance
response = client.post('/api/auth/login', json={'username': 'testuser', 'password': 'testpass'})
assert response.status_code == 200
data = response.get_json()
assert data['success'] is True
assert data['username'] == 'testuser'
assert data['is_admin'] is False
@patch('app.routes.auth.NextcloudClient')
def test_login_admin_user(mock_nc_client, client):
"""Test login with admin user."""
mock_instance = MagicMock()
mock_instance.verify_credentials.return_value = True
mock_instance.check_admin.return_value = True
mock_nc_client.return_value = mock_instance
response = client.post('/api/auth/login', json={'username': 'admin', 'password': 'adminpass'})
assert response.status_code == 200
data = response.get_json()
assert data['success'] is True
assert data['is_admin'] is True
def test_status_not_authenticated(client):
"""Test status endpoint when not authenticated."""
response = client.get('/api/auth/status')
assert response.status_code == 200
data = response.get_json()
assert data['authenticated'] is False
@patch('app.routes.auth.NextcloudClient')
def test_status_authenticated(mock_nc_client, client):
"""Test status endpoint when authenticated."""
# First login
mock_instance = MagicMock()
mock_instance.verify_credentials.return_value = True
mock_instance.check_admin.return_value = False
mock_nc_client.return_value = mock_instance
client.post('/api/auth/login', json={'username': 'testuser', 'password': 'testpass'})
# Check status
response = client.get('/api/auth/status')
assert response.status_code == 200
data = response.get_json()
assert data['authenticated'] is True
assert data['username'] == 'testuser'
@patch('app.routes.auth.NextcloudClient')
def test_logout(mock_nc_client, client):
"""Test logout functionality."""
# First login
mock_instance = MagicMock()
mock_instance.verify_credentials.return_value = True
mock_instance.check_admin.return_value = False
mock_nc_client.return_value = mock_instance
client.post('/api/auth/login', json={'username': 'testuser', 'password': 'testpass'})
# Verify logged in
response = client.get('/api/auth/status')
data = response.get_json()
assert data['authenticated'] is True
# Logout
response = client.post('/api/auth/logout')
assert response.status_code == 200
data = response.get_json()
assert data['success'] is True
# Verify logged out
response = client.get('/api/auth/status')
data = response.get_json()
assert data['authenticated'] is False