Merge pull request #76 from Simple2B/svyat/fix/avatar_size

limit avatar file size, delete avatar
This commit is contained in:
Svyatoslav Artymovych 2023-05-26 14:05:21 +03:00 committed by GitHub
commit 7094101581
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 10 deletions

View File

@ -1,3 +1,5 @@
import base64
from flask_wtf import FlaskForm
from wtforms import (
StringField,
@ -58,7 +60,7 @@ class NewUserForm(FlaskForm):
class EditUserForm(FlaskForm):
name = StringField("Name", [DataRequired()])
avatar_img = FileField("Avatar file (max 200x200px)")
avatar_img = FileField("Avatar file (max 1mb)")
submit = SubmitField("Save")
def validate_username(self, field):
@ -69,6 +71,16 @@ class EditUserForm(FlaskForm):
):
raise ValidationError("This username is taken.")
def validate_avatar_img(self, field):
if field.data:
img_data = field.data.read()
img_data = base64.b64encode(img_data)
img_data = img_data.decode("utf-8")
field.data = img_data
size = len(img_data) / 1000000
if size > 1:
raise ValidationError("Avatar file size too large")
class ReactivateUserForm(FlaskForm):
submit = SubmitField("Save")

View File

@ -35,19 +35,24 @@
<div class="flex items-center mb-3">
<div>
{% if current_user.avatar_img %}
<img class=" w-14 h-14 rounded-full mr-3" src="data:image/jpeg;base64,{{ current_user.avatar_img }}" alt="user avatar">
<img class="w-14 h-14 rounded-full mr-3" src="data:image/jpeg;base64,{{ current_user.avatar_img }}" alt="user avatar">
{% else %}
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 56 56" stroke-width="1.5" stroke="currentColor" class="w-14 h-14"> <path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-14 h-14 mr-2"> <path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" /> </svg>
{% endif %}
</div>
<div>
{{form.avatar_img(type='file', class='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500', id="avatar_img",
value=current_user.avatar_img if current_user.avatar_img else "")}}</div>
</div>
<button type="submit" class="w-full px-5 py-3 text-base font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 sm:w-auto dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save changes</button>
</form>
<button type="button" data-modal-target="delete_profile_modal" data-modal-toggle="delete_profile_modal" class="text-red-700 hover:text-white border border-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600 dark:focus:ring-red-900">Delete you profile</button>
<div class="flex">
<form action="{{ url_for('user.delete_avatar') }}" class="mb-0" method="POST">
<button type="submit" class="text-red-700 hover:text-white border border-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600 dark:focus:ring-red-900">Delete Avatar</button>
</form>
<button type="button" data-modal-target="delete_profile_modal" data-modal-toggle="delete_profile_modal" class="text-red-700 hover:text-white border border-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600 dark:focus:ring-red-900">Delete you profile</button>
</div>
</div>
</div>
</div>

View File

@ -1,5 +1,3 @@
import base64
from flask import Blueprint, render_template, request, flash, redirect, url_for, jsonify
from flask_login import login_required, current_user, logout_user
from app.controllers import create_pagination
@ -40,9 +38,9 @@ def edit_profile():
user: m.User = current_user
user.username = form.name.data
if form.avatar_img.data:
img_data = form.avatar_img.data.read()
img_data = base64.b64encode(img_data)
current_user.avatar_img = img_data.decode("utf-8")
current_user.avatar_img = (
form.avatar_img.data
) # form.avatar_img.data is changed in form validator
user.is_activated = True
user.save()
return redirect(url_for("main.index"))
@ -58,6 +56,17 @@ def edit_profile():
return render_template("user/edit_profile.html", form=form)
@bp.route("/delete_avatar", methods=["POST"])
@login_required
def delete_avatar():
user: m.User = current_user
current_user.avatar_img = None
log(log.ERROR, "Delete user [%s] avatar", user)
current_user.save()
return redirect(url_for("user.edit_profile"))
@bp.route("/<int:user_id>/profile")
def profile(user_id: int):
user: m.User = db.session.get(m.User, user_id)

View File

@ -133,6 +133,15 @@ def test_profile(client):
assert res.status_code == 200
assert str.encode(new_name) in res.data
# delete_avatar
assert user.avatar_img
res = client.post(
"/user/delete_avatar",
follow_redirects=True,
)
assert res
assert not user.avatar_img
# delete_profile
res = client.post(
"/user/profile_delete",