python3 fet2020/manage.py create_thumbs
-
\ No newline at end of file
+
+
+Erstellt alle Searchindexes neu.
+
+python3 fet2020/manage.py rebuild_index
+
+
+Aktualisiert alle Searchindexes, die in den letzten 24 Stunden geändert wurden.
+
+python3 fet2020/manage.py update_index --age=24
+
diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py
index 7a661a56..d36cb3bc 100644
--- a/fet2020/fet2020/settings.py
+++ b/fet2020/fet2020/settings.py
@@ -66,7 +66,7 @@ INSTALLED_APPS = [
"django.contrib.sites",
"django.contrib.sitemaps",
"django.contrib.flatpages",
-
+
"taggit",
"ckeditor",
"ckeditor_uploader",
@@ -77,7 +77,9 @@ INSTALLED_APPS = [
"django_filters",
"django_static_jquery_ui",
"fontawesomefree",
-
+ "whoosh",
+ "haystack",
+
"core.apps.CoreConfig",
"posts.apps.PostsConfig",
"members.apps.MembersConfig",
@@ -344,3 +346,12 @@ GALLERY = {
CSRF_TRUSTED_ORIGINS = [
"https://" + env("HOST_NAME"),
]
+
+
+# DJANGO HAYSTACK
+HAYSTACK_CONNECTIONS = {
+ "default": {
+ "ENGINE": "haystack.backends.whoosh_backend.WhooshEngine",
+ "PATH": os.path.join(BASE_DIR, "whoosh_index"),
+ },
+}
diff --git a/fet2020/fet2020/urls.py b/fet2020/fet2020/urls.py
index cdc4516e..8e865e75 100644
--- a/fet2020/fet2020/urls.py
+++ b/fet2020/fet2020/urls.py
@@ -41,6 +41,7 @@ urlpatterns = [
path("members/", include("members.urls"), name="members"),
path("member/", include(member_urlpatterns), name="member"),
path("posts/", include("posts.urls")),
+ path("search/", include("search.urls")),
path("tasks/", include("tasks.urls"), name="tasks"),
path("intern/", include("intern.urls"), name="intern"),
path(
diff --git a/fet2020/intern/models.py b/fet2020/intern/models.py
index e9cd223e..6cffd8a0 100644
--- a/fet2020/intern/models.py
+++ b/fet2020/intern/models.py
@@ -9,7 +9,8 @@ from django.utils import timezone
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
-from documents import create_pad
+from documents import create_pad, get_pad_html
+from documents.api import get_pad_link
from tasks.models import TaskList
logger = logging.getLogger(__name__)
@@ -139,6 +140,12 @@ class Etherpad(models.Model):
),
]
+ def __str__(self):
+ return self.title
+
+ def get_absolute_url(self):
+ return get_pad_link(self.__get_pad_name())
+
def __get_pad_name(self):
return (
slugify(self.date)
@@ -170,8 +177,12 @@ class Etherpad(models.Model):
_(f"Etherpad '{pad_name}' konnte nicht erstellt werden."),
)
- def __str__(self):
- return self.title
+ @property
+ def etherpad_html(self):
+ if not self.__get_pad_name():
+ return None
+
+ return get_pad_html(self.__get_pad_name())
class FileUpload(models.Model):
diff --git a/fet2020/intern/search_indexes.py b/fet2020/intern/search_indexes.py
new file mode 100644
index 00000000..4d4cb5a7
--- /dev/null
+++ b/fet2020/intern/search_indexes.py
@@ -0,0 +1,17 @@
+from haystack import indexes
+from html2text import html2text
+
+from .models import Etherpad
+
+
+class EtherpadIndex(indexes.SearchIndex, indexes.Indexable):
+ text = indexes.CharField(document=True, use_template=True)
+ title = indexes.CharField(model_attr="title")
+ date = indexes.DateField(model_attr="date")
+ etherpad = indexes.EdgeNgramField(null=True)
+
+ def get_model(self):
+ return Etherpad
+
+ def prepare_etherpad(self, obj):
+ return html2text(obj.etherpad_html)
diff --git a/fet2020/posts/search_indexes.py b/fet2020/posts/search_indexes.py
new file mode 100644
index 00000000..596aede7
--- /dev/null
+++ b/fet2020/posts/search_indexes.py
@@ -0,0 +1,38 @@
+from haystack import indexes
+from html2text import html2text
+
+from .models import Post
+
+
+class PostIndex(indexes.SearchIndex, indexes.Indexable):
+ text = indexes.CharField(document=True, use_template=True)
+ title = indexes.EdgeNgramField(model_attr="title")
+ body = indexes.EdgeNgramField(model_attr="body", null=True)
+ status = indexes.EdgeNgramField(model_attr="status")
+ date = indexes.DateField()
+ agenda = indexes.EdgeNgramField(null=True)
+ protocol = indexes.EdgeNgramField(null=True)
+
+ def get_model(self):
+ return Post
+
+ def index_queryset(self, using=None):
+ return self.get_model().objects.date_sorted_list(public=False)
+
+ def prepare_date(self, obj):
+ if obj.post_type == "N":
+ return obj.public_date
+ elif obj.post_type == "E":
+ return obj.event_start.date()
+ elif obj.post_type == "F":
+ return obj.event_start.date()
+
+ def prepare_agenda(self, obj):
+ if obj.has_agenda:
+ return html2text(obj.agenda_html)
+ return None
+
+ def prepare_protocol(self, obj):
+ if obj.has_protocol:
+ return html2text(obj.protocol_html)
+ return None
diff --git a/fet2020/requirements.txt b/fet2020/requirements.txt
index 7c9dfc76..f35498e9 100644
--- a/fet2020/requirements.txt
+++ b/fet2020/requirements.txt
@@ -3,6 +3,7 @@ django-ckeditor==6.2.0
django-crontab==0.7.1
django-environ==0.8.1
django-filter==21.1
+django-haystack==3.2.dev0
django-static-jquery-ui==1.12.1.1
django-softhyphen==1.1.0
django-taggit==2.1.0
diff --git a/fet2020/search/__init__.py b/fet2020/search/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/fet2020/search/forms.py b/fet2020/search/forms.py
new file mode 100644
index 00000000..045b0199
--- /dev/null
+++ b/fet2020/search/forms.py
@@ -0,0 +1,60 @@
+from collections import deque
+
+from haystack.forms import SearchForm
+from haystack.query import SQ
+
+from intern.models import Etherpad
+from posts.models import Post
+
+
+class FetUserSearchForm(SearchForm):
+ def search(self):
+ if not self.is_valid():
+ return self.no_query_found()
+
+ if not self.cleaned_data.get("q"):
+ return self.no_query_found()
+
+ sqs_post = self.searchqueryset.models(Post)
+ sqs_post = sqs_post.filter(
+ SQ(title__icontains=self.cleaned_data["q"])
+ | SQ(body__icontains=self.cleaned_data["q"])
+ | SQ(agenda__icontains=self.cleaned_data["q"])
+ | SQ(protocol__icontains=self.cleaned_data["q"])
+ )
+
+ sqs_intern = self.searchqueryset.models(Etherpad)
+ sqs_intern = sqs_intern.filter(etherpad__icontains=self.cleaned_data["q"])
+
+ results = deque([])
+
+ for elem in sqs_post.order_by("-date"):
+ results.append(elem.object)
+
+ for elem in sqs_intern.order_by("-date"):
+ results.append(elem.object)
+
+ return sorted(results, key=lambda elem: elem.date, reverse=True)
+
+
+class NonUserSearchForm(SearchForm):
+ def search(self):
+ if not self.is_valid():
+ return self.no_query_found()
+
+ if not self.cleaned_data.get("q"):
+ return self.no_query_found()
+
+ sqs_post = self.searchqueryset.models(Post).filter(status="20")
+ sqs_post = sqs_post.filter(
+ SQ(title__icontains=self.cleaned_data["q"])
+ | SQ(body__icontains=self.cleaned_data["q"])
+ | SQ(agenda__icontains=self.cleaned_data["q"])
+ )
+
+ results = deque([])
+
+ for elem in sqs_post.order_by("-date"):
+ results.append(elem.object)
+
+ return sorted(results, key=lambda elem: elem.date, reverse=True)
diff --git a/fet2020/search/urls.py b/fet2020/search/urls.py
new file mode 100644
index 00000000..68e46d2e
--- /dev/null
+++ b/fet2020/search/urls.py
@@ -0,0 +1,7 @@
+from django.urls import path, re_path
+
+from . import views
+
+urlpatterns = [
+ path("", views.index, name="index"),
+]
diff --git a/fet2020/search/views.py b/fet2020/search/views.py
new file mode 100644
index 00000000..de5c67fd
--- /dev/null
+++ b/fet2020/search/views.py
@@ -0,0 +1,26 @@
+from haystack.generic_views import SearchView
+from haystack.query import SearchQuerySet
+
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.shortcuts import render
+
+from .forms import FetUserSearchForm, NonUserSearchForm
+
+
+class FetUserSearchView(LoginRequiredMixin, SearchView):
+ template_name = "search/index.html"
+ queryset = SearchQuerySet()
+ form_class = FetUserSearchForm
+
+
+class NonUserSearchView(SearchView):
+ template_name = "search/index.html"
+ queryset = SearchQuerySet()
+ form_class = NonUserSearchForm
+
+
+def index(request):
+ if request.user.is_authenticated:
+ return FetUserSearchView.as_view()(request)
+
+ return NonUserSearchView.as_view()(request)
diff --git a/fet2020/templates/search/index.html b/fet2020/templates/search/index.html
new file mode 100644
index 00000000..e2b4d349
--- /dev/null
+++ b/fet2020/templates/search/index.html
@@ -0,0 +1,33 @@
+{% extends 'base.html' %}
+
+{% block content %}
+