settings: avatar & username (& little stuff too)

This commit is contained in:
AdrienLSH 2024-03-11 15:21:47 +01:00
parent 6d942eea09
commit c65c986b25
19 changed files with 302 additions and 214 deletions

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-01 13:59+0100\n" "POT-Creation-Date: 2024-03-11 11:02+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,6 +17,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: serializers/update_user.py:15
msgid "You dont have permission for this user."
msgstr "Vous n'avez pas de permissions pour cet utilisateur."
#: views/login.py:22 #: views/login.py:22
msgid "Invalid username or password." msgid "Invalid username or password."
msgstr "Nom d'utilisateur ou mot de passe incorect." msgstr "Nom d'utilisateur ou mot de passe incorect."

View File

@ -0,0 +1,20 @@
from rest_framework.serializers import ModelSerializer, ValidationError
from django.contrib.auth.models import User
from django.utils.translation import gettext as _
class UpdateUserSerializer(ModelSerializer):
class Meta:
model = User
fields = ['username']
def update(self, instance, validated_data):
user = self.context['request'].user
if user.pk != instance.pk:
raise ValidationError({'authorize': _('You dont have permission for this user.')})
instance.username = validated_data.get('username', instance.username)
instance.save()
return instance

View File

@ -1,6 +1,6 @@
from django.urls import path from django.urls import path
from .views import register, login, logout, delete, edit, logged from .views import register, login, logout, delete, logged, update_profile
urlpatterns = [ urlpatterns = [
path("register", register.RegisterView.as_view(), name="register"), path("register", register.RegisterView.as_view(), name="register"),
@ -8,6 +8,5 @@ urlpatterns = [
path("logout", logout.LogoutView.as_view(), name="logout"), path("logout", logout.LogoutView.as_view(), name="logout"),
path("logged", logged.LoggedView.as_view(), name="logged"), path("logged", logged.LoggedView.as_view(), name="logged"),
path("delete", delete.DeleteView.as_view(), name="delete"), path("delete", delete.DeleteView.as_view(), name="delete"),
path("edit", edit.EditView.as_view(), name="change_password") path('update_profile', update_profile.UpdateProfileView.as_view(), name='update_profile')
]
]

View File

@ -5,17 +5,18 @@ from django.contrib.auth import logout
from django.http import HttpRequest from django.http import HttpRequest
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
class DeleteView(APIView): class DeleteView(APIView):
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def delete(self, request: HttpRequest): def delete(self, request: HttpRequest):
data: dict = request.data data: dict = request.data
password: str = data["password"] password: str = data["password"]
if (password is None): if (request.user.check_password(password) is False):
return Response({"password": ["This field may not be blank."]}) return Response({"password": ["Password incorrect."]},
if (request.user.check_password(password) == False): status.HTTP_401_UNAUTHORIZED)
return Response({"password": ["Password wrong."]})
request.user.delete() request.user.delete()
logout(request) logout(request)
return Response("user deleted", status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)

View File

@ -1,45 +0,0 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions, status
from django.http import HttpRequest
from django.contrib.auth import login
from rest_framework.authentication import SessionAuthentication
from django.contrib.auth.models import User
import re
class EditView(APIView):
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,)
def get(self, request: HttpRequest):
return Response({"username": request.user.username, "id": request.user.pk})
def patch(self, request: HttpRequest):
data: dict = request.data
current_password: str = data.get("current_password")
if (current_password is None):
return Response({"current_password": ["This field may not be blank."]})
user_object = request.user
if (user_object.check_password(current_password) == False):
return Response({"current_password": ["Password is wrong."]})
new_username = data.get("username", user_object.username)
if (new_username != user_object.username):
if (User.objects.filter(username=new_username).exists()):
return Response({"username": ["A user with that username already exists."]})
if (set(new_username) == {' '}):
return Response({"username": ["This field may not be blank."]})
if (re.search('^([a-z]||\@||\+||\-||\_)+$', new_username) is None):
return Response({"username":["Enter a valid username. This value may contain only letters, numbers, and @/./+/-/_ characters."]})
new_password: str = data.get("password")
if (new_password is not None):
user_object.set_password(new_password)
user_object.save()
return Response("data has been alterate")

View File

@ -2,15 +2,13 @@ from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import permissions, status from rest_framework import permissions, status
from django.http import HttpRequest from django.http import HttpRequest
from django.contrib.auth import login
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from ..serializers.login import LoginSerializer
class LoggedView(APIView): class LoggedView(APIView):
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def get(self, request: HttpRequest): def get(self, request: HttpRequest):
return Response(status = (status.HTTP_200_OK if request.user.is_authenticated else status.HTTP_400_BAD_REQUEST)) return Response(status=status.HTTP_200_OK if request.user.is_authenticated else status.HTTP_400_BAD_REQUEST)

View File

@ -8,8 +8,9 @@ from django.utils.translation import gettext as _
from ..serializers.login import LoginSerializer from ..serializers.login import LoginSerializer
class LoginView(APIView): class LoginView(APIView):
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)

View File

@ -5,9 +5,11 @@ from rest_framework.response import Response
from django.http import HttpRequest from django.http import HttpRequest
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
class LogoutView(APIView): class LogoutView(APIView):
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def get(self, request: HttpRequest): def get(self, request: HttpRequest):
logout(request) logout(request)
return Response("user unlogged", status=status.HTTP_200_OK) return Response("user logged out", status.HTTP_200_OK)

View File

@ -5,8 +5,10 @@ from rest_framework.response import Response
from django.http import HttpRequest from django.http import HttpRequest
from django.contrib.auth import login from django.contrib.auth import login
class RegisterView(APIView): class RegisterView(APIView):
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
def post(self, request: HttpRequest): def post(self, request: HttpRequest):
data = request.data data = request.data
serializer = RegisterSerialiser(data=data) serializer = RegisterSerialiser(data=data)

View File

@ -0,0 +1,14 @@
from ..serializers.update_user import UpdateUserSerializer
from rest_framework.generics import UpdateAPIView
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import User
class UpdateProfileView(UpdateAPIView):
queryset = User.objects.all()
permission_classes = (IsAuthenticated,)
serializer_class = UpdateUserSerializer
def get_object(self):
return self.queryset.get(pk=self.request.user.pk)

View File

@ -1,11 +1,3 @@
#app #avatar {
max-height: 10em;
max-width: 10em;
min-height: 6em;
min-width: 6em;
}
#popup { #popup {
position: fixed; position: fixed;
font-size: 1.2em; font-size: 1.2em;

View File

@ -1,11 +0,0 @@
#app * {
font-size: 30px;
}
#app #main
{
width: 60%;
display: flex;
flex-direction: column;
}

View File

@ -48,41 +48,24 @@ class Account
} }
/** /**
* Get account data (username) * @param {String} newUsername
* @returns {?Promise<Object>} * @returns {?Promise<Object>}
*/ */
async get() async updateUsername(newUsername)
{ {
let response = await this.client._get("/api/accounts/edit"); const data = {
let response_data = await response.json(); username: newUsername
};
const response = await this.client._patch_json(`/api/accounts/update_profile`, data);
const respondeData = await response.json();
if (response.status === 403) if (response.status === 200) {
{ this.client.me.username = respondeData.username;
this.client._update_logged(false); document.getElementById('navbarDropdownButton').innerHTML = respondeData.username;
document.getElementById('myProfileLink').href = '/profiles/' + respondeData.username;
return null; return null;
} }
return response_data; return respondeData['authorize'] || respondeData['detail'] || respondeData['username']?.join(' ') || 'Error.';
}
/**
*
* @param {*} data
* @param {Number} password
* @returns {?Object}
*/
async update(data, password)
{
data.current_password = password;
let response = await this.client._patch_json("/api/accounts/edit", data);
let response_data = await response.json();
if (response.status === 403)
{
this.client._update_logged(false);
return null;
}
return response_data;
} }
} }

View File

@ -14,15 +14,35 @@ class MyProfile extends Profile
/** /**
* *
* @param {*} form_data * @param {File} selectedFile
* @returns {Promise<Object>} * @returns {Promise<Response>}
*/ */
async change_avatar(form_data) async changeAvatar(selectedFile)
{ {
let response = await this.client._patch_file(`/api/profiles/settings`, form_data); const formData = new FormData();
let response_data = await response.json(); formData.append('avatar', selectedFile);
return response_data; const response = await this.client._patch_file(`/api/profiles/settings`, formData);
const responseData = await response.json();
if (response.ok) {
console.log('save', responseData);
this.avatar_url = responseData.avatar.substr(responseData.avatar.indexOf('static') - 1);
return null;
}
return responseData;
}
async deleteAvatar() {
const response = await this.client._delete('/api/profiles/settings');
const responseData = await response.json();
if (response.ok) {
console.log('delete', responseData);
this.avatar_url = responseData.avatar.substr(responseData.avatar.indexOf('static') - 1);
return null;
}
return responseData;
} }
} }

View File

@ -1,55 +1,82 @@
import { client, navigateTo } from "../index.js"; import { client, navigateTo } from '../index.js';
import { clear, fill_errors } from "../utils/formUtils.js"; import { clear, fill_errors } from '../utils/formUtils.js';
import AbstractAuthenticatedView from "./abstracts/AbstractAuthenticatedView.js"; import AbstractAuthenticatedView from './abstracts/AbstractAuthenticatedView.js';
export default class extends AbstractAuthenticatedView export default class extends AbstractAuthenticatedView
{ {
constructor(params) constructor(params)
{ {
super(params, "Settings"); super(params, 'Settings');
this.PROFILE_PICTURE_MAX_SIZE = 2 * 1024 * 1024; // 2MB this.PROFILE_PICTURE_MAX_SIZE = 2 * 1024 * 1024; // 2MB
} }
async postInit() async postInit()
{ {
this.display_avatar(); this.avatarInit();
document.getElementById("save-account-button").onclick = () => this.save_account(); this.usernameInit();
document.getElementById("delete-account-button").onclick = () => this.delete_account();
document.getElementById("save-profile-button").onclick = () => this.save_profile(); // document.getElementById('delete-account-button').onclick = () => this.delete_account();
} }
async display_avatar() { usernameInit() {
let profile = await client.profiles.getProfile(client.me.username); const usernameInput = document.getElementById('usernameInput');
if (profile !== undefined || profile !== null) { const usernameSave = document.getElementById('usernameSave');
if (document.getElementById("avatar") != undefined)
document.getElementById("avatar").remove(); usernameInput.oninput = e => {
let avatar = document.createElement("img"); const value = e.target.value;
avatar.id = "avatar"; if (value != client.me.username && value.length)
avatar.src = profile.avatar_url + '?t=' +new Date().getTime(); usernameSave.classList.remove('disabled');
document.getElementsByClassName("avatar")[0].appendChild(avatar); else
usernameSave.classList.add('disabled');
} }
usernameSave.onclick = _ => this.saveUsername();
}
avatarInit() {
const avatar = document.getElementById('avatar');
const avatarInput = document.getElementById('avatarInput');
const avatarUpload = document.getElementById('avatarUpload');
const avatarDelete = document.getElementById('avatarDelete');
avatar.onclick = _ => avatarInput.click();
avatarInput.onchange = function () {
const selectedFile = this.files[0];
if (!selectedFile)
return;
avatar.src = URL.createObjectURL(selectedFile);
avatarUpload.classList.remove('d-none');
}
avatarUpload.onclick = _ => this.saveAvatar();
avatarDelete.onclick = _ => this.deleteAvatar();
}
async displayAvatar() {
let avatar = document.getElementById('avatar');
avatar.src = client.me.avatar_url + '?t=' + new Date().getTime();
console.log(avatar.src);
} }
async delete_account() async delete_account()
{ {
let current_password = document.getElementById("current_password-input").value; let current_password = document.getElementById('current_password-input').value;
let response_data = await client.account.delete(current_password); let response_data = await client.account.delete(current_password);
if (response_data === null || response_data === "user deleted") if (response_data === null || response_data === 'user deleted')
{ {
navigateTo("/login"); navigateTo('/login');
return; return;
} }
clear("innerHTML", ["current_password-input"]); clear('innerHTML', ['current_password-input']);
fill_errors({"current_password-input": response_data.password}, "innerHTML"); fill_errors({'current_password-input': response_data.password}, 'innerHTML');
} }
async save_account() async save_account()
{ {
let username = document.getElementById("username-input").value; let username = document.getElementById('username-input').value;
let new_password = document.getElementById("new_password-input").value; let new_password = document.getElementById('new_password-input').value;
let current_password = document.getElementById("current_password-input").value; let current_password = document.getElementById('current_password-input').value;
let data = {}; let data = {};
@ -61,67 +88,139 @@ export default class extends AbstractAuthenticatedView
if (response_data === null) if (response_data === null)
{ {
navigateTo("/login"); navigateTo('/login');
return; return;
} }
if (response_data === "data has been alterate") if (response_data === 'data has been alterate')
response_data = {"save-account": "saved"}; response_data = {'save-account': 'saved'};
clear("innerHTML", ["username", "new_password", "current_password", "save-account", "delete-account"]); clear('innerHTML', ['username', 'new_password', 'current_password', 'save-account', 'delete-account']);
fill_errors(response_data, "innerHTML"); fill_errors(response_data, 'innerHTML');
}
async save_profile()
{
let avatar = document.getElementById("avatar-input");
if (avatar.files[0] !== undefined)
{
if (avatar.files[0].size > this.PROFILE_PICTURE_MAX_SIZE) {
document.getElementById("save-profile").classList.add('text-danger');
document.getElementById("save-profile").innerHTML = "Image too large :/";
return;
}
let form_data = new FormData();
form_data.append("avatar", avatar.files[0]);
await client.me.change_avatar(form_data);
this.display_avatar();
}
document.getElementById("save-profile").classList.remove('text-danger');
document.getElementById("save-profile").innerHTML = "Saved";
} }
async getHtml() async saveUsername()
{ {
return /* HTML */ ` const usernameInput = document.getElementById('usernameInput');
<link rel="stylesheet" href="/static/css/settings.css"> const username = usernameInput.value;
<h1>ME</h1> const usernameDetail = document.getElementById('usernameDetail');
<div id="main">
<div class="avatar">
</div>
<div class="account">
<h3>Account</h3>
<input type="text" placeholder="username" id="username-input" text=${client.me.username}>
<span id="username"></span>
<input type=password placeholder="new_password" id="new_password-input">
<span id="new_password"></span>
<input type=password placeholder="current_password" id="current_password-input">
<span id="current_password"></span>
<input type="button" value="Save Credentials" id="save-account-button"> if (!username.length || username === client.me.username)
<span id="save-account"></span> return;
<input type="button" value="Delete Account" id="delete-account-button">
<span id="delete-account"></span> const error = await client.account.updateUsername(username);
</div> if (!error) {
<div class="profile"> usernameDetail.classList.remove('text-danger');
<h3>Profile</h3> usernameDetail.classList.add('text-success');
<input type="file" id="avatar-input" accept="image/*"> usernameDetail.innerHTML = 'Username Saved.';
<input type="button" value="Save profile" id="save-profile-button"> setTimeout(_ => usernameDetail.innerHTML = '', 2000);
<span id="save-profile"></span> document.getElementById('usernameSave').classList.add('disabled');
</div> } else {
<a href="/logout" class="nav__link" data-link>Logout</a> usernameDetail.classList.remove('text-success');
</div> usernameDetail.classList.add('text-danger');
`; usernameDetail.innerHTML = error;
} document.getElementById('usernameSave').classList.add('disabled');
console.log(error);
}
}
async saveAvatar()
{
const avatarInput = document.getElementById('avatarInput');
const selectedFile = avatarInput.files[0];
const avatarDetail = document.getElementById('avatarDetail');
if (!selectedFile)
return;
if (selectedFile.size > this.PROFILE_PICTURE_MAX_SIZE) {
avatarDetail.classList.remove('text-success');
avatarDetail.classList.add('text-danger');
avatarDetail.innerHTML = 'Image is too large.'; //to translate
return;
}
const error = await client.me.changeAvatar(selectedFile);
if (!error) {
avatarDetail.classList.remove('text-danger');
avatarDetail.classList.add('text-success');
avatarDetail.innerHTML = 'Avatar saved.'; //to translate
setTimeout(_ => avatarDetail.innerHTML = '', 2000);
document.getElementById('avatarDelete').classList.remove('d-none');
document.getElementById('avatarUpload').classList.add('d-none');
avatarInput.value = null;
} else {
avatarDetail.classList.remove('text-success');
avatarDetail.classList.add('text-danger');
avatarDetail.innerHTML = error.avatar[0];
document.getElementById('avatarUpload').classList.add('d-none');
avatarInput.value = null;
console.log(error);
}
this.displayAvatar();
}
async deleteAvatar() {
const avatarDetail = document.getElementById('avatarDetail');
const error = await client.me.deleteAvatar();
if (!error) {
avatarDetail.classList.remove('text-danger');
avatarDetail.classList.add('text-success');
avatarDetail.innerHTML = 'Avatar deleted.'; //to translate
setTimeout(_ => avatarDetail.innerHTML = '', 2000);
document.getElementById('avatarDelete').classList.add('d-none');
} else {
avatarDetail.classList.remove('text-success');
avatarDetail.classList.add('text-danger');
avatarDetail.innerHTML = 'Something went wrong.'; //to translate
}
this.displayAvatar();
}
async getHtml()
{
const avatarUnchanged = client.me.avatar_url === '/static/avatars/default.avif';
return /* HTML */ `
<div class='container col-sm-10 col-8 d-flex rounded border border-2 bg-light-subtle py-3'>
<div class='row col-4 bg-body-tertiary border rounded p-2 m-2 d-flex justify-content-center align-items-center'>
<h2 class='border-bottom'>Avatar</h2>
<img id='avatar' class='rounded p-0' src=${client.me.avatar_url} style='cursor: pointer;'>
<input id='avatarInput' class='d-none' type='file' accept='image/*'>
<div class='d-flex gap-2 mt-1 px-0'>
<span class='my-auto ms-1 me-auto' id='avatarDetail'></span>
<button class='btn btn-primary d-none' id='avatarUpload'>Save</button>
<button class='btn btn-danger${avatarUnchanged ? ' d-none' : ''}' id='avatarDelete'>Delete</button>
</div>
</div>
<div class='flex-grow-1'>
<h1 class='border-bottom ps-1 mb-3'>Account</h1>
<div>
<div class='input-group'>
<div class='form-floating'>
<input type='text' class='form-control' id='usernameInput' placeholder='username' value=${client.me.username}>
<label for='usernameInput'>Username</label>
</div>
<button class='input-group-text btn btn-success disabled' id='usernameSave'>Save</button>
</div>
<span class='form-text' id='usernameDetail'></span>
</div>
</div>
</div>
`;
// <input class='form-control' type='text' placeholder='Username' id='username-input' value=${client.me.username}>
// <h1>Settings</h1>
// <input class='form-control d-inline-block' type='text' placeholder='Username' id='username-input' value=${client.me.username}>
// <span id='username'></span>
// <input type=password placeholder='New Password' id='new_password-input'>
// <span id='new_password'></span>
// <input type=password placeholder='Current Password' id='current_password-input'>
// <span id='current_password'></span>
// <input type='button' value='Save Credentials' id='save-account-button'>
// <span id='save-account'></span>
//
// <input type='button' value='Delete Account' id='delete-account-button'>
// <span id='delete-account'></span>
}
} }

View File

@ -3,16 +3,17 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models.signals import post_save, pre_delete from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.conf import settings
from django.db.models import IntegerField from django.db.models import IntegerField
from games.consumers import game_manager from games.consumers import game_manager
from os.path import splitext from os.path import splitext
def upload_to(instance, filename: str): def upload_to(instance, filename: str):
return f"./profiles/static/avatars/{instance.pk}{splitext(filename)[1]}" return f"./profiles/static/avatars/{instance.pk}{splitext(filename)[1]}"
# Create your models here. # Create your models here.
class ProfileModel(models.Model): class ProfileModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)

View File

@ -1,6 +1,8 @@
from rest_framework import serializers from rest_framework import serializers
from .models import ProfileModel from .models import ProfileModel
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext as _
class ProfileSerializer(serializers.ModelSerializer): class ProfileSerializer(serializers.ModelSerializer):
@ -16,5 +18,5 @@ class ProfileSerializer(serializers.ModelSerializer):
Check that the image is not too large Check that the image is not too large
''' '''
if value.size > settings.PROFILE_PICTURE_MAX_SIZE: if value.size > settings.PROFILE_PICTURE_MAX_SIZE:
raise serializers.ValidationError('Image is too large.'); raise serializers.ValidationError(_('Image is too large.'))
return value; return value

View File

@ -4,7 +4,7 @@ from . import viewsets
from . import views from . import views
urlpatterns = [ urlpatterns = [
path("settings", viewsets.MyProfileViewSet.as_view({'patch': 'partial_update'}), name="my_profile_page"), path("settings", viewsets.MyProfileViewSet.as_view({'patch': 'partial_update', 'delete': 'delete_avatar'}), name="my_profile_page"),
path("me", viewsets.MyProfileViewSet.as_view({'get': 'retrieve'}), name="my_profile_page"), path("me", viewsets.MyProfileViewSet.as_view({'get': 'retrieve'}), name="my_profile_page"),
path("", viewsets.ProfileViewSet.as_view({'get': 'list'}), name="profiles_list"), path("", viewsets.ProfileViewSet.as_view({'get': 'list'}), name="profiles_list"),
path("block", views.BlocksView.as_view(), name="block_page"), path("block", views.BlocksView.as_view(), name="block_page"),
@ -12,5 +12,4 @@ urlpatterns = [
path("friend", views.FriendsView.as_view(), name="friend_page"), path("friend", views.FriendsView.as_view(), name="friend_page"),
path("user/<str:username>", viewsets.ProfileViewSet.as_view({'get': 'retrieve'}), name="profile_page"), path("user/<str:username>", viewsets.ProfileViewSet.as_view({'get': 'retrieve'}), name="profile_page"),
path("id/<int:pk>", viewsets.ProfileViewSet.as_view({'get': 'retrieve_id'}), name="profile_page"), path("id/<int:pk>", viewsets.ProfileViewSet.as_view({'get': 'retrieve_id'}), name="profile_page"),
] ]

View File

@ -1,4 +1,3 @@
from rest_framework import permissions
from rest_framework.parsers import MultiPartParser, FormParser from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework import permissions, status from rest_framework import permissions, status
from rest_framework import viewsets from rest_framework import viewsets
@ -42,28 +41,35 @@ class ProfileViewSet(viewsets.ModelViewSet):
profile["avatar"] = profile["avatar"][profile["avatar"].find("static") - 1:] profile["avatar"] = profile["avatar"][profile["avatar"].find("static") - 1:]
return Response(serializer.data) return Response(serializer.data)
class MyProfileViewSet(viewsets.ModelViewSet):
class MyProfileViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
serializer_class = ProfileSerializer serializer_class = ProfileSerializer
queryset = ProfileModel.objects.all queryset = ProfileModel.objects.all()
def get_object(self): def get_object(self):
obj = self.queryset().get(pk=self.request.user.pk) obj = self.queryset.get(pk=self.request.user.pk)
return obj return obj
def perform_update(self, serializer, pk=None): def perform_update(self, serializer: ProfileSerializer, pk=None):
serializer.is_valid(raise_exception=True); serializer.is_valid(raise_exception=True)
profile: ProfileModel = self.get_object(); avatar = serializer.validated_data.get('avatar')
avatar = serializer.validated_data.get('avatar'); profile: ProfileModel = self.get_object()
if (avatar is not None): if (avatar is not None):
if (profile.avatar.name != "./profiles/static/avatars/default.avif"): if (profile.avatar.name != "./profiles/static/avatars/default.avif"):
profile.avatar.storage.delete(profile.avatar.name) profile.avatar.storage.delete(profile.avatar.name)
profile.avatar = avatar serializer.save()
profile.save()
def delete_avatar(self, request, pk=None):
profile = self.get_object()
if (profile.avatar.name != './profiles/static/avatars/default.avif'):
profile.avatar.storage.delete(profile.avatar.name)
profile.avatar.name = './profiles/static/avatars/default.avif'
profile.save()
return Response(ProfileSerializer(profile).data)
def retrieve(self, request: HttpRequest, pk=None): def retrieve(self, request: HttpRequest, pk=None):
instance: ProfileModel = self.get_object() instance: ProfileModel = self.get_object()
instance.avatar.name = instance.avatar.name[instance.avatar.name.find("static") - 1:] instance.avatar.name = instance.avatar.name[instance.avatar.name.find("static") - 1:]