working FileIndex and user Profile pages/settings
This commit is contained in:
+137
-4
@@ -1,11 +1,18 @@
|
||||
import hashlib
|
||||
import io
|
||||
import secrets
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth import authenticate, get_user_model, login, logout, update_session_auth_hash
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
|
||||
from django.shortcuts import redirect, render
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm, UserCreationForm
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import default_storage
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
|
||||
from library.models import FileIndex
|
||||
|
||||
from .forms import AvatarForm, BioForm, EmailForm, UsernameForm
|
||||
from .models import ApiToken, UserProfile
|
||||
|
||||
|
||||
@@ -37,7 +44,12 @@ def user_login(request):
|
||||
|
||||
def user_logout(request):
|
||||
if request.method == 'POST':
|
||||
was_authorized = request.session.get('authorized', False)
|
||||
logout(request)
|
||||
# logout() flushes the session (wiping the gate flag). The gate is a
|
||||
# site-wide master password, separate from user accounts — preserve it.
|
||||
if was_authorized:
|
||||
request.session['authorized'] = True
|
||||
return redirect('landing:home')
|
||||
return redirect('landing:home')
|
||||
|
||||
@@ -67,4 +79,125 @@ def token_create(request):
|
||||
@login_required
|
||||
def token_delete(request, token_id):
|
||||
ApiToken.objects.filter(id=token_id, user=request.user).delete()
|
||||
return redirect('profiles:settings')
|
||||
return redirect('profiles:settings')
|
||||
|
||||
|
||||
def _jpeg_bytes(uploaded):
|
||||
"""Return JPEG bytes for an uploaded image.
|
||||
|
||||
Already-JPEG uploads are stored as-is; anything else is re-encoded
|
||||
to JPEG via Pillow.
|
||||
"""
|
||||
import PIL.Image
|
||||
|
||||
image = PIL.Image.open(uploaded)
|
||||
if image.format == 'JPEG':
|
||||
uploaded.seek(0)
|
||||
return uploaded.read()
|
||||
|
||||
if image.mode not in ('RGB', 'L'):
|
||||
image = image.convert('RGB')
|
||||
buffer = io.BytesIO()
|
||||
image.save(buffer, format='JPEG', quality=88)
|
||||
return buffer.getvalue()
|
||||
|
||||
|
||||
def _store_avatar(user, uploaded):
|
||||
"""Persist an avatar under /avatars/user_<id>/picture.jpeg, index it in
|
||||
FileIndex, and return the FileIndex row (replacing any previous avatar)."""
|
||||
profile, _ = UserProfile.objects.get_or_create(user=user)
|
||||
|
||||
old_index = profile.avatar
|
||||
if old_index is not None:
|
||||
if old_index.stored_path and default_storage.exists(old_index.stored_path):
|
||||
default_storage.delete(old_index.stored_path)
|
||||
FileIndex.objects.filter(pk=old_index.pk).delete()
|
||||
profile.avatar = None
|
||||
|
||||
data = _jpeg_bytes(uploaded)
|
||||
stored_path = f'avatars/user_{user.pk}/picture.jpeg'
|
||||
actual_path = default_storage.save(stored_path, ContentFile(data))
|
||||
file_index = FileIndex.objects.create(
|
||||
owner=user,
|
||||
kind='avatar',
|
||||
stored_path=actual_path,
|
||||
original_filename=getattr(uploaded, 'name', '') or 'picture.jpeg',
|
||||
content_type='image/jpeg',
|
||||
size=len(data),
|
||||
md5=hashlib.md5(data).hexdigest(),
|
||||
)
|
||||
profile.avatar = file_index
|
||||
profile.save(update_fields=['avatar'])
|
||||
return file_index
|
||||
|
||||
|
||||
@login_required
|
||||
def account_page(request):
|
||||
username_form = UsernameForm(instance=request.user)
|
||||
email_form = EmailForm(instance=request.user)
|
||||
password_form = PasswordChangeForm(request.user)
|
||||
avatar_form = AvatarForm()
|
||||
|
||||
if request.method == 'POST':
|
||||
action = request.POST.get('action')
|
||||
if action == 'username':
|
||||
username_form = UsernameForm(request.POST, instance=request.user)
|
||||
if username_form.is_valid():
|
||||
username_form.save()
|
||||
messages.success(request, 'Username updated.')
|
||||
return redirect('profiles:account')
|
||||
messages.error(request, 'Could not update username.')
|
||||
elif action == 'email':
|
||||
email_form = EmailForm(request.POST, instance=request.user)
|
||||
if email_form.is_valid():
|
||||
email_form.save()
|
||||
messages.success(request, 'Email updated.')
|
||||
return redirect('profiles:account')
|
||||
messages.error(request, 'Could not update email.')
|
||||
elif action == 'password':
|
||||
password_form = PasswordChangeForm(request.user, request.POST)
|
||||
if password_form.is_valid():
|
||||
user = password_form.save()
|
||||
update_session_auth_hash(request, user)
|
||||
messages.success(request, 'Password updated.')
|
||||
return redirect('profiles:account')
|
||||
messages.error(request, 'Could not update password.')
|
||||
elif action == 'avatar':
|
||||
avatar_form = AvatarForm(request.POST, request.FILES)
|
||||
if avatar_form.is_valid():
|
||||
_store_avatar(request.user, avatar_form.cleaned_data['avatar'])
|
||||
messages.success(request, 'Profile picture updated.')
|
||||
return redirect('profiles:account')
|
||||
messages.error(request, 'Could not update profile picture.')
|
||||
|
||||
context = {
|
||||
'username_form': username_form,
|
||||
'email_form': email_form,
|
||||
'password_form': password_form,
|
||||
'avatar_form': avatar_form,
|
||||
}
|
||||
return render(request, 'profiles/account.html', context)
|
||||
|
||||
|
||||
def user_profile(request, username):
|
||||
User = get_user_model()
|
||||
user = get_object_or_404(User, username__iexact=username)
|
||||
profile, created = UserProfile.objects.get_or_create(user=user)
|
||||
is_owner = request.user.is_authenticated and request.user.pk == user.pk
|
||||
bio_form = None
|
||||
if is_owner:
|
||||
if request.method == 'POST' and request.POST.get('action') == 'bio':
|
||||
bio_form = BioForm(request.POST, instance=profile)
|
||||
if bio_form.is_valid():
|
||||
bio_form.save()
|
||||
messages.success(request, 'Bio updated.')
|
||||
return redirect('profiles:user_profile', username=user.username)
|
||||
messages.error(request, 'Could not update bio.')
|
||||
else:
|
||||
bio_form = BioForm(instance=profile)
|
||||
return render(request, 'profiles/profile.html', {
|
||||
'profile': profile,
|
||||
'profile_user': user,
|
||||
'is_owner': is_owner,
|
||||
'bio_form': bio_form,
|
||||
})
|
||||
Reference in New Issue
Block a user