start working

This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-09 11:37:23 +03:00
parent 706c9463be
commit 526bc62d84
11 changed files with 195 additions and 6 deletions

View File

@ -10,4 +10,4 @@ from .contributor import (
from .collection import CreateCollectionForm, EditCollectionForm from .collection import CreateCollectionForm, EditCollectionForm
from .section import CreateSectionForm, EditSectionForm from .section import CreateSectionForm, EditSectionForm
from .interpretation import CreateInterpretationForm, EditInterpretationForm from .interpretation import CreateInterpretationForm, EditInterpretationForm
from .comment import CreateCommentForm from .comment import CreateCommentForm, DeleteCommentForm

View File

@ -7,7 +7,13 @@ class BaseCommentForm(FlaskForm):
text = StringField("Text", [DataRequired(), Length(3, 256)]) text = StringField("Text", [DataRequired(), Length(3, 256)])
marked = BooleanField("Marked") marked = BooleanField("Marked")
included_with_interpretation = BooleanField("Included") included_with_interpretation = BooleanField("Included")
parent_id = StringField("Text")
class CreateCommentForm(BaseCommentForm): class CreateCommentForm(BaseCommentForm):
submit = SubmitField("Create") submit = SubmitField("Create")
class DeleteCommentForm(FlaskForm):
comment_id = StringField("Text")
submit = SubmitField("Delete")

1
app/static/js/comment.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function initComments(): void;

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<nav class="fixed flex p-4 pl-1 mt-1.5 z-40 w-full md:max-w-4xl bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700" aria-label="Breadcrumb"> <nav class="fixed flex p-4 pl-1 mt-1.5 z-40 w-full md:w-4/5 bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 md:space-x-3 ml-5 overflow-x-scroll md:overflow-auto p-0"> <ol class="inline-flex items-center space-x-1 md:space-x-3 ml-5 overflow-x-scroll md:overflow-auto p-0">
{% for breadcrumb in breadcrumbs %} {% for breadcrumb in breadcrumbs %}
<li class="inline-flex items-center"> <li class="inline-flex items-center">

View File

@ -0,0 +1,25 @@
<!-- prettier-ignore-->
<div id="delete_comment_modal" tabindex="-1" aria-hidden="true" class="fixed top-0 left-0 right-0 z-50 hidden w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative w-full max-w-2xl max-h-full">
<!-- Modal content -->
<form
{% if sub_collection %}
action="{{ url_for('book.comment_delete', book_id=book.id, collection_id=collection.id, sub_collection_id=sub_collection.id, section_id=section.id, interpretation_id=interpretation.id) }}"
{% else %}
action="{{ url_for('book.comment_delete', book_id=book.id, collection_id=collection.id, section_id=section.id, interpretation_id=interpretation.id) }}"
{% endif %}
method="post" class="relative bg-white rounded-lg shadow dark:bg-gray-700">
{{ form_hidden_tag() }}
<!-- Modal header -->
<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 Comment </h3>
<input type="hidden" name="comment_id" id="comment_id" value="" />
<button id="modalAddCloseButton" data-modal-hide="delete_comment_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>
<!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 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>
</div>
</form>
</div>
</div>

View File

@ -2,6 +2,9 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% include 'book/delete_interpretation_modal.html' %} {% include 'book/delete_interpretation_modal.html' %}
{% include 'book/delete_comment_modal.html' %}
{% include 'book/edit_interpretation_modal.html' %} {% include 'book/edit_interpretation_modal.html' %}
<!-- show delete section btn on rightside bar --> <!-- show delete section btn on rightside bar -->
@ -45,7 +48,7 @@
<dl <dl
class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700"> class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700">
<!-- prettier-ignore --> <!-- prettier-ignore -->
{% for comment in interpretation.comments %} {% for comment in interpretation.comments if not comment.is_deleted %}
<!-- prettier-ignore --> <!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700"> <dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<div class="flex flex-row pb-3 p-3 w-2/3 md:w-full"> <div class="flex flex-row pb-3 p-3 w-2/3 md:w-full">
@ -68,6 +71,10 @@
<div id="accordion-collapse" data-accordion="collapse" class="flex mt-auto align-center justify-between space-x-3"> <div id="accordion-collapse" data-accordion="collapse" class="flex mt-auto align-center justify-between space-x-3">
<div>Commented by {{comment.user.username}} on {{comment.created_at.strftime('%B %d, %Y')}}</div> <div>Commented by {{comment.user.username}} on {{comment.created_at.strftime('%B %d, %Y')}}</div>
<div class="flex ml-auto justify-between w-24"> <div class="flex ml-auto justify-between w-24">
<button id="delete_comment_btn" data-comment-id="{{comment.id}}" type="button" data-modal-target="delete_comment_modal" data-modal-toggle="delete_comment_modal" class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg>
</button>
<button type="button" data-accordion-target="#accordion-collapse-body-{{loop.index}}" aria-expanded="false" aria-controls="accordion-collapse-body-1" class="space-x-0.5 flex items-center"> <button type="button" data-accordion-target="#accordion-collapse-body-{{loop.index}}" aria-expanded="false" aria-controls="accordion-collapse-body-1" class="space-x-0.5 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 shrink-0"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" /> </svg> <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 shrink-0"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" /> </svg>
</button> </button>
@ -76,6 +83,9 @@
</div> </div>
<div id="accordion-collapse-body-{{loop.index}}" class="hidden" aria-labelledby="accordion-collapse-heading-1"> <div id="accordion-collapse-body-{{loop.index}}" class="hidden" aria-labelledby="accordion-collapse-heading-1">
<div class="p-5 border border-b-0 border-gray-200 dark:border-gray-700 dark:bg-gray-900"> <div class="p-5 border border-b-0 border-gray-200 dark:border-gray-700 dark:bg-gray-900">
{% for child in comment.children %}
{{child.text}}
{% endfor %}
<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 %}
@ -83,6 +93,7 @@
{% endif %} {% endif %}
method="post" class="flex flex-col 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"> method="post" class="flex flex-col 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">
{{ form_hidden_tag() }} {{ form_hidden_tag() }}
<input type="hidden" name="parent_id" id="parent_id" value="{{comment.id}}" />
<div class="relative z-0 w-full mb-6 group"> <div class="relative z-0 w-full mb-6 group">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<input autocomplete="off" type="text" name="text" id="floating_email" class="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer" placeholder=" " required /> <input autocomplete="off" type="text" name="text" id="floating_email" class="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer" placeholder=" " required />

View File

@ -1,5 +1,5 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<aside id="logo-right-sidebar" class="fixed top-0 right-0 left-auto z-40 w-64 h-screen pt-28 transition-transform translate-x-96 bg-white border-r border-gray-200 md:translate-x-0 dark:bg-gray-800 dark:border-gray-700" aria-label="Right-sidebar"> <aside id="logo-right-sidebar" class="fixed top-0 right-0 left-auto z-50 w-64 h-screen pt-28 transition-transform translate-x-96 bg-white border-r border-gray-200 md:translate-x-0 dark:bg-gray-800 dark:border-gray-700" aria-label="Right-sidebar">
<div class="h-full pb-4 overflow-y-auto bg-white dark:bg-gray-800"> <div class="h-full pb-4 overflow-y-auto bg-white dark:bg-gray-800">
<ul class="space-y-4 mt-1 font-medium"> <ul class="space-y-4 mt-1 font-medium">
{% if book.owner.id == current_user.id %} {% if book.owner.id == current_user.id %}

View File

@ -1298,6 +1298,10 @@ def create_comment(
user_id=current_user.id, user_id=current_user.id,
interpretation_id=interpretation_id, interpretation_id=interpretation_id,
) )
if form.parent_id.data:
comment.parent_id = form.parent_id.data
comment.interpretation = None
log( log(
log.INFO, log.INFO,
"Create comment for interpretation [%s]. Section: [%s]", "Create comment for interpretation [%s]. Section: [%s]",
@ -1316,3 +1320,99 @@ def create_comment(
flash(error.lower().replace("field", field_label).title(), "danger") flash(error.lower().replace("field", field_label).title(), "danger")
return redirect(redirect_url) return redirect(redirect_url)
@bp.route(
"/<int:book_id>/<int:collection_id>/<int:section_id>/<int:interpretation_id>/comment_delete",
methods=["POST"],
)
@bp.route(
(
"/<int:book_id>/<int:collection_id>/<int:sub_collection_id>/"
"<int:section_id>/<int:interpretation_id>/comment_delete"
),
methods=["POST"],
)
@login_required
def comment_delete(
book_id: int,
collection_id: int,
section_id: int,
interpretation_id: int,
sub_collection_id: int | None = None,
):
form = f.DeleteCommentForm()
if form.validate_on_submit():
book: m.Book = db.session.get(m.Book, book_id)
comment_id = form.comment_id.data
if not book or book.owner != current_user or book.is_deleted:
log(log.INFO, "User: [%s] is not owner of book: [%s]", current_user, book)
flash("You are not owner of this book!", "danger")
return redirect(url_for("book.my_books"))
collection: m.Collection = db.session.get(m.Collection, collection_id)
if not collection or collection.is_deleted:
log(log.WARNING, "Collection with id [%s] not found", collection_id)
flash("Collection not found", "danger")
return redirect(url_for("book.collection_view", book_id=book_id))
if sub_collection_id:
sub_collection: m.Collection = db.session.get(
m.Collection, sub_collection_id
)
if not sub_collection or sub_collection.is_deleted:
log(
log.WARNING,
"Sub_collection with id [%s] not found",
sub_collection_id,
)
flash("SubCollection not found", "danger")
return redirect(
url_for(
"book.sub_collection_view",
book_id=book_id,
collection_id=collection_id,
)
)
redirect_url = url_for(
"book.qa_view",
book_id=book_id,
collection_id=collection_id,
sub_collection_id=sub_collection_id,
section_id=section_id,
interpretation_id=interpretation_id,
)
section: m.Section = db.session.get(m.Section, section_id)
if not section or section.is_deleted:
log(log.WARNING, "Section with id [%s] not found", section_id)
flash("Section not found", "danger")
return redirect(redirect_url)
interpretation: m.Interpretation = db.session.get(
m.Interpretation, interpretation_id
)
if not interpretation or interpretation.is_deleted:
log(log.WARNING, "Interpretation with id [%s] not found", interpretation_id)
flash("Interpretation not found", "danger")
return redirect(redirect_url)
comment: m.Comment = db.session.get(m.Comment, comment_id)
if not comment or comment.is_deleted:
log(log.WARNING, "Comment with id [%s] not found", comment_id)
flash("Comment not found", "danger")
return redirect(redirect_url)
comment.is_deleted = True
log(log.INFO, "Delete comment [%s]", comment)
comment.save()
flash("Success!", "success")
return redirect(redirect_url)
return redirect(
url_for(
"book.sub_collection_view",
book_id=book_id,
collection_id=collection_id,
)
)

15
src/comment.ts Normal file
View File

@ -0,0 +1,15 @@
export function initComments() {
// deleting comment
const deleteCommentBtn: HTMLButtonElement = document.querySelector(
'#delete_comment_btn',
);
const deleteCommentInputOnModal: HTMLInputElement =
document.querySelector('#comment_id');
if (deleteCommentBtn && deleteCommentInputOnModal) {
deleteCommentBtn.addEventListener('click', () => {
const id = deleteCommentBtn.getAttribute('data-comment-id');
console.log(id);
deleteCommentInputOnModal.value = id;
});
}
}

View File

@ -4,6 +4,7 @@ import {initContributors} from './contributors';
import {initWallet} from './wallet'; import {initWallet} from './wallet';
import {initQuill} from './initQuill'; import {initQuill} from './initQuill';
import {initQuillValueToInput} from './quillValueToInput'; import {initQuillValueToInput} from './quillValueToInput';
import {initComments} from './comment';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initBooks(); initBooks();
@ -11,4 +12,5 @@ document.addEventListener('DOMContentLoaded', () => {
initQuill(); initQuill();
initQuillValueToInput(); initQuillValueToInput();
initWallet(); initWallet();
initComments();
}); });