From 54099ad5e95df1717cde07f2eca4ca9e44971ee3 Mon Sep 17 00:00:00 2001
From: Robin Sonnabend <robin@fsmpi.rwth-aachen.de>
Date: Sat, 25 Feb 2017 23:05:08 +0100
Subject: [PATCH] Protocol search

---
 parser.py                     |  2 ++
 server.py                     | 41 +++++++++++++++++++++++++++++++----
 templates/decisions-list.html |  4 ++--
 templates/protocol.txt        |  1 +
 templates/protocols-list.html | 22 ++++++++++++++++++-
 templates/todos-list.html     |  4 ++--
 utils.py                      | 28 ++++++++++++++++++++++++
 7 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/parser.py b/parser.py
index 0e1a62f..edebf90 100644
--- a/parser.py
+++ b/parser.py
@@ -196,6 +196,8 @@ class Tag:
                 return self.todo.render_latex(current_protocol=protocol)
             return r"\textbf{{{}:}} {}".format(escape_tex(self.name.capitalize()), escape_tex(self.values[0]))
         elif render_type == RenderType.plaintext:
+            if self.name == "url":
+                return self.values[0]
             return "{}: {}".format(self.name.capitalize(), self.values[0])
         elif render_type == RenderType.wikitext:
             if self.name == "url":
diff --git a/server.py b/server.py
index f5c8cb1..1b087d1 100755
--- a/server.py
+++ b/server.py
@@ -15,7 +15,7 @@ import math
 
 import config
 from shared import db, date_filter, datetime_filter, date_filter_long, time_filter, ldap_manager, security_manager, current_user, check_login, login_required, group_required, class_filter
-from utils import is_past, mail_manager, url_manager, get_first_unused_int, set_etherpad_text, get_etherpad_text
+from utils import is_past, mail_manager, url_manager, get_first_unused_int, set_etherpad_text, get_etherpad_text, split_terms
 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, DecisionsTable
@@ -282,15 +282,48 @@ def move_default_top(type_id, top_id, diff):
 def list_protocols():
     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
+    protocol_query = Protocol.query
+    if search_term is not None:
+        match_target = Protocol.content_public
+        if protocoltype is not None and protocoltype.has_private_view_right(user):
+            match_target = Protocol.content_private
+        for term in split_terms(search_term):
+            protocol_query = protocol_query.filter(match_target.match("%{}%".format(term)))
     protocols = [
-        protocol for protocol in Protocol.query.all()
+        protocol for protocol in protocol_query.all()
         if (not is_logged_in and protocol.protocoltype.is_public)
         or (is_logged_in and (
             protocol.protocoltype.public_group in user.groups
             or protocol.protocoltype.private_group in user.groups))]
-    # TODO: sort by date and paginate
+    if protocoltype_id is not None and protocoltype_id != -1:
+        protocols = [
+            protocol for protocol in protocols
+            if protocol.protocoltype.id == protocoltype_id
+        ]
+    protocols = sorted(protocols, key=lambda protocol: protocol.date, reverse=True)
+    page = _get_page()
+    page_count = int(math.ceil(len(protocols)) / config.PAGE_LENGTH)
+    if page >= page_count:
+        page = 0
+    begin_index = page * config.PAGE_LENGTH
+    end_index = (page + 1) * config.PAGE_LENGTH
+    protocols = protocols[begin_index:end_index]
     protocols_table = ProtocolsTable(protocols)
-    return render_template("protocols-list.html", protocols=protocols, protocols_table=protocols_table)
+    return render_template("protocols-list.html", protocols=protocols, protocols_table=protocols_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("/protocol/new", methods=["GET", "POST"])
 @login_required
diff --git a/templates/decisions-list.html b/templates/decisions-list.html
index 4d16abe..c62a083 100644
--- a/templates/decisions-list.html
+++ b/templates/decisions-list.html
@@ -14,14 +14,14 @@
         {% if page > page_diff %}
             {{page_link(0, "<<")}}
         {% endif %}
-        {% for p in range(max(0, page - page_diff), min(page_count, page + page_diff)) %}
+        {% for p in range(max(0, page - page_diff), min(page_count, page + page_diff + 1)) %}
             {% if p != page %}
                 {{page_link(p, p + 1)}}
             {% else %}
                 Seite {{p + 1}}
             {% endif %}
         {% endfor %}
-        {% if page < page_count - page_diff %}
+        {% if page < page_count - page_diff - 1 %}
             {{page_link(page_count - 1, ">>")}}
         {% endif %}
     </div>
diff --git a/templates/protocol.txt b/templates/protocol.txt
index 50a816d..d255a79 100644
--- a/templates/protocol.txt
+++ b/templates/protocol.txt
@@ -1,5 +1,6 @@
 {% for top in tree.children %}
 {% if top|class == "Fork" %}
 {{top.render(render_type=render_type, level=0, show_private=show_private, protocol=protocol)}}
+
 {% endif %}
 {% endfor %}
diff --git a/templates/protocols-list.html b/templates/protocols-list.html
index 43d3cdb..3f8e842 100644
--- a/templates/protocols-list.html
+++ b/templates/protocols-list.html
@@ -1,9 +1,29 @@
 {% extends "layout.html" %}
-{% from "macros.html" import render_table %}
+{% from "macros.html" import render_table, render_form %}
 {% block title %}Protokolle{% 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_protocols"), action_text="Suchen", labels_visible=False, method="GET")}}
     {{render_table(protocols_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 + 1)) %}
+            {% if p != page %}
+                {{page_link(p, p + 1)}}
+            {% else %}
+                Seite {{p + 1}}
+            {% endif %}
+        {% endfor %}
+        {% if page < page_count - page_diff - 1 %}
+            {{page_link(page_count - 1, ">>")}}
+        {% endif %}
+    </div>
 </div>
 {% endblock %}
diff --git a/templates/todos-list.html b/templates/todos-list.html
index c663b0c..fefb0c6 100644
--- a/templates/todos-list.html
+++ b/templates/todos-list.html
@@ -14,14 +14,14 @@
         {% if page > page_diff %}
             {{page_link(0, "<<")}}
         {% endif %}
-        {% for p in range(max(0, page - page_diff), min(page_count, page + page_diff)) %}
+        {% for p in range(max(0, page - page_diff), min(page_count, page + page_diff + 1)) %}
             {% if p != page %}
                 {{page_link(p, p + 1)}}
             {% else %}
                 Seite {{p + 1}}
             {% endif %}
         {% endfor %}
-        {% if page < page_count - page_diff %}
+        {% if page < page_count - page_diff - 1 %}
             {{page_link(page_count - 1, ">>")}}
         {% endif %}
     </div>
diff --git a/utils.py b/utils.py
index 6d818bc..bd6f3ce 100644
--- a/utils.py
+++ b/utils.py
@@ -124,3 +124,31 @@ def set_etherpad_text(pad, text, only_if_default=True):
     req = requests.post(get_etherpad_import_url(pad), files=files)
     return req.status_code == 200
     
+def split_terms(text, quote_chars="\"'", separators=" \t\n"):
+    terms = []
+    in_quote = False
+    last_quote_char = ""
+    current_term = ""
+    for char in text:
+        if in_quote:
+            if char != last_quote_char:
+                current_term += char
+            else:
+                in_quote = False
+                last_quote_char = ""
+                terms.append(current_term)
+                current_term = ""
+        else:
+            if char in separators:
+                if len(current_term) > 0:
+                    terms.append(current_term)
+                    current_term = ""
+            else:
+                if char in quote_chars and len(current_term) == 0:
+                    in_quote = True
+                    last_quote_char = char
+                else:
+                    current_term += char
+    if len(current_term) > 0:
+        terms.append(current_term)
+    return terms
-- 
GitLab