Merge branch 'develop' into svyat/fix/bugs

This commit is contained in:
SvyatoslavArtymovych 2023-06-16 09:56:25 +03:00
commit b36cb9a9be
24 changed files with 86 additions and 92 deletions

View File

@ -0,0 +1,8 @@
from flask import flash
def create_error_flash(form):
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")

File diff suppressed because one or more lines are too long

View File

@ -68,7 +68,7 @@
<!-- 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-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
class="prevent-unsaved-changes-event 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 px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
</div>
</form>
</div>

View File

@ -47,7 +47,7 @@
</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-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Add</button>
<button name="submit" type="submit" class="prevent-unsaved-changes-event 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 px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Add</button>
</div>
</form>
</div>

View File

@ -17,7 +17,7 @@
<!-- 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-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
<button name="submit" type="submit" class="prevent-unsaved-changes-event 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 px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
</div>
</form>
</div>

View File

@ -13,7 +13,7 @@
<!-- 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>
<button name="submit" type="submit" class="prevent-unsaved-changes-event 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>

View File

@ -15,7 +15,7 @@
<!-- Modal footer -->
<div class="flex flex-col items-start p-6 border-t border-gray-200 rounded-b dark:border-gray-600">
<button id="modalDeleteContributorCloseButton" data-modal-hide="delete_contributor_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, delete contributor</button>
<button name="submit" type="submit" class="prevent-unsaved-changes-event 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, delete contributor</button>
</div>
</form>
</div>

View File

@ -15,7 +15,7 @@
<!-- Modal footer -->
<div class="flex justify-between items-start p-6 border-t border-gray-200 rounded-b dark:border-gray-600">
<button id="modalDeleteContributorCloseButton" data-modal-hide="delete_version_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, delete version</button>
<button name="submit" type="submit" class="prevent-unsaved-changes-event 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, delete version</button>
</div>
</form>
</div>

View File

@ -88,7 +88,7 @@
</div>
<div class="flex justify-between">
<button type="submit" class="mr-2 mb-2 text-center 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 px-4 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Submit</button>
<button type="submit" class="prevent-unsaved-changes-event mr-2 mb-2 text-center 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 px-4 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Submit</button>
{% if book.user_id == current_user.id %}
<button type="button" data-modal-target="delete_book_modal" data-modal-toggle="delete_book_modal" class="text-red-700 hover:text-white border border-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600 dark:focus:ring-red-900">Delete Book</button>
{% endif %}
@ -145,7 +145,7 @@
</option>
{% endfor %}
</select>
<button type="submit" class="text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-5 py-1 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700">Save</button>
<button type="submit" class="prevent-unsaved-changes-event text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-5 py-1 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700">Save</button>
</form>
</td>
<td class="px-4 py-4 flex justify-center">

View File

@ -7,7 +7,7 @@
{% include 'book/modals/fork_book_modal.html' %}
<div class="border-b border-gray-200 dark:border-gray-700">
<div class="border-b border-gray-200 dark:border-gray-700 pt-3">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 my-2">{{book.label}}</h1>
<!-- prettier-ignore -->

View File

@ -43,7 +43,12 @@
id="explore-books"
role="tabpanel"
aria-labelledby="explore-books-tab">
{% for book in books if not book.is_deleted %}
{% if not books.total %}
<p
class="hidden md:block text-l ml-4 w-1/2 mt-2 text-gray-500 text-center md:text-left dark:text-gray-400">
Books not found!
</p>
{% endif %} {% for book in books if not book.is_deleted %}
<!-- prettier-ignore -->
<dl class=" bg-white dark:bg-gray-900 max-w-full p-5 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<dt class="mb-2"><a class="flex flex-col" href="{{url_for('book.collection_view',book_id=book.id)}}">{{book.label}}</a></dt>

View File

@ -35,6 +35,12 @@
<div id="myTabContent">
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="last-interpretations" role="tabpanel" aria-labelledby="last-interpretations-tab">
{% if not interpretations.total %}
<p
class="hidden md:block text-l ml-4 w-1/2 mt-2 text-gray-500 text-center md:text-left dark:text-gray-400">
Interpretations not found!
</p>
{% endif %}
{% for interpretation in interpretations %}
<!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">

View File

@ -3,7 +3,7 @@
<div class="flex px-4 py-3">
<div class="w-full pl-3">
<div class="text-gray-500 text-sm mb-1.5 dark:text-gray-400">
You haven't notifications!
You don't have notifications!
</div>
</div>
</div>

View File

@ -81,7 +81,6 @@
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<div class="flex flex-row pb-3 p-3 w-2/3 md:w-10/12">
<div class="vote-block flex flex-col m-5 justify-center items-center">
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="true">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote %}
@ -89,7 +88,6 @@
{% endif %}
" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" > <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18" /> </svg>
</div>
{% endif %}
<span
class="vote-count text-3xl select-none
@ -103,7 +101,6 @@
{{ interpretation.vote_count }}
</span>
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="false">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote == False %}
@ -111,7 +108,6 @@
{% endif %}
" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3" /> </svg>
</div>
{% endif %}
</div>
<!-- prettier-ignore -->
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">

View File

@ -17,6 +17,7 @@ from app.controllers.create_access_groups import (
)
from app.controllers.require_permission import require_permission
from app.controllers.sorting import sort_by
from app.controllers.error_flashes import create_error_flash
from app import models as m, db, forms as f
from app.logger import log
from .bp import bp
@ -130,10 +131,7 @@ def create():
return redirect(url_for("book.my_library"))
else:
log(log.ERROR, "Book create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(url_for("book.my_library"))
@ -162,10 +160,7 @@ def edit(book_id: int):
return redirect(url_for("book.collection_view", book_id=book_id))
else:
log(log.ERROR, "Book create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(url_for("book.settings", book_id=book_id))

View File

@ -10,6 +10,7 @@ from app.controllers.notification_producer import collection_notification
from app.controllers.delete_nested_book_entities import (
delete_nested_collection_entities,
)
from app.controllers.error_flashes import create_error_flash
from app import models as m, db, forms as f
from app.controllers.require_permission import require_permission
from app.logger import log
@ -128,10 +129,7 @@ def collection_create(book_id: int, collection_id: int | None = None):
return redirect(redirect_url)
else:
log(log.ERROR, "Collection/Subcollection create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)
@ -195,10 +193,7 @@ def collection_edit(book_id: int, collection_id: int):
return redirect(redirect_url)
else:
log(log.ERROR, "Collection edit errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)

View File

@ -3,6 +3,7 @@ from flask_login import login_required
from app import models as m, db, forms as f
from app.controllers.fork import fork_book
from app.controllers.error_flashes import create_error_flash
from app.logger import log
from .bp import bp
@ -20,8 +21,5 @@ def fork(book_id):
return redirect(redirect_url)
else:
log(log.ERROR, "Fork book errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)

View File

@ -16,6 +16,7 @@ from app.controllers.notification_producer import interpretation_notification
from app.controllers.delete_nested_book_entities import (
delete_nested_interpretation_entities,
)
from app.controllers.error_flashes import create_error_flash
from app import models as m, db, forms as f
from app.controllers.require_permission import require_permission
from app.controllers.tags import set_interpretation_tags
@ -122,10 +123,7 @@ def interpretation_create(
return redirect(redirect_url)
else:
log(log.ERROR, "Interpretation create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)
@ -182,10 +180,7 @@ def interpretation_edit(
return redirect(redirect_url)
else:
log(log.ERROR, "Interpretation edit errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)

View File

@ -5,6 +5,7 @@ from app.controllers import register_book_verify_route
from app.controllers.copy_access_groups import recursive_copy_access_groups
from app.controllers.notification_producer import section_notification
from app.controllers.delete_nested_book_entities import delete_nested_section_entities
from app.controllers.error_flashes import create_error_flash
from app import models as m, db, forms as f
from app.controllers.require_permission import require_permission
from app.logger import log
@ -59,10 +60,7 @@ def section_create(book_id: int, collection_id: int):
return redirect(redirect_url)
else:
log(log.ERROR, "Section create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)
@ -98,10 +96,7 @@ def section_edit(book_id: int, section_id: int):
return redirect(redirect_url)
else:
log(log.ERROR, "Section edit errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)

View File

@ -15,6 +15,7 @@ from app.controllers.contributor import (
add_contributor_to_book,
delete_contributor_from_book,
)
from app.controllers.error_flashes import create_error_flash
from app.logger import log
from .bp import bp
@ -59,10 +60,7 @@ def add_contributor(book_id: int):
return response
else:
log(log.ERROR, "Book create errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(
url_for("book.settings", selected_tab=selected_tab, book_id=book_id)
)
@ -89,10 +87,7 @@ def delete_contributor(book_id: int):
return response
else:
log(log.ERROR, "Delete contributor errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(
url_for("book.settings", selected_tab=selected_tab, book_id=book_id)
)
@ -161,10 +156,7 @@ def edit_contributor_role(book_id: int):
)
else:
log(log.ERROR, "Edit contributor errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(
url_for("book.settings", selected_tab=selected_tab, book_id=book_id)
)

View File

@ -8,6 +8,7 @@ from app.controllers import (
from app import models as m, db, forms as f
from app.controllers.version import create_new_version
from app.controllers.delete_nested_book_entities import delete_nested_version_entities
from app.controllers.error_flashes import create_error_flash
from app.logger import log
from .bp import bp
@ -28,10 +29,7 @@ def create_version(book_id):
return redirect(redirect_url)
else:
log(log.ERROR, "Create version errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)
@ -64,10 +62,7 @@ def edit_version(book_id: int):
return redirect(redirect_url)
else:
log(log.ERROR, "Edit version errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)
@ -102,8 +97,5 @@ def delete_version(book_id: int):
return redirect(redirect_url)
else:
log(log.ERROR, "Delete version errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
return redirect(redirect_url)

View File

@ -1,3 +1,5 @@
from datetime import datetime, timedelta
from flask import Blueprint, render_template, redirect, url_for
from flask_login import login_required, current_user
@ -17,9 +19,13 @@ bp = Blueprint("notifications", __name__, url_prefix="/notifications")
@login_required
def get_all():
log(log.INFO, "Create query for notifications")
notifications: m.Notification = m.Notification.query.filter_by(
user_id=current_user.id
).order_by(m.Notification.created_at.desc())
notifications: m.Notification = (
m.Notification.query.filter(
m.Notification.created_at <= datetime.now() + timedelta(days=30)
)
.filter_by(user_id=current_user.id)
.order_by(m.Notification.created_at.desc())
)
log(log.INFO, "Create pagination for books")
pagination = create_pagination(total=notifications.count())

View File

@ -1,6 +1,7 @@
from flask import Blueprint, render_template, request, flash, redirect, url_for, jsonify
from flask_login import login_required, current_user, logout_user
from app.controllers import create_pagination
from app.controllers.error_flashes import create_error_flash
from sqlalchemy import func, not_, or_
from app import models as m, db
@ -46,10 +47,7 @@ def edit_profile():
return redirect(url_for("main.index"))
elif form.is_submitted():
log(log.ERROR, "Update user errors: [%s]", form.errors)
for field, errors in form.errors.items():
field_label = form._fields[field].label.text
for error in errors:
flash(error.replace("Field", field_label), "danger")
create_error_flash(form)
if current_user.is_activated:
form.username.data = current_user.username

View File

@ -1,13 +1,15 @@
const alertEvent = (e: any) => {
var confirmationMessage =
'It looks like you have been editing something. ' +
'If you leave before saving, your changes will be lost.';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
};
const initAlertOnClick = (element: HTMLElement) => {
element.addEventListener('click', () => {
window.addEventListener('beforeunload', function (e) {
var confirmationMessage =
'It looks like you have been editing something. ' +
'If you leave before saving, your changes will be lost.';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
window.addEventListener('beforeunload', alertEvent);
});
};
@ -18,8 +20,9 @@ export const initUnsavedChangedAlerts = () => {
'.book-tags-input',
'.multiple-input-word',
'.contributor-role-select',
'.edit-permissions-btn',
// '.edit-permissions-btn',
'.add-contributor-btn',
'input[type=checkbox]',
];
elementsSelectors.forEach(selector => {
@ -29,4 +32,14 @@ export const initUnsavedChangedAlerts = () => {
initAlertOnClick(element);
});
});
const elementsOnClickPrevent = document.querySelectorAll(
'.prevent-unsaved-changes-event',
);
elementsOnClickPrevent.forEach(element => {
element.addEventListener('click', () => {
document.removeEventListener('beforeunload', alertEvent);
window.removeEventListener('beforeunload', alertEvent);
});
});
};