Merge branch 'develop' into svyat/fix/deleting_collections

This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-17 16:39:57 +03:00
commit 206411caa6
26 changed files with 286 additions and 3238 deletions

View File

@ -1,6 +1,6 @@
# flake8: noqa F401 # flake8: noqa F401
from .auth import LoginForm from .auth import LoginForm
from .user import UserForm, NewUserForm, EditUserForm from .user import UserForm, NewUserForm, EditUserForm, ReactivateUserForm
from .book import CreateBookForm, EditBookForm from .book import CreateBookForm, EditBookForm
from .contributor import ( from .contributor import (
AddContributorForm, AddContributorForm,

View File

@ -68,3 +68,7 @@ class EditUserForm(FlaskForm):
.first() .first()
): ):
raise ValidationError("This username is taken.") raise ValidationError("This username is taken.")
class ReactivateUserForm(FlaskForm):
submit = SubmitField("Save")

View File

@ -1,4 +1,5 @@
from flask_login import current_user from flask_login import current_user
from sqlalchemy import and_
from app import db, models as m from app import db, models as m
from app.models.utils import BaseModel from app.models.utils import BaseModel
@ -17,7 +18,7 @@ class Book(BaseModel):
owner = db.relationship("User", viewonly=True) owner = db.relationship("User", viewonly=True)
stars = db.relationship("User", secondary="books_stars", back_populates="stars") stars = db.relationship("User", secondary="books_stars", back_populates="stars")
contributors = db.relationship("BookContributor") contributors = db.relationship("BookContributor")
versions = db.relationship("BookVersion") versions = db.relationship("BookVersion", order_by="asc(BookVersion.id)")
def __repr__(self): def __repr__(self):
return f"<{self.id}: {self.label}>" return f"<{self.id}: {self.label}>"
@ -34,3 +35,55 @@ class Book(BaseModel):
).first() ).first()
if book_star: if book_star:
return True return True
@property
def approved_comments(self):
comments = (
db.session.query(
m.Comment,
)
.filter(
and_(
m.BookVersion.id == self.last_version.id,
m.Section.version_id == m.BookVersion.id,
m.Collection.id == m.Section.collection_id,
m.Interpretation.section_id == m.Section.id,
m.Comment.interpretation_id == m.Interpretation.id,
m.Comment.approved.is_(True),
m.Comment.is_deleted.is_(False),
m.BookVersion.is_deleted.is_(False),
m.Interpretation.is_deleted.is_(False),
m.Section.is_deleted.is_(False),
m.Collection.is_deleted.is_(False),
),
)
.order_by(m.Comment.created_at.desc())
.all()
)
return comments
@property
def approved_interpretations(self):
interpretations = (
db.session.query(
m.Interpretation,
)
.filter(
and_(
m.BookVersion.id == self.last_version.id,
m.Section.version_id == m.BookVersion.id,
m.Collection.id == m.Section.collection_id,
m.Interpretation.section_id == m.Section.id,
m.Interpretation.approved.is_(True),
m.BookVersion.is_deleted.is_(False),
m.Interpretation.is_deleted.is_(False),
m.Section.is_deleted.is_(False),
m.Collection.is_deleted.is_(False),
),
)
.order_by(m.Interpretation.created_at.desc())
.all()
)
return interpretations

View File

@ -1,5 +1,3 @@
from datetime import datetime
from flask_login import current_user from flask_login import current_user
from app import db, models as m from app import db, models as m
@ -13,7 +11,6 @@ class Interpretation(BaseModel):
text = db.Column(db.Text, unique=False, nullable=False) text = db.Column(db.Text, unique=False, nullable=False)
approved = db.Column(db.Boolean, default=False) approved = db.Column(db.Boolean, default=False)
marked = db.Column(db.Boolean, default=False) marked = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.now)
# Foreign keys # Foreign keys
user_id = db.Column(db.ForeignKey("users.id")) user_id = db.Column(db.ForeignKey("users.id"))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -74,9 +74,10 @@
{% block body %} {% block body %}
{% if current_user.is_authenticated %}
{% block right_sidebar %} {% include 'right_sidebar.html' %} {% endblock %} {% block right_sidebar %} {% include 'right_sidebar.html' %} {% endblock %}
{% include 'book/add_book_modal.html' %} {% include 'book/add_book_modal.html' %}
{% endif %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<script src="{{ url_for('static', filename='js/main.js') }}" type="text/javascript" defer></script> <script src="{{ url_for('static', filename='js/main.js') }}" type="text/javascript" defer></script>

View File

@ -25,11 +25,11 @@
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_interpretations|length }}</p>
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_comments|length }}</p>
</span> </span>
</div> </div>
</dd> </dd>

View File

@ -36,11 +36,11 @@
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_interpretations|length }}</p>
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_comments|length }}</p>
</span> </span>
</div> </div>
</dd> </dd>

View File

@ -1,16 +1,18 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% extends 'base.html' %} {% extends 'base.html' %}
{% if current_user.is_authenticated %}
{% include 'book/delete_section_modal.html' %} {% include 'book/delete_section_modal.html' %}
{% include 'book/edit_section_modal.html' %} {% include 'book/edit_section_modal.html' %}
<!-- show delete section btn on rightside bar -->
{% set show_delete_section = True %} {% set show_edit_section = True %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% set show_delete_section = True %}
<!-- prettier-ignore -->
{% set show_edit_section = True %}
{% block right_sidebar %} {% block right_sidebar %}
{% include 'book/right_sidebar.html' %} {% include 'book/right_sidebar.html' %}
{% endblock %} {% endblock %}
{% endif %}
{% block content %} {% block content %}
{% include 'book/breadcrumbs_navigation.html'%} {% include 'book/breadcrumbs_navigation.html'%}
@ -18,17 +20,10 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="fixed z-30 w-full top-44 pt-6 bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700"> <div class="fixed z-30 w-full top-44 pt-6 bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<h1 class="text-l font-extrabold dark:text-white ml-4"> Interpretations page </h1> <h1 class="text-l font-extrabold dark:text-white ml-4">{{section.label}}</h1>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="mb-1"> <div class="mb-1">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist"> <ul class="flex flex-wrap -mb-px text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist">
<li class="mr-2" role="presentation">
<!-- prettier-ignore -->
<button class="flex items-center space-x-2 p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="text-tab" data-tabs-target="#section-text" type="button" role="tab" aria-controls="text" 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"> <path stroke-linecap="round" stroke-linejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z" /> </svg>
<span>Text</span>
</button>
</li>
<li class="mr-2" role="presentation"> <li class="mr-2" role="presentation">
<button class="flex items-center space-x-2 p-4 border-b-2 rounded-t-lg" id="interpretation-tab" data-tabs-target="#interpretation" type="button" role="tab" aria-controls="interpretation" aria-selected="false"> <button class="flex items-center space-x-2 p-4 border-b-2 rounded-t-lg" id="interpretation-tab" data-tabs-target="#interpretation" type="button" role="tab" aria-controls="interpretation" 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"> <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.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9zm3.75 11.625a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 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-6 h-6"> <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.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9zm3.75 11.625a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" /> </svg>
@ -39,22 +34,6 @@
</div> </div>
</div> </div>
<div id="myTabContent" class="mt-40"> <div id="myTabContent" class="mt-40">
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="section-text" role="tabpanel" aria-labelledby="text-tab">
<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-col w-full">
<!-- 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">
<div class="ql-editor">
{{ section.about|safe }}
</div>
</div>
</dt>
</div>
</dl>
</div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="interpretation" role="tabpanel" aria-labelledby="interpretation-tab"> <div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="interpretation" role="tabpanel" aria-labelledby="interpretation-tab">
{% if not current_user.is_authenticated %} {% if not current_user.is_authenticated %}
@ -181,7 +160,7 @@
<div class="flex border-t-2 pt-3 mt-6 align-center justify-between md:w-full"> <div class="flex border-t-2 pt-3 mt-6 align-center justify-between md:w-full">
<div> <div>
<span class="hidden md:inline-block">Interpretation by</span> <span class="hidden md:inline-block">Interpretation by</span>
{{interpretation.user.username}} on {{interpretation.created_at.strftime('%B %d, %Y')}} <a href="{{url_for('user.profile',user_id=interpretation.user.id)}}" class=" text-blue-500 {% if interpretation.user.is_deleted %}line-through{% endif %}">{{interpretation.user.username}}</a> on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div> </div>
<div class="flex ml-auto justify-between w-24"> <div class="flex ml-auto justify-between w-24">
<span class="space-x-0.5 flex items-center"> <span class="space-x-0.5 flex items-center">

View File

@ -2,7 +2,7 @@
<ol class="inline-flex items-center overflow-x-scroll md:overflow-auto p-0"> <ol class="inline-flex items-center overflow-x-scroll md:overflow-auto p-0">
{% for breadcrumb in local_breadcrumbs if breadcrumb.type != "MyBookList" and breadcrumb.type != "AuthorBookList" %} {% for breadcrumb in local_breadcrumbs if breadcrumb.type != "MyBookList" and breadcrumb.type != "AuthorBookList" %}
<li class="inline-flex items-center align-middle justify-center"> <li class="inline-flex items-center align-middle justify-center">
{% if not loop.index==local_breadcrumbs|length %} {% if not loop.index==local_breadcrumbs|length-1 %}
<a href="{{ breadcrumb.url }}" class="inline-flex text-xs font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white" data-tooltip-target="breadcrumb-{{loop.index}}-tooltip" data-tooltip-placement="bottom"> <a href="{{ breadcrumb.url }}" class="inline-flex text-xs font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white" data-tooltip-target="breadcrumb-{{loop.index}}-tooltip" data-tooltip-placement="bottom">
{% else %} {% else %}
<span class="inline-flex items-center text-sm font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white" data-tooltip-target="breadcrumb-{{loop.index}}-tooltip" data-tooltip-placement="bottom"> <span class="inline-flex items-center text-sm font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white" data-tooltip-target="breadcrumb-{{loop.index}}-tooltip" data-tooltip-placement="bottom">
@ -18,7 +18,7 @@
{% else %} {% else %}
</span> </span>
{% endif %} {% endif %}
{% if not loop.index==local_breadcrumbs|length %} {% if not loop.index==local_breadcrumbs|length-1 %}
<svg aria-hidden="true" class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path> </svg> <svg aria-hidden="true" class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path> </svg>
{% endif %} {% endif %}
</li> </li>

View File

@ -1,22 +1,20 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% extends 'base.html' %} {% extends 'base.html' %}
{% if current_user.is_authenticated %}
{% include 'book/delete_interpretation_modal.html' %} {% include 'book/delete_interpretation_modal.html' %}
{% include 'book/delete_comment_modal.html' %} {% include 'book/delete_comment_modal.html' %}
{% include 'book/edit_comment_modal.html' %} {% include 'book/edit_comment_modal.html' %}
{% include 'book/edit_interpretation_modal.html' %} {% include 'book/edit_interpretation_modal.html' %}
<!-- show delete section btn on rightside bar -->
{% set show_edit_interpretation = True %} {% set show_edit_interpretation = True %}
<!-- prettier-ignore -->
{% set show_delete_interpretation = True %} {% set show_delete_interpretation = True %}
<!-- prettier-ignore -->
{% block right_sidebar %} {% block right_sidebar %}
{% include 'book/right_sidebar.html' %} {% include 'book/right_sidebar.html' %}
{% endblock %} {% endblock %}
{% endif %}
{% block content %} {% block content %}
{% include 'book/breadcrumbs_navigation.html'%} {% include 'book/breadcrumbs_navigation.html'%}
@ -29,6 +27,17 @@
</div> </div>
<div class="p-1"> <div class="p-1">
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% if not current_user.is_authenticated %}
<div class="bg-white dark:bg-gray-900 max-w-full p-6 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="grid gap-6">
<div class="col-span-6 sm:col-span-3 truncate">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white ">Connect you wallet to start contributing!</h3>
</div>
</div>
</div>
<!-- prettier-ignore -->
{% endif %}
{% if current_user.is_authenticated %}
<form {% if sub_collection %} <form {% if sub_collection %}
action="{{ url_for('book.create_comment', book_id=book.id, collection_id=collection.id, sub_collection_id=sub_collection.id,section_id=section.id,interpretation_id=interpretation.id) }}" action="{{ url_for('book.create_comment', book_id=book.id, collection_id=collection.id, sub_collection_id=sub_collection.id,section_id=section.id,interpretation_id=interpretation.id) }}"
{% else %} {% else %}
@ -45,6 +54,8 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<button type="submit" class="ml-auto text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"> Leave comment </button> <button type="submit" class="ml-auto text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"> Leave comment </button>
</form> </form>
<!-- prettier-ignore -->
{% endif %}
</div> </div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<dl class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700"> <dl class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700">

View File

@ -5,10 +5,7 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">{{book.label}}</h1> <h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">{{book.label}}</h1>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> <p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> {{book.about}} </p>
An open-source law hosting platform that allows online communities to easily
create, collaborate, and publish their own body of law.
</p>
<!-- prettier-ignore --> <!-- 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"> <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">

View File

@ -63,6 +63,9 @@
<div class="px-4 py-3" role="none"> <div class="px-4 py-3" role="none">
<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">
<a class="text-center text-sm text-gray-900 dark:text-white" role="none" href="{{ url_for('user.profile',user_id=current_user.id) }}"> View profile </a>
</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.edit_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>

View File

@ -79,7 +79,7 @@
<div class="flex mt-auto align-center justify-between md:w-full"> <div class="flex mt-auto align-center justify-between md:w-full">
<div> <div>
<span class="hidden md:inline-block">Interpretation by</span> <span class="hidden md:inline-block">Interpretation by</span>
{{interpretation.user.username}} on {{interpretation.created_at.strftime('%B %d, %Y')}} <a href="{{url_for('user.profile',user_id=interpretation.user.id)}}" class=" text-blue-500 {% if interpretation.user.is_deleted %}line-through{% endif %}">{{interpretation.user.username}}</a> on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div> </div>
<div class="flex ml-auto justify-between w-24"> <div class="flex ml-auto justify-between w-24">
<span class="space-x-0.5 flex items-center"> <span class="space-x-0.5 flex items-center">
@ -105,7 +105,7 @@
<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> <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"> <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 %} {% if book.versions %}
<p> Last updated on {{book.versions[-1].updated_at.strftime('%B %d, %Y')}} </p> <p> Last updated by <a href="{{url_for('user.profile',user_id=book.owner.id)}}" class=" text-blue-500 {% if book.owner.is_deleted %}line-through{% endif %}">{{book.owner.username}}</a> on {{book.versions[-1].updated_at.strftime('%B %d, %Y')}} </p>
{% endif %} {% endif %}
<div class="flex ml-auto align-center justify-center space-x-3"> <div class="flex ml-auto align-center justify-center space-x-3">
<span class="book-star-block space-x-0.5 flex items-center"> <span class="book-star-block space-x-0.5 flex items-center">
@ -114,11 +114,11 @@
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_interpretations|length }}</p>
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_comments|length }}</p>
</span> </span>
</div> </div>
</dd> </dd>

View File

@ -6,14 +6,15 @@
{{ form_hidden_tag() }} {{ form_hidden_tag() }}
<!-- Modal header --> <!-- Modal header -->
<div class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600"> <div class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white"> Delete profile </h3> <h3 class="text-xl font-semibold text-gray-900 dark:text-white"> Are you sure you want to deactivate your profile? </h3>
<button id="modalAddCloseButton" data-modal-hide="delete_profile_modal" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"> <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path> </svg> </button> <button id="modalAddCloseButton" data-modal-hide="delete_profile_modal" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"> <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path> </svg> </button>
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<!-- Modal footer --> <!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600"> <div class="flex flex-col items-start p-6 border-t border-gray-200 rounded-b dark:border-gray-600">
<button name="submit" type="submit" class="text-white bg-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 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800">Confirm Deletion</button> <button id="modalAddCloseButton" data-modal-hide="delete_profile_modal" type="button" class="text-white mb-2 bg-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 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800">No, cancel</button>
<button name="submit" type="submit" class="text-white mb-2 bg-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 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800">Yes, deactivate profile</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -2,16 +2,19 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64"> <div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
{% if user.is_deleted %}
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4">Sorry this user was deactivated</h1>
{% else %}
<div class="flex p-5 items-center"> <div class="flex p-5 items-center">
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% if user.avatar_img %} {% if user.avatar_img %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<img class=" w-10 h-10 rounded-full mr-3" src="data:image/jpeg;base64,{{ current_user.avatar_img }}" alt="user avatar"> <img class=" w-10 h-10 rounded-full mr-3" src="data:image/jpeg;base64,{{ user.avatar_img }}" alt="user avatar">
{% else %} {% else %}
<!-- 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-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> <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 %} {% endif %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4">{{user.username}}</h1> <h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4">{{user.username}}</h1>
<!-- prettier-ignore --> <!-- prettier-ignore -->
@ -19,6 +22,7 @@
{{user.wallet_id}} {{user.wallet_id}}
</span> </span>
</div> </div>
{% endif %}
<!-- prettier-ignore --> <!-- 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"> <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">
@ -30,7 +34,6 @@
<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 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="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 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="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>
Contributions Contributions
</button> </button>
</li> </li>
@ -56,11 +59,11 @@
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_interpretations|length }}</p>
</span> </span>
<span class="space-x-0.5 flex items-center"> <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> <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> <p>{{ book.approved_comments|length }}</p>
</span> </span>
</div> </div>
</dd> </dd>
@ -120,7 +123,7 @@
<div class="flex mt-auto align-center justify-between md:w-full"> <div class="flex mt-auto align-center justify-between md:w-full">
<div> <div>
<span class="hidden md:inline-block">Interpretation by</span> <span class="hidden md:inline-block">Interpretation by</span>
{{interpretation.user.username}} on {{interpretation.created_at.strftime('%B %d, %Y')}} <a href="{{url_for('user.profile',user_id=interpretation.user.id)}}" class=" text-blue-500 {% if interpretation.user.is_deleted %}line-through{% endif %}">{{interpretation.user.username}}</a> on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div> </div>
<div class="flex ml-auto justify-between w-24"> <div class="flex ml-auto justify-between w-24">
<span class="space-x-0.5 flex items-center"> <span class="space-x-0.5 flex items-center">

View File

@ -0,0 +1,23 @@
<!-- 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">
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">You profile where deactivated earlier. Do you want to reactivate it?</h2>
<!-- prettier-ignore -->
<form class="mt-8 space-y-6 from" role="form" action="{{ url_for('user.profile_reactivate') }}" method="post">
{{ form.hidden_tag() }}
<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">Reactivate profile</button>
</form>
</div>
</div>
</div>
</section>
{% block right_sidebar %}{% endblock %}
<!-- prettier-ignore -->
{% endblock %}

View File

@ -103,6 +103,9 @@ def verify():
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.edit_profile")) return redirect(url_for("user.edit_profile"))
if user.is_deleted:
login_user(user=user)
return redirect(url_for("user.profile_reactivate"))
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

@ -940,7 +940,6 @@ def interpretation_delete(
), ),
methods=["GET"], methods=["GET"],
) )
@login_required
def qa_view( def qa_view(
book_id: int, book_id: int,
collection_id: int, collection_id: int,

View File

@ -46,7 +46,7 @@ def edit_profile():
user.is_activated = True user.is_activated = True
user.save() user.save()
return redirect(url_for("main.index")) return redirect(url_for("main.index"))
elif form.is_submitted: elif form.is_submitted():
log(log.ERROR, "Update user errors: [%s]", form.errors) log(log.ERROR, "Update user errors: [%s]", form.errors)
for field, errors in form.errors.items(): for field, errors in form.errors.items():
field_label = form._fields[field].label.text field_label = form._fields[field].label.text
@ -59,7 +59,6 @@ def edit_profile():
@bp.route("/<int:user_id>/profile") @bp.route("/<int:user_id>/profile")
@login_required
def profile(user_id: int): def profile(user_id: int):
user: m.User = db.session.get(m.User, user_id) user: m.User = db.session.get(m.User, user_id)
interpretations: m.Interpretation = m.Interpretation.query.filter_by( interpretations: m.Interpretation = m.Interpretation.query.filter_by(
@ -93,8 +92,6 @@ def create():
@login_required @login_required
def profile_delete(): def profile_delete():
user: m.User = db.session.get(m.User, current_user.id) user: m.User = db.session.get(m.User, current_user.id)
for book in user.books:
book.is_deleted = True
user.is_deleted = True user.is_deleted = True
log(log.INFO, "User deleted. User: [%s]", user) log(log.INFO, "User deleted. User: [%s]", user)
user.save() user.save()
@ -103,6 +100,22 @@ def profile_delete():
return redirect(url_for("home.get_all")) return redirect(url_for("home.get_all"))
@bp.route("/profile_reactivate", methods=["GET", "POST"])
def profile_reactivate():
user: m.User = db.session.get(m.User, current_user.id)
if not user:
log(log.CRITICAL, "No such user. User: [%s]", user)
return redirect(url_for("home.get_all"))
form = f.ReactivateUserForm()
if form.validate_on_submit():
user.is_deleted = False
log(log.INFO, "Form submitted. User reactivated: [%s]", user)
flash("User reactivated!", "success")
user.save()
return redirect(url_for("home.get_all"))
return render_template("user/reactivate.html", form=form)
@bp.route("/search", methods=["GET"]) @bp.route("/search", methods=["GET"])
@login_required @login_required
def search(): def search():

View File

@ -8,15 +8,9 @@ const $addUserModalElement: HTMLElement =
const modalOptions: ModalOptions = { const modalOptions: ModalOptions = {
placement: 'bottom-right', placement: 'bottom-right',
closable: true, closable: true,
onHide: () => { onHide: () => {},
console.log('modal is hidden'); onShow: () => {},
}, onToggle: () => {},
onShow: () => {
console.log('user id: ');
},
onToggle: () => {
console.log('modal has been toggled');
},
}; };
const addModal: ModalInterface = new Modal($addUserModalElement, modalOptions); const addModal: ModalInterface = new Modal($addUserModalElement, modalOptions);

View File

@ -54,7 +54,9 @@ export function initWallet() {
credentials: 'include', credentials: 'include',
redirect: 'follow', redirect: 'follow',
}); });
window.location.reload(); if (res2.status == 200) {
window.location.replace(res2.url);
} else window.location.reload();
} }
const connectWalletBtns = document.querySelectorAll('#connectWalletBtn'); const connectWalletBtns = document.querySelectorAll('#connectWalletBtn');

View File

@ -879,9 +879,7 @@ def test_crud_interpretation(client: FlaskClient, runner: FlaskCliRunner):
# edit # edit
m.Interpretation( m.Interpretation(
label="Test", label="Test", text="Test", section_id=section_in_collection.id, user_id=user.id
text="Test",
section_id=section_in_collection.id,
).save() ).save()
m.Interpretation( m.Interpretation(
@ -1087,8 +1085,11 @@ def test_crud_comment(client: FlaskClient, runner: FlaskCliRunner):
def test_access_to_settings_page(client: FlaskClient): def test_access_to_settings_page(client: FlaskClient):
_, user = login(client) _, user = login(client)
book_1 = m.Book(label="test", about="test").save() book_1 = m.Book(label="test", about="test", user_id=user.id).save()
m.BookVersion(semver="1.0.0", book_id=book_1.id).save()
book_2 = m.Book(label="test", about="test", user_id=user.id).save() book_2 = m.Book(label="test", about="test", user_id=user.id).save()
m.BookVersion(semver="1.0.0", book_id=book_2.id).save()
response: Response = client.get( response: Response = client.get(
f"/book/{book_1.id}/settings", f"/book/{book_1.id}/settings",
@ -1096,7 +1097,6 @@ def test_access_to_settings_page(client: FlaskClient):
) )
assert response.status_code == 200 assert response.status_code == 200
assert b"You are not owner of this book!" in response.data
response: Response = client.get( response: Response = client.get(
f"/book/{book_2.id}/settings", f"/book/{book_2.id}/settings",

View File

@ -0,0 +1,114 @@
from flask.testing import FlaskClient
from app import models as m
from tests.utils import login, create_test_book
def test_approved_interpretations(client: FlaskClient):
_, user = login(client)
create_test_book(user.id)
dummy_user = m.User(username="Bob").save()
create_test_book(dummy_user.id)
book: m.Book = m.Book.query.first()
assert len(book.approved_interpretations) == 0
for interpretation in m.Interpretation.query.all():
interpretation.approved = True
interpretation.save()
assert len(book.approved_interpretations) == 1
section: m.Section = m.Section.query.first()
assert section
interpretation: m.Interpretation = m.Interpretation(
section_id=section.id, label="231", text="123", approved=True
).save()
assert len(book.approved_interpretations) == 2
interpretation.is_deleted = True
interpretation.save()
assert len(book.approved_interpretations) == 1
collection: m.Collection = m.Collection.query.first()
sub_collection: m.Collection = m.Collection(
parent_id=collection.id,
label="123",
).save()
section: m.Section = m.Section(
label="123", collection_id=sub_collection.id, version_id=book.last_version.id
).save()
interpretation: m.Interpretation = m.Interpretation(
section_id=section.id, label="231", text="123", approved=True
).save()
assert len(book.approved_interpretations) == 2
sub_collection.is_deleted = True
sub_collection.save()
assert len(book.approved_interpretations) == 1
sub_collection.is_deleted = False
sub_collection.save()
assert len(book.approved_interpretations) == 2
# collection.is_deleted = True
# collection.save()
# assert len(book.approved_interpretations) == 0
def test_approved_comments(client: FlaskClient):
_, user = login(client)
create_test_book(user.id)
dummy_user = m.User(username="Bob").save()
create_test_book(dummy_user.id)
book: m.Book = m.Book.query.first()
assert len(book.approved_comments) == 0
for comment in m.Comment.query.all():
comment.approved = True
comment.save()
assert len(book.approved_comments) == 1
interpretation: m.Interpretation = m.Interpretation.query.first()
assert interpretation
comment: m.Comment = m.Comment(
text="231", approved=True, interpretation_id=interpretation.id
).save()
assert len(book.approved_comments) == 2
comment.is_deleted = True
comment.save()
assert len(book.approved_comments) == 1
comment: m.Comment = m.Comment(
text="456", approved=True, interpretation_id=interpretation.id
).save()
assert len(book.approved_comments) == 2
interpretation.is_deleted = True
interpretation.save()
assert len(book.approved_comments) == 0
interpretation.is_deleted = False
interpretation.save()
assert len(book.approved_comments) == 2
collection: m.Collection = m.Collection.query.first()
collection.is_deleted = True
collection.save()
interpretation.is_deleted = False
interpretation.save()
assert len(book.approved_comments) == 0

View File

@ -120,6 +120,7 @@ def test_profile(client):
user_id=user.id, user_id=user.id,
) )
book.save() book.save()
m.BookVersion(semver="1.0.0", book_id=book.id).save()
assert book assert book
# profile page # profile page
@ -139,4 +140,3 @@ def test_profile(client):
) )
assert res assert res
assert user.is_deleted assert user.is_deleted
assert user.books[0].is_deleted