mirror of
https://github.com/logos-co/open-law.git
synced 2025-02-24 20:48:18 +00:00
Merge branch 'develop' into svyat/fix/deleting_collections
This commit is contained in:
commit
206411caa6
@ -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,
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
{% 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>
|
||||||
@ -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">
|
||||||
|
23
app/templates/user/reactivate.html
Normal file
23
app/templates/user/reactivate.html
Normal 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 %}
|
@ -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")
|
||||||
|
@ -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,
|
||||||
|
@ -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():
|
||||||
|
12
src/books.ts
12
src/books.ts
@ -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);
|
||||||
|
@ -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');
|
||||||
|
@ -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",
|
||||||
|
114
tests/test_book_stats_properties.py
Normal file
114
tests/test_book_stats_properties.py
Normal 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
|
@ -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
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user