added notification page and change export->have no permissions

This commit is contained in:
Kostiantyn Stoliarskyi 2023-06-08 16:44:13 +03:00
parent 999fbe1951
commit 0fc94d3180
11 changed files with 280 additions and 141 deletions

View File

@ -29,6 +29,7 @@ def create_app(environment="development"):
star_blueprint,
permissions_blueprint,
search_blueprint,
notifications_blueprint,
)
from app import models as m
@ -58,6 +59,7 @@ def create_app(environment="development"):
app.register_blueprint(star_blueprint)
app.register_blueprint(permissions_blueprint)
app.register_blueprint(search_blueprint)
app.register_blueprint(notifications_blueprint)
# Set up flask login.
@login_manager.user_loader

View File

@ -71,6 +71,16 @@ class User(BaseModel, UserMixin):
contributions.append(comment.interpretation)
return contributions
@property
def active_notifications(self):
items = [
notification
for notification in self.notifications
if not notification.is_read
]
items.sort(key=lambda x: x.created_at)
return items
class AnonymousUser(AnonymousUserMixin):
pass

View File

@ -8,28 +8,28 @@
{% if access_to_create_collections or access_to_update_collections %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
{% if access_to_create_collections_in_root %}
<li>
<button
type="button"
data-modal-target="add-collection-modal"
data-modal-toggle="add-collection-modal"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Collection
</button>
</li>
{% endif %}
{% if collection.active_children or not collection.active_sections%}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Subcollection
</button>
</li>
<li>
<button
type="button"
data-modal-target="add-collection-modal"
data-modal-toggle="add-collection-modal"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Collection
</button>
</li>
{% endif %} {% if collection.active_children or not
collection.active_sections%}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Subcollection
</button>
</li>
<!-- prettier-ignore -->
{% endif %}
{% if access_to_create_section %}
@ -80,15 +80,19 @@
{% endif %}
</ul>
{% endif %}
<!-- prettier-ignore -->
{% if not access_to_create_collections_in_root and not access_to_create_collections and not access_to_update_collections and not access_to_delete_collections and not access_to_create_section %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Export Collection
You have no permissions for this collection
</button>
</li>
</ul>
{% endif %}
<!-- prettier-ignore -->
{% else %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>

View File

@ -24,16 +24,19 @@
{% endif %}
</ul>
{% endif %}
<!-- prettier-ignore -->
{% if not access_to_create_sections and not access_to_update_sections and not access_to_delete_sections %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Export Section
You have no permissions for this section
</button>
</li>
</ul>
{% endif %}
<!-- prettier-ignore -->
{% else %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>

View File

@ -6,120 +6,118 @@
{% set access_to_create_section = has_permission(sub_collection, Access.C,EntityType.SECTION) %}
{% if access_to_create_collections or access_to_update_collections or access_to_create_section %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<!-- prettier-ignore -->
{% if access_to_create_section and sub_collection.active_sections and not sub_collection.active_children %}
<li>
<button
type="button"
id="callAddSectionModal"
data-modal-target="add-section-modal"
data-modal-toggle="add-section-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
New Section
</button>
</li>
<!-- prettier-ignore -->
{% elif not sub_collection.active_sections and not sub_collection.active_children %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<!-- prettier-ignore -->
{% if access_to_create_section and sub_collection.active_sections and not sub_collection.active_children %}
<li>
<button
type="button"
id="callAddSectionModal"
data-modal-target="add-section-modal"
data-modal-toggle="add-section-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Section
</button>
</li>
<!-- prettier-ignore -->
{% elif not sub_collection.active_sections and not sub_collection.active_children %}
{% if access_to_create_section %}
<li>
<button
type="button"
id="callAddSectionModal"
data-modal-target="add-section-modal"
data-modal-toggle="add-section-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
New Section
</button>
</li>
{% endif %}
<!-- prettier-ignore -->
{% if access_to_create_collections %}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
New Subcollection
</button>
</li>
{% endif %}
{% else %}
<!-- prettier-ignore -->
{% if access_to_create_collections %}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Subcollection
</button>
</li>
{% endif %}
{% endif %}
</ul>
<li>
<button
type="button"
id="callAddSectionModal"
data-modal-target="add-section-modal"
data-modal-toggle="add-section-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Section
</button>
</li>
{% endif %}
<!-- prettier-ignore -->
{% if access_to_update_collections or access_to_delete_collections%}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
{% if access_to_update_collections %}
<li>
<button
type="button"
id="rename-sub-collection-button-{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Rename Sub Collection
</button>
</li>
{% endif %}
<!-- prettier-ignore -->
{% if access_to_delete_collections %}
<li>
<button
type="button"
id="callDeleteSubCollectionModal"
data-modal-target="delete-sub-collection-modal"
data-modal-toggle="delete-sub-collection-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
Delete Sub Collection
</button>
</li>
{% endif %}
</ul>
{% endif %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Export Sub Collection
</button>
</li>
</ul>
{% else %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Connect your wallet to do this
</button>
</li>
</ul>
{% if access_to_create_collections %}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Subcollection
</button>
</li>
{% endif %} {% else %}
<!-- prettier-ignore -->
{% if access_to_create_collections %}
<li>
<button
type="button"
id="callAddSubCollectionModal"
data-modal-target="add-sub-collection-modal"
data-modal-toggle="add-sub-collection-modal"
data-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
New Subcollection
</button>
</li>
{% endif %} {% endif %}
</ul>
{% endif %}
<!-- prettier-ignore -->
{% if access_to_update_collections or access_to_delete_collections%}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
{% if access_to_update_collections %}
<li>
<button
type="button"
id="rename-sub-collection-button-{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Rename Sub Collection
</button>
</li>
{% endif %}
<!-- prettier-ignore -->
{% if access_to_delete_collections %}
<li>
<button
type="button"
id="callDeleteSubCollectionModal"
data-modal-target="delete-sub-collection-modal"
data-modal-toggle="delete-sub-collection-modal"
data-collection-id="{{collection.id}}"
data-sub-collection-id="{{sub_collection.id}}"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Delete Sub Collection
</button>
</li>
{% endif %}
</ul>
{% endif %}
<!-- prettier-ignore -->
{% if not access_to_create_collections and not access_to_update_collections and not access_to_delete_collections and not access_to_create_section%}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
You have no permissions for this sub collection
</button>
</li>
</ul>
{% endif %}
<!-- prettier-ignore -->
{% else %}
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
<li>
<button
type="button"
class="w-full block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Connect your wallet to do this
</button>
</li>
</ul>
{% endif %}

View File

@ -92,7 +92,7 @@
<div class="block px-4 py-2 font-medium text-center text-gray-700 rounded-t-lg bg-gray-50 dark:bg-gray-800 dark:text-white"> Notifications </div>
<div class="divide-y divide-gray-100 dark:divide-gray-700">
{% include 'notification.html' %}
<a href="#" class="block py-2 text-sm font-medium text-center text-gray-900 rounded-b-lg bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-white">
<a href="{{url_for('notifications.get_all')}}" class="block py-2 text-sm font-medium text-center text-gray-900 rounded-b-lg bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-white">
<div class="inline-flex items-center">
<svg class="w-4 h-4 mr-2 text-gray-500 dark:text-gray-400" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="M10 12a2 2 0 100-4 2 2 0 000 4z"></path> <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"></path> </svg>
View all

View File

@ -1,5 +1,5 @@
<!-- prettier-ignore -->
{% if not current_user.notifications %}
{% if not current_user.active_notifications %}
<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">
@ -10,7 +10,7 @@
<!-- prettier-ignore -->
{% endif %}
<!-- prettier-ignore -->
{% for notification in current_user.notifications[:5]%}
{% for notification in current_user.active_notifications[:5]%}
<a
href="{{notification.link}}"
class="flex px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700">

View File

@ -0,0 +1,85 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block title %}Notifications{% endblock %}
{% block right_sidebar %}
{% endblock %}
{% block content %}
<div class="relative overflow-x-auto shadow-md sm:rounded-lg mt-1">
<!-- prettier-ignore -->
<div class="p-5 flex border-b-2 border-gray-200 border-solid dark:border-gray-700 text-gray-900 dark:text-white dark:divide-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8"> <path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" /> </svg>
<h1 class="text-2xl font-extrabold dark:text-white ml-4">Notifications</h1>
</div>
{% if not current_user.notifications %}
<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">
You don't have notifications!
</p>
{% endif %} {% for notification in current_user.notifications %}
<!-- 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 pb-4" href="{{notification.link}}">{{notification.text}}</a> </dt>
<dd class="flex flex-col md:flex-row text-lg font-semibold text-gray-500 md:text-lg dark:text-gray-400">
<p> Created at {{notification.created_at.strftime('%B %d, %Y')}}</p>
</dd>
</dl>
{% endfor %}
<!-- prettier-ignore -->
{% if page.pages > 1 %}
<div class="container content-center mt-3 flex bg-white dark:bg-gray-800">
<nav aria-label="Page navigation example" class="mx-auto">
<ul class="inline-flex items-center -space-x-px">
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page=1&q={{page.query}}" class="block px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<span class="sr-only">First</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M15.79 14.77a.75.75 0 01-1.06.02l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 111.04 1.08L11.832 10l3.938 3.71a.75.75 0 01.02 1.06zm-6 0a.75.75 0 01-1.06.02l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 111.04 1.08L5.832 10l3.938 3.71a.75.75 0 01.02 1.06z" clip-rule="evenodd" /> </svg>
</a>
</li>
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page={{page.page-1 if page.page > 1 else 1}}&q={{page.query}}" class="block px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<span class="sr-only">Previous</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
<!-- prettier-ignore -->
{% for p in page.pages_for_links %}
<li>
<!-- prettier-ignore -->
{% if p == page.page %}
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page={{p}}&q={{page.query}}" aria-current="page" class="z-10 px-3 py-2 leading-tight text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white">{{p}}</a>
{% else %}
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page={{p}}&q={{page.query}}" class="px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">{{p}}</a>
{% endif %}
</li>
{% endfor %}
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page={{page.page+1 if page.page < page.pages else page.pages}}&q={{page.query}}" class="block px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<!-- prettier-ignore -->
<span class="sr-only">Next</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('notifications.get_all') }}?page={{page.pages}}&q={{page.query}}" class="block px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<!-- prettier-ignore -->
<span class="sr-only">Last</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M10.21 14.77a.75.75 0 01.02-1.06L14.168 10 10.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> <path fill-rule="evenodd" d="M4.21 14.77a.75.75 0 01.02-1.06L8.168 10 4.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
</ul>
</nav>
</div>
{% endif %}
</div>
<!-- prettier-ignore -->
{% endblock %}

View File

@ -9,3 +9,4 @@ from .approve import bp as approve_blueprint
from .star import bp as star_blueprint
from .permission import bp as permissions_blueprint
from .search import bp as search_blueprint
from .notifications import bp as notifications_blueprint

View File

@ -0,0 +1,2 @@
# flake8: noqa F401
from .notifications import bp

View File

@ -0,0 +1,34 @@
from flask import Blueprint, render_template
from flask_login import login_required, current_user
from app.controllers import (
create_pagination,
)
from app import models as m
from app.logger import log
bp = Blueprint("notifications", __name__, url_prefix="/notifications")
@bp.route("/all", methods=["GET"])
@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())
log(log.INFO, "Create pagination for books")
pagination = create_pagination(total=notifications.count())
log(log.INFO, "Returning data for front end")
return render_template(
"notifications/index.html",
notifications=notifications.paginate(
page=pagination.page, per_page=pagination.per_page
),
page=pagination,
)