diff --git a/models/database.py b/models/database.py index 9c19723d2c74122c26da09f2d8cf01d83ca3c5ce..215c3da5340ba76ccfe461846cd6e0a72508f811 100644 --- a/models/database.py +++ b/models/database.py @@ -11,6 +11,7 @@ import os from sqlalchemy import event from sqlalchemy.orm import relationship, backref, sessionmaker +from sqlalchemy.ext.hybrid import hybrid_method import config @@ -52,6 +53,7 @@ class ProtocolType(db.Model): return None return candidates[0] + @hybrid_method def has_public_view_right(self, user): return (self.is_public or (user is not None and @@ -65,12 +67,26 @@ class ProtocolType(db.Model): return self.has_private_view_right(user) @staticmethod - def get_available_protocoltypes(user): + def get_modifiable_protocoltypes(user): return [ protocoltype for protocoltype in ProtocolType.query.all() if protocoltype.has_modify_right(user) ] + @staticmethod + def get_public_protocoltypes(user): + return [ + protocoltype for protocoltype in ProtocolType.query.all() + if protocoltype.has_public_view_right(user) + ] + + @staticmethod + def get_private_protocoltypes(user): + return [ + protocoltype for protocoltype in ProtocolType.query.all() + if protocoltype.has_private_view_right(user) + ] + class Protocol(db.Model): diff --git a/server.py b/server.py index 0279cfc9038e8e33cea3d9a159d9bc56a9e72eac..6c1b428e97f82bc02a20218bab3c4fc4aff42aa2 100755 --- a/server.py +++ b/server.py @@ -18,7 +18,7 @@ from shared import db, date_filter, datetime_filter, date_filter_long, time_filt from utils import is_past, mail_manager, url_manager, get_first_unused_int, set_etherpad_text, get_etherpad_text from models.database import ProtocolType, Protocol, DefaultTOP, TOP, Document, Todo, Decision, MeetingReminder, Error from views.forms import LoginForm, ProtocolTypeForm, DefaultTopForm, MeetingReminderForm, NewProtocolForm, DocumentUploadForm, KnownProtocolSourceUploadForm, NewProtocolSourceUploadForm, ProtocolForm, TopForm, SearchForm -from views.tables import ProtocolsTable, ProtocolTypesTable, ProtocolTypeTable, DefaultTOPsTable, MeetingRemindersTable, ErrorsTable, TodosTable, DocumentsTable +from views.tables import ProtocolsTable, ProtocolTypesTable, ProtocolTypeTable, DefaultTOPsTable, MeetingRemindersTable, ErrorsTable, TodosTable, DocumentsTable, DecisionsTable app = Flask(__name__) app.config.from_object(config) @@ -293,7 +293,7 @@ def list_protocols(): @login_required def new_protocol(): user = current_user() - protocoltypes = ProtocolType.get_available_protocoltypes(user) + protocoltypes = ProtocolType.get_modifiable_protocoltypes(user) form = NewProtocolForm(protocoltypes) upload_form = NewProtocolSourceUploadForm(protocoltypes) if form.validate_on_submit(): @@ -549,30 +549,80 @@ def list_todos(): except (ValueError, TypeError): pass search_term = request.args.get("search") - protocoltypes = ProtocolType.get_available_protocoltypes(user) + protocoltypes = ProtocolType.get_public_protocoltypes(user) search_form = SearchForm(protocoltypes) if protocoltype_id is not None: - print(protocoltype_id) search_form.protocoltype.data = protocoltype_id protocoltype = ProtocolType.query.filter_by(id=protocoltype_id).first() if search_term is not None: search_form.search.data = search_term - base_query = Todo.query.order_by(Todo.done).order_by(Todo.number.desc()) + todos = [ + todo for todo in Todo.query.all() + if todo.protocoltype.has_public_view_right(user) + ] if protocoltype_id is not None and protocoltype_id != -1: - base_query = base_query.filter(ProtocolType.id == protocoltype_id) + todos = [ + todo for todo in todos + if todo.protocoltype.id == protocoltype_id + ] if search_term is not None and len(search_term.strip()) > 0: - base_query = base_query.filter(Todo.description.match("%{}%".format(search_term))) + todos = [ + todo for todo in todos + if search_term.lower() in todo.description.lower() + ] page = _get_page() - page_count = int(math.ceil(base_query.count() / config.PAGE_LENGTH)) + page_count = int(math.ceil(len(todos) / config.PAGE_LENGTH)) if page >= page_count: page = 0 begin_index = page * config.PAGE_LENGTH end_index = (page + 1) * config.PAGE_LENGTH - todos = base_query.slice(begin_index, end_index).all() - # TODO: paginate and search + todos = todos[begin_index:end_index] todos_table = TodosTable(todos) return render_template("todos-list.html", todos=todos, todos_table=todos_table, search_form=search_form, page=page, page_count=page_count, page_diff=config.PAGE_DIFF, protocoltype_id=protocoltype_id, search_term=search_term) +@app.route("/decisions/list") +def list_decisions(): + is_logged_In = check_login() + user = current_user() + protocoltype = None + protocoltype_id = None + try: + protocoltype_id = int(request.args.get("protocoltype")) + except (ValueError, TypeError): + pass + search_term = request.args.get("search") + protocoltypes = ProtocolType.get_public_protocoltypes(user) + search_form = SearchForm(protocoltypes) + if protocoltype_id is not None: + search_form.protocoltype.data = protocoltype_id + protocoltype = ProtocolType.query.filter_by(id=protocoltype_id).first() + if search_term is not None: + search_form.search.data = search_term + decisions = [ + decision for decision in Decision.query.all() + if decision.protocol.protocoltype.has_public_view_right(user) + ] + if protocoltype_id is not None and protocoltype_id != -1: + decisions = [ + decision for decision in decisions + if decision.protocol.protocoltype.id == protocoltype_id + ] + if search_term is not None and len(search_term.strip()) > 0: + decisions = [ + decision for decision in decisions + if search_term.lower() in decision.content.lower() + ] + page = _get_page() + page_count = int(math.ceil(len(decisions) / config.PAGE_LENGTH)) + if page >= page_count: + page = 0 + begin_index = page * config.PAGE_LENGTH + end_index = (page + 1) * config.PAGE_LENGTH + decisions = decisions[begin_index:end_index] + decisions_table = DecisionsTable(decisions) + return render_template("decisions-list.html", decisions=decisions, decisions_table=decisions_table, search_form=search_form, page=page, page_count=page_count, page_diff=config.PAGE_DIFF, protocoltype_id=protocoltype_id, search_term=search_term) + + @app.route("/document/download/<int:document_id>") def download_document(document_id): user = current_user() diff --git a/templates/decisions-list.html b/templates/decisions-list.html new file mode 100644 index 0000000000000000000000000000000000000000..4d16abe2e7168af47e2b77a2c43a18adcbd45734 --- /dev/null +++ b/templates/decisions-list.html @@ -0,0 +1,29 @@ +{% extends "layout.html" %} +{% from "macros.html" import render_table, render_form %} +{% block title %}Beschlüsse{% endblock %} + +{% macro page_link(page, text) %} + <a href="{{url_for(request.endpoint, page=page, protocoltype=protocoltype_id, search=search_term)}}">{{text}}</a> +{% endmacro %} + +{% block content %} +<div class="container"> + {{render_form(search_form, class_="form-inline", action_url=url_for("list_decisions"), action_text="Suchen", labels_visible=False, method="GET")}} + {{render_table(decisions_table)}} + <div class="centered"> + {% if page > page_diff %} + {{page_link(0, "<<")}} + {% endif %} + {% for p in range(max(0, page - page_diff), min(page_count, page + page_diff)) %} + {% if p != page %} + {{page_link(p, p + 1)}} + {% else %} + Seite {{p + 1}} + {% endif %} + {% endfor %} + {% if page < page_count - page_diff %} + {{page_link(page_count - 1, ">>")}} + {% endif %} + </div> +</div> +{% endblock %} diff --git a/templates/layout.html b/templates/layout.html index 18ae724e06af1e03bf8cdd4cc0fe58324c27ba39..57520e3b5b57197f14228d3a1b6b4229969bfbe9 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -22,16 +22,16 @@ <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - <a class="navbar-brand" href="#">Protokolle</a> + <a class="navbar-brand" href="{{url_for("index")}}">Protokolle</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav"> - <li><a href="{{url_for("index")}}">Zuhause</a></li> {% if check_login() %} <li><a href="{{url_for("new_protocol")}}">Neues Protokoll</a></li> {% endif %} <li><a href="{{url_for("list_protocols")}}">Protokolle</a></li> <li><a href="{{url_for("list_todos")}}">Todos</a></li> + <li><a href="{{url_for("list_decisions")}}">Beschlüsse</a></li> {% if check_login() %} <li><a href="{{url_for("list_types")}}">Typen</a></li> {% endif %} diff --git a/views/tables.py b/views/tables.py index 77013423346c7e8a508bdb4b628a235d3fbd5e76..f7f5255d145ff66cf72907940e9f2c4440150b86 100644 --- a/views/tables.py +++ b/views/tables.py @@ -188,6 +188,19 @@ class TodosTable(Table): todo.description ] +class DecisionsTable(Table): + def __init__(self, decisions): + super().__init__("Beschlüsse", decisions) + + def headers(self): + return ["Sitzung", "Beschluss"] + + def row(self, decision): + return [ + Table.link(url_for("show_protocol", protocol_id=decision.protocol.id), decision.protocol.get_identifier()), + decision.content + ] + class DocumentsTable(Table): def __init__(self, documents): super().__init__("Anhang", documents)