added profile page (edit-change to edit_profile)

This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-12 17:05:30 +03:00
parent 53bc7810b2
commit c82912d6da
11 changed files with 146316 additions and 95 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,7 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% endif %} {% endif %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="flex flex-col w-4/5">
{% for book in books if not book.is_deleted%} {% for book in books if not book.is_deleted%}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 h-max w-full p-5 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700"> <dl class="bg-white dark:bg-gray-900 h-max w-full p-5 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
@ -45,6 +46,7 @@
</dd> </dd>
</dl> </dl>
{% endfor %} {% endfor %}
</div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% if current_user.is_authenticated and page.pages > 1 %} {% if current_user.is_authenticated and page.pages > 1 %}
<div class="container content-center mt-3 flex bg-white dark:bg-gray-800"> <div class="container content-center mt-3 flex bg-white dark:bg-gray-800">

View File

@ -64,7 +64,7 @@
<p class="text-center text-sm text-gray-900 dark:text-white" role="none"> {{current_user.username}} </p> <p class="text-center text-sm text-gray-900 dark:text-white" role="none"> {{current_user.username}} </p>
</div> </div>
<div class="px-4 py-3" role="none"> <div class="px-4 py-3" role="none">
<a class="text-center text-sm text-gray-900 dark:text-white" role="none" href="{{ url_for('user.profile') }}"> Edit profile </a> <a class="text-center text-sm text-gray-900 dark:text-white" role="none" href="{{ url_for('user.edit_profile') }}"> Edit profile </a>
</div> </div>
<ul class="py-1" role="none"> <ul class="py-1" role="none">
<li> <li>

View File

@ -13,8 +13,8 @@
<ul class="flex md:flex-wrap -mb-px text-xs md:text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist"> <ul class="flex md:flex-wrap -mb-px text-xs md:text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist">
<li class="mr-2 w-full md:w-auto" role="presentation"> <li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 rounded-t-lg" id="last-sections-tab" data-tabs-target="#last-sections" type="button" role="tab" aria-controls="last-sections" aria-selected="false"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-3"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg> <button class="inline-flex p-4 border-b-2 rounded-t-lg" id="last-interpretations-tab" data-tabs-target="#last-interpretations" type="button" role="tab" aria-controls="last-interpretations" aria-selected="false"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-3"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>
LAtest Interpretations Latest Interpretations
</button> </button>
</li> </li>
<li class="mr-2 w-full md:w-auto" role="presentation"> <li class="mr-2 w-full md:w-auto" role="presentation">
@ -27,7 +27,7 @@
</div> </div>
<div id="myTabContent" class="md:mr-64"> <div id="myTabContent" class="md:mr-64">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="last-sections" role="tabpanel" aria-labelledby="last-sections-tab"> <div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="last-interpretations" role="tabpanel" aria-labelledby="last-interpretations-tab">
{% for interpretation in interpretations %} {% for interpretation in interpretations %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700"> <dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">

View File

@ -18,7 +18,7 @@
</span> </span>
</li> </li>
<li class="md:hidden"> <li class="md:hidden">
<a href="{{ url_for('user.profile') }}" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700"> <a href="{{ url_for('user.edit_profile') }}" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /> </svg>
<span class="ml-3">Edit profile</span> <span class="ml-3">Edit profile</span>

View File

@ -0,0 +1,57 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% include 'user/delete_profile_modal.html' %}
{% block content %}
<!-- component -->
<section>
<div class="w-full lg:w-4/12 px-4 mx-auto pt-6">
<div>
<!-- prettier-ignore -->
<div class="w-full lg:max-w-xl p-6 space-y-8 sm:p-8 bg-white rounded-lg shadow-xl dark:bg-gray-800">
{% if current_user.is_activated %}
<!-- prettier-ignore -->
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">Edit your profile</h2>
{% else %}
<!-- prettier-ignore -->
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">Create your profile</h2>
{% endif %}
<div>
<!-- prettier-ignore -->
<label class='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>Account</label>
<input type="text" 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' autocomplete="off" onCopy="return false" readonly value="{{current_user.wallet_id}}">
</div>
<!-- prettier-ignore -->
<form class="mt-8 space-y-6 from" role="form" action="{{ url_for('user.edit_profile') }}" method="post" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div>
<!-- prettier-ignore -->
{{form.name.label(class='block mb-2 text-sm font-medium text-gray-900 dark:text-white')}}
{{form.name(autocomplete="off", 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')}}
</div>
<!-- prettier-ignore -->
{{form.avatar_img.label(class='block mb-2 text-sm font-medium text-gray-900 dark:text-white')}}
<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">
{% 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>
{% 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>
</div>
</div>
</section>
{% block right_sidebar %}{% endblock %}
<!-- prettier-ignore -->
{% endblock %}

View File

@ -1,58 +1,140 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% extends 'base.html' %} {% extends 'base.html' %}
{% include 'user/delete_profile_modal.html' %}
{% block content %} {% block content %}
<!-- component --> <div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<section> <div class="flex p-5 items-center">
<div class="w-full lg:w-4/12 px-4 mx-auto pt-6">
<div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="w-full lg:max-w-xl p-6 space-y-8 sm:p-8 bg-white rounded-lg shadow-xl dark:bg-gray-800"> {% if user.avatar_img %}
{% if current_user.is_activated %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">Edit your profile</h2> <img class=" w-10 h-10 rounded-full mr-3" src="data:image/jpeg;base64,{{ current_user.avatar_img }}" alt="user avatar">
{% endif %}
{% if not current_user.is_activated %}
<!-- prettier-ignore -->
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">Create your profile</h2>
{% endif %}
<div>
<!-- prettier-ignore -->
<label class='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>Account</label>
<input type="text" 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' autocomplete="off" onCopy="return false" readonly value="{{current_user.wallet_id}}">
</div>
<!-- prettier-ignore -->
<form class="mt-8 space-y-6 from" role="form" action="{{ url_for('user.profile') }}" method="post" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div>
<!-- prettier-ignore -->
{{form.name.label(class='block mb-2 text-sm font-medium text-gray-900 dark:text-white')}}
{{form.name(autocomplete="off", 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')}}
</div>
<!-- prettier-ignore -->
{{form.avatar_img.label(class='block mb-2 text-sm font-medium text-gray-900 dark:text-white')}}
<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">
{% else %} {% 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> <!-- prettier-ignore -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-10 h-10"> <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 %}
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4">{{user.username}}</h1>
<!-- prettier-ignore -->
<span class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400">
{{user.wallet_id}}
</span>
</div>
<!-- prettier-ignore -->
<ul class="flex md:flex-wrap -mb-px text-xs md:text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist">
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 rounded-t-lg" id="library-tab" data-tabs-target="#library" type="button" role="tab" aria-controls="library" aria-selected="false"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-3"> <path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" /> </svg>
Library
</button>
</li>
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="contributions-tab" data-tabs-target="#contributions" type="button" role="tab" aria-controls="contributions" aria-selected="false"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-3"> <path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" /> </svg>
Contributions
</button>
</li>
</ul>
</div>
<div id="myTabContent" class="md:mr-64">
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="library" role="tabpanel" aria-labelledby="library-tab">
{% for book in user.books if not book.is_deleted %}
<!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 h-max w-full p-5 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<dt class="mb-2"><a class="flex flex-col pb-4" href="{{url_for('book.collection_view',book_id=book.id)}}">{{book.owner.username}}/{{book.label}}</a></dt>
<dd class="flex flex-col md:flex-row text-lg font-semibold text-gray-500 md:text-lg dark:text-gray-400">
{% if book.versions %}
<p>
Last updated on {{book.versions[-1].updated_at.strftime('%B %d, %Y')}}
</p>
{% endif %}
<div class="flex ml-auto align-center justify-center space-x-3">
<span class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" /> </svg>
<p>{{ book.stars|length }}</p>
</span>
<span class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>
<p>55</p>
</span>
<span class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /> </svg>
<p>55</p>
</span>
</div>
</dd>
</dl>
{% endfor %}
</div>
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="contributions" role="tabpanel" aria-labelledby="contributions-tab">
{% for interpretation in interpretations %}
<!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<div class="flex flex-row pb-3 p-3 w-2/3 md:w-10/12">
<div class="vote-block flex flex-col m-5 justify-center items-center">
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="true">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote %}
stroke-green-500
{% endif %}
" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" > <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18" /> </svg>
</div>
{% endif %}
<span
class="vote-count text-3xl select-none
{% if interpretation.vote_count < 0 %}
text-red-500
{% elif interpretation.vote_count > 0 %}
text-green-500
{% endif %}
"
>
{{ interpretation.vote_count }}
</span>
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="false">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote == False %}
stroke-red-500
{% endif %}
" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3" /> </svg>
</div>
{% endif %} {% endif %}
</div> </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>
</div>
</div>
</section>
{% block right_sidebar %}{% endblock %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
<div class="ql-snow truncate md:max-w-xl">
{% set local_breadcrumbs = interpretation.section.breadcrumbs_path %}
{% include 'book/local_breadcrumbs_navigation.html'%}
<p>{{ interpretation.section.label }}</p>
</a>
<div class="dark:text-white h-30 ql-editor">
<p>{{ interpretation.text|safe }}</p>
</div>
</div>
<div class="flex mt-auto align-center justify-between md:w-full">
<div>
<span class="hidden md:inline-block">Interpretation by</span>
{{interpretation.user.username}} on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div>
<div class="flex ml-auto justify-between w-24">
<span class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15m0-3l-3-3m0 0l-3 3m3-3V15" /> </svg>
</span>
<div class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" /> </svg>
<p>{{interpretation.active_comments | length}}</p>
</div>
</div>
</div>
</dt>
</div>
</dl>
{% endfor %}
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -102,7 +102,7 @@ def verify():
login_user(user=user) login_user(user=user)
log(log.INFO, "Register new user") log(log.INFO, "Register new user")
flash("User created and logged in successful.", "success") flash("User created and logged in successful.", "success")
return redirect(url_for("user.profile")) return redirect(url_for("user.edit_profile"))
login_user(user=user) login_user(user=user)
log(log.INFO, "Verify success.") log(log.INFO, "Verify success.")
flash("Verify success.", "success") flash("Verify success.", "success")

View File

@ -32,9 +32,9 @@ def get_all():
) )
@bp.route("/profile", methods=["GET", "POST"]) @bp.route("/edit_profile", methods=["GET", "POST"])
@login_required @login_required
def profile(): def edit_profile():
form = f.EditUserForm() form = f.EditUserForm()
if form.validate_on_submit(): if form.validate_on_submit():
user: m.User = current_user user: m.User = current_user
@ -55,31 +55,22 @@ def profile():
if current_user.is_activated: if current_user.is_activated:
form.name.data = current_user.username form.name.data = current_user.username
return render_template("user/profile.html", form=form) return render_template("user/edit_profile.html", form=form)
@bp.route("/save", methods=["POST"]) @bp.route("/<int:user_id>/profile")
@login_required @login_required
def save(): def profile(user_id: int):
form = f.UserForm() user: m.User = m.User.query.get(user_id)
if form.validate_on_submit(): interpretations: m.Interpretation = m.Interpretation.query.filter_by(
u: m.User = m.User.query.get(int(form.user_id.data)) user_id=user_id
if not u: )
log(log.ERROR, "Not found user by id : [%s]", form.user_id.data) if not user:
flash("Cannot save user data", "danger") log(log.ERROR, "Not found user by id : [%s]", user_id)
u.username = form.username.data flash("Cannot find user data", "danger")
u.activated = form.activated.data return render_template(
if form.password.data.strip("*\n "): "user/profile.html", user=user, interpretations=interpretations
u.password = form.password.data )
u.save()
if form.next_url.data:
return redirect(form.next_url.data)
return redirect(url_for("user.get_all"))
else:
log(log.ERROR, "User save errors: [%s]", form.errors)
flash(f"{form.errors}", "danger")
return redirect(url_for("user.get_all"))
@bp.route("/create", methods=["POST"]) @bp.route("/create", methods=["POST"])

View File

@ -100,23 +100,20 @@ def test_profile(client):
) )
login(client, username=user.username, password="password") login(client, username=user.username, password="password")
# edit_profile
new_name = "Some other name"
res = client.post( res = client.post(
"/user/profile", "/user/edit_profile",
data={ data={
"name": "Some other name", "name": new_name,
"avatar_img": avatar_img, "avatar_img": avatar_img,
}, },
follow_redirects=True, follow_redirects=True,
) )
assert res.status_code == 200 assert res.status_code == 200
assert user.username == "Some other name" assert user.username == new_name
assert user.is_activated assert user.is_activated
assert user.avatar_img assert user.avatar_img
res2 = client.post(
"/user/profile",
follow_redirects=True,
)
assert b"This field is required." in res2.data
book = m.Book( book = m.Book(
label="Book label", label="Book label",
about="Book about", about="Book about",
@ -125,6 +122,16 @@ def test_profile(client):
book.save() book.save()
assert book assert book
# profile page
res = client.get(
"/user/2/profile",
follow_redirects=True,
)
assert res
assert res.status_code == 200
assert str.encode(new_name) in res.data
# delete_profile # delete_profile
res = client.post( res = client.post(
"/user/profile_delete", "/user/profile_delete",