Internal
Public Access
Features: - Django-based REST API with web interface - Task management with tags, priorities, and due dates - Time tracking with start/stop timers - Subtasks support - Task filtering (all, today, upcoming, overdue, completed) - Tag-based organization with color coding - Sorting by due date and priority - Auto-assign tags when filtering - Responsive 3-pane layout (sidebar, task list, detail panel) - Task sharing between users - Mobile-responsive design with dark mode support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
203 lines
6.0 KiB
Python
203 lines
6.0 KiB
Python
"""
|
|
User views for KeepItGoing.
|
|
"""
|
|
|
|
from django.contrib.auth import get_user_model, login, logout
|
|
from django.shortcuts import render, redirect
|
|
from django.views import View
|
|
from rest_framework import generics, permissions, status
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
from .serializers import (
|
|
UserSerializer,
|
|
UserRegistrationSerializer,
|
|
ChangePasswordSerializer,
|
|
DeviceTokenSerializer,
|
|
)
|
|
from .models import DeviceToken
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
# =============================================================================
|
|
# API Views
|
|
# =============================================================================
|
|
|
|
class RegisterAPIView(generics.CreateAPIView):
|
|
"""API endpoint for user registration."""
|
|
|
|
queryset = User.objects.all()
|
|
serializer_class = UserRegistrationSerializer
|
|
permission_classes = [permissions.AllowAny]
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
user = serializer.save()
|
|
|
|
# Generate tokens
|
|
refresh = RefreshToken.for_user(user)
|
|
|
|
return Response({
|
|
'user': UserSerializer(user).data,
|
|
'tokens': {
|
|
'refresh': str(refresh),
|
|
'access': str(refresh.access_token),
|
|
}
|
|
}, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
class UserProfileAPIView(generics.RetrieveUpdateAPIView):
|
|
"""API endpoint for user profile."""
|
|
|
|
serializer_class = UserSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_object(self):
|
|
return self.request.user
|
|
|
|
|
|
class ChangePasswordAPIView(APIView):
|
|
"""API endpoint for changing password."""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def post(self, request):
|
|
serializer = ChangePasswordSerializer(
|
|
data=request.data,
|
|
context={'request': request}
|
|
)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
request.user.set_password(serializer.validated_data['new_password'])
|
|
request.user.save()
|
|
|
|
return Response({'message': 'Password changed successfully.'})
|
|
|
|
|
|
class DeviceTokenAPIView(generics.ListCreateAPIView):
|
|
"""API endpoint for managing device tokens."""
|
|
|
|
serializer_class = DeviceTokenSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return DeviceToken.objects.filter(user=self.request.user)
|
|
|
|
|
|
class DeviceTokenDeleteAPIView(generics.DestroyAPIView):
|
|
"""API endpoint for deleting a device token."""
|
|
|
|
serializer_class = DeviceTokenSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return DeviceToken.objects.filter(user=self.request.user)
|
|
|
|
|
|
# =============================================================================
|
|
# Web Views (Django Templates)
|
|
# =============================================================================
|
|
|
|
class LoginView(View):
|
|
"""Web login page."""
|
|
|
|
def get(self, request):
|
|
if request.user.is_authenticated:
|
|
return redirect('dashboard')
|
|
return render(request, 'users/login.html')
|
|
|
|
def post(self, request):
|
|
from django.contrib.auth import authenticate
|
|
|
|
email = request.POST.get('email')
|
|
password = request.POST.get('password')
|
|
|
|
user = authenticate(request, username=email, password=password)
|
|
|
|
if user is not None:
|
|
login(request, user)
|
|
next_url = request.GET.get('next', 'dashboard')
|
|
return redirect(next_url)
|
|
|
|
return render(request, 'users/login.html', {
|
|
'error': 'Invalid email or password.'
|
|
})
|
|
|
|
|
|
class LogoutView(View):
|
|
"""Web logout."""
|
|
|
|
def get(self, request):
|
|
logout(request)
|
|
return redirect('login')
|
|
|
|
def post(self, request):
|
|
logout(request)
|
|
return redirect('login')
|
|
|
|
|
|
class RegisterView(View):
|
|
"""Web registration page."""
|
|
|
|
def get(self, request):
|
|
if request.user.is_authenticated:
|
|
return redirect('dashboard')
|
|
return render(request, 'users/register.html')
|
|
|
|
def post(self, request):
|
|
email = request.POST.get('email')
|
|
username = request.POST.get('username')
|
|
password = request.POST.get('password')
|
|
password_confirm = request.POST.get('password_confirm')
|
|
|
|
errors = {}
|
|
|
|
if password != password_confirm:
|
|
errors['password_confirm'] = 'Passwords do not match.'
|
|
|
|
if User.objects.filter(email=email).exists():
|
|
errors['email'] = 'Email already registered.'
|
|
|
|
if User.objects.filter(username=username).exists():
|
|
errors['username'] = 'Username already taken.'
|
|
|
|
if errors:
|
|
return render(request, 'users/register.html', {'errors': errors})
|
|
|
|
user = User.objects.create_user(
|
|
email=email,
|
|
username=username,
|
|
password=password
|
|
)
|
|
login(request, user)
|
|
return redirect('dashboard')
|
|
|
|
|
|
class ProfileView(View):
|
|
"""Web profile page."""
|
|
|
|
def get(self, request):
|
|
if not request.user.is_authenticated:
|
|
return redirect('login')
|
|
return render(request, 'users/profile.html')
|
|
|
|
def post(self, request):
|
|
if not request.user.is_authenticated:
|
|
return redirect('login')
|
|
|
|
user = request.user
|
|
user.first_name = request.POST.get('first_name', '')
|
|
user.last_name = request.POST.get('last_name', '')
|
|
user.timezone = request.POST.get('timezone', 'UTC')
|
|
user.default_reminder_minutes = int(request.POST.get('default_reminder_minutes', 30))
|
|
user.email_notifications = request.POST.get('email_notifications') == 'on'
|
|
user.push_notifications = request.POST.get('push_notifications') == 'on'
|
|
user.save()
|
|
|
|
return render(request, 'users/profile.html', {
|
|
'success': 'Profile updated successfully.'
|
|
})
|