Browse Source

Merge pull request #211 from sh4nks/replace-whooshalchemy

Replace Flask-WhooshAlchemy with Flask-Whooshee
Peter Justin 8 years ago
parent
commit
4bda8478bf
8 changed files with 176 additions and 19 deletions
  1. 10 10
      flaskbb/app.py
  2. 5 1
      flaskbb/configs/default.py
  3. 4 0
      flaskbb/extensions.py
  4. 5 5
      flaskbb/forum/forms.py
  5. 142 0
      flaskbb/utils/search.py
  6. 8 1
      manage.py
  7. 1 1
      requirements.txt
  8. 1 1
      setup.py

+ 10 - 10
flaskbb/app.py

@@ -17,7 +17,6 @@ from sqlalchemy import event
 from sqlalchemy.engine import Engine
 from sqlalchemy.engine import Engine
 from flask import Flask, request
 from flask import Flask, request
 from flask_login import current_user
 from flask_login import current_user
-from flask_whooshalchemy import whoosh_index
 
 
 # views
 # views
 from flaskbb.user.views import user
 from flaskbb.user.views import user
@@ -27,11 +26,10 @@ from flaskbb.management.views import management
 from flaskbb.forum.views import forum
 from flaskbb.forum.views import forum
 # models
 # models
 from flaskbb.user.models import User, Guest
 from flaskbb.user.models import User, Guest
-from flaskbb.forum.models import Post, Topic, Category, Forum
 # extensions
 # extensions
 from flaskbb.extensions import (db, login_manager, mail, cache, redis_store,
 from flaskbb.extensions import (db, login_manager, mail, cache, redis_store,
                                 debugtoolbar, migrate, themes, plugin_manager,
                                 debugtoolbar, migrate, themes, plugin_manager,
-                                babel, csrf, allows, limiter, celery)
+                                babel, csrf, allows, limiter, celery, whooshee)
 # various helpers
 # various helpers
 from flaskbb.utils.helpers import (time_utcnow, format_date, time_since,
 from flaskbb.utils.helpers import (time_utcnow, format_date, time_since,
                                    crop_title, is_online, mark_online,
                                    crop_title, is_online, mark_online,
@@ -44,6 +42,9 @@ from flaskbb.utils.requirements import (IsAdmin, IsAtleastModerator,
                                         TplCanModerate, TplCanDeletePost,
                                         TplCanModerate, TplCanDeletePost,
                                         TplCanDeleteTopic, TplCanEditPost,
                                         TplCanDeleteTopic, TplCanEditPost,
                                         TplCanPostTopic, TplCanPostReply)
                                         TplCanPostTopic, TplCanPostReply)
+# whooshees
+from flaskbb.utils.search import (PostWhoosheer, TopicWhoosheer,
+                                  ForumWhoosheer, UserWhoosheer)
 # app specific configurations
 # app specific configurations
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
 
 
@@ -137,13 +138,12 @@ def configure_extensions(app):
     # Flask-Limiter
     # Flask-Limiter
     limiter.init_app(app)
     limiter.init_app(app)
 
 
-    # Flask-WhooshAlchemy
-    with app.app_context():
-        whoosh_index(app, Post)
-        whoosh_index(app, Topic)
-        whoosh_index(app, Forum)
-        whoosh_index(app, Category)
-        whoosh_index(app, User)
+    # Flask-Whooshee
+    whooshee.init_app(app)
+    whooshee.register_whoosheer(PostWhoosheer)
+    whooshee.register_whoosheer(TopicWhoosheer)
+    whooshee.register_whoosheer(ForumWhoosheer)
+    whooshee.register_whoosheer(UserWhoosheer)
 
 
     # Flask-Login
     # Flask-Login
     login_manager.login_view = app.config["LOGIN_VIEW"]
     login_manager.login_view = app.config["LOGIN_VIEW"]

+ 5 - 1
flaskbb/configs/default.py

@@ -57,7 +57,11 @@ class DefaultConfig(object):
     WTF_CSRF_SECRET_KEY = "reallyhardtoguess"
     WTF_CSRF_SECRET_KEY = "reallyhardtoguess"
 
 
     # Searching
     # Searching
-    WHOOSH_BASE = os.path.join(_basedir, "whoosh_index", _VERSION_STR)
+    WHOOSHEE_DIR = os.path.join(_basedir, "whoosh_index", _VERSION_STR)
+    # How long should whooshee try to acquire write lock? (defaults to 2)
+    WHOOSHEE_WRITER_TIMEOUT = 2
+    # Minimum number of characters for the search (defaults to 3)
+    WHOOSHEE_MIN_STRING_LEN = 3
 
 
     # Auth
     # Auth
     LOGIN_VIEW = "auth.login"
     LOGIN_VIEW = "auth.login"

+ 4 - 0
flaskbb/extensions.py

@@ -11,6 +11,7 @@
 from celery import Celery
 from celery import Celery
 from flask_allows import Allows
 from flask_allows import Allows
 from flask_sqlalchemy import SQLAlchemy
 from flask_sqlalchemy import SQLAlchemy
+from flask_whooshee import Whooshee
 from flask_login import LoginManager
 from flask_login import LoginManager
 from flask_mail import Mail
 from flask_mail import Mail
 from flask_caching import Cache
 from flask_caching import Cache
@@ -32,6 +33,9 @@ allows = Allows(throws=AuthorizationRequired)
 # Database
 # Database
 db = SQLAlchemy()
 db = SQLAlchemy()
 
 
+# Whooshee (Full Text Search)
+whooshee = Whooshee()
+
 # Login
 # Login
 login_manager = LoginManager()
 login_manager = LoginManager()
 
 

+ 5 - 5
flaskbb/forum/forms.py

@@ -90,7 +90,7 @@ class UserSearchForm(Form):
 
 
     def get_results(self):
     def get_results(self):
         query = self.search_query.data
         query = self.search_query.data
-        return User.query.whoosh_search(query)
+        return User.query.whooshee_search(query)
 
 
 
 
 class SearchPageForm(Form):
 class SearchPageForm(Form):
@@ -107,10 +107,10 @@ class SearchPageForm(Form):
         # Because the DB is not yet initialized when this form is loaded,
         # Because the DB is not yet initialized when this form is loaded,
         # the query objects cannot be instantiated in the class itself
         # the query objects cannot be instantiated in the class itself
         search_actions = {
         search_actions = {
-            'post': Post.query.whoosh_search,
-            'topic': Topic.query.whoosh_search,
-            'forum': Forum.query.whoosh_search,
-            'user': User.query.whoosh_search
+            'post': Post.query.whooshee_search,
+            'topic': Topic.query.whooshee_search,
+            'forum': Forum.query.whooshee_search,
+            'user': User.query.whooshee_search
         }
         }
 
 
         query = self.search_query.data
         query = self.search_query.data

+ 142 - 0
flaskbb/utils/search.py

@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.utils.search
+    ~~~~~~~~~~~~~~~~~~~~
+
+    This module contains all the whoosheers for FlaskBB's
+    full text search.
+
+    :copyright: (c) 2016 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import whoosh
+from flask_whooshee import AbstractWhoosheer
+
+from flaskbb.forum.models import Forum, Topic, Post
+from flaskbb.user.models import User
+
+
+class PostWhoosheer(AbstractWhoosheer):
+    models = [Post]
+
+    schema = whoosh.fields.Schema(
+        post_id=whoosh.fields.NUMERIC(stored=True, unique=True),
+        username=whoosh.fields.TEXT(),
+        modified_by=whoosh.fields.TEXT(),
+        content=whoosh.fields.TEXT()
+    )
+
+    @classmethod
+    def update_post(cls, writer, post):
+        writer.update_document(
+            post_id=post.id,
+            username=post.username,
+            modified_by=post.modified_by,
+            content=post.content
+        )
+
+    @classmethod
+    def insert_post(cls, writer, post):
+        writer.add_document(
+            post_id=post.id,
+            username=post.username,
+            modified_by=post.modified_by,
+            content=post.content
+        )
+
+    @classmethod
+    def delete_post(cls, writer, post):
+        writer.delete_by_term('post_id', post.id)
+
+
+class TopicWhoosheer(AbstractWhoosheer):
+    models = [Topic]
+
+    schema = whoosh.fields.Schema(
+        topic_id=whoosh.fields.NUMERIC(stored=True, unique=True),
+        title=whoosh.fields.TEXT(),
+        username=whoosh.fields.TEXT(),
+        content=whoosh.fields.TEXT()
+    )
+
+    @classmethod
+    def update_topic(cls, writer, topic):
+        writer.update_document(
+            topic_id=topic.id,
+            title=topic.title,
+            username=topic.username,
+            content=topic.first_post.content
+        )
+
+    @classmethod
+    def insert_topic(cls, writer, topic):
+        writer.add_document(
+            topic_id=topic.id,
+            title=topic.title,
+            username=topic.username,
+            content=topic.first_post.content
+        )
+
+    @classmethod
+    def delete_topic(cls, writer, topic):
+        writer.delete_by_term('topic_id', topic.id)
+
+
+class ForumWhoosheer(AbstractWhoosheer):
+    models = [Forum]
+
+    schema = whoosh.fields.Schema(
+        forum_id=whoosh.fields.NUMERIC(stored=True, unique=True),
+        title=whoosh.fields.TEXT(),
+        description=whoosh.fields.TEXT()
+    )
+
+    @classmethod
+    def update_forum(cls, writer, forum):
+        writer.update_document(
+            forum_id=forum.id,
+            title=forum.title,
+            description=forum.description
+        )
+
+    @classmethod
+    def insert_forum(cls, writer, forum):
+        writer.add_document(
+            forum_id=forum.id,
+            title=forum.title,
+            description=forum.description
+        )
+
+    @classmethod
+    def delete_forum(cls, writer, forum):
+        writer.delete_by_term('forum_id', forum.id)
+
+
+class UserWhoosheer(AbstractWhoosheer):
+    models = [User]
+
+    schema = whoosh.fields.Schema(
+        user_id=whoosh.fields.NUMERIC(stored=True, unique=True),
+        username=whoosh.fields.TEXT(),
+        email=whoosh.fields.TEXT()
+    )
+
+    @classmethod
+    def update_user(cls, writer, user):
+        writer.update_document(
+            user_id=user.id,
+            username=user.username,
+            email=user.email
+        )
+
+    @classmethod
+    def insert_user(cls, writer, user):
+        writer.add_document(
+            user_id=user.id,
+            username=user.username,
+            email=user.email
+        )
+
+    @classmethod
+    def delete_user(cls, writer, user):
+        writer.delete_by_term('user_id', user.id)

+ 8 - 1
manage.py

@@ -31,7 +31,7 @@ from flask_script import (Manager, Shell, Server, prompt, prompt_pass,
 from flask_migrate import MigrateCommand, upgrade
 from flask_migrate import MigrateCommand, upgrade
 
 
 from flaskbb import create_app
 from flaskbb import create_app
-from flaskbb.extensions import db, plugin_manager
+from flaskbb.extensions import db, plugin_manager, whooshee
 from flaskbb.utils.populate import (create_test_data, create_welcome_forum,
 from flaskbb.utils.populate import (create_test_data, create_welcome_forum,
                                     create_admin_user, create_default_groups,
                                     create_admin_user, create_default_groups,
                                     create_default_settings, insert_mass_data,
                                     create_default_settings, insert_mass_data,
@@ -94,6 +94,13 @@ def populate(dropdb=False, createdb=False):
     create_test_data()
     create_test_data()
 
 
 
 
+@manager.command
+def reindex():
+    """Reindexes the search index."""
+    print("Reindexing search index...")
+    whooshee.reindex()
+
+
 @manager.option('-u', '--username', dest='username')
 @manager.option('-u', '--username', dest='username')
 @manager.option('-p', '--password', dest='password')
 @manager.option('-p', '--password', dest='password')
 @manager.option('-e', '--email', dest='email')
 @manager.option('-e', '--email', dest='email')

+ 1 - 1
requirements.txt

@@ -22,7 +22,7 @@ Flask-Redis==0.1.0
 Flask-Script==2.0.5
 Flask-Script==2.0.5
 Flask-SQLAlchemy==2.1
 Flask-SQLAlchemy==2.1
 Flask-Themes2==0.1.4
 Flask-Themes2==0.1.4
-Flask-WhooshAlchemy==0.56
+flask-whooshee==0.2.3
 Flask-WTF==0.12
 Flask-WTF==0.12
 itsdangerous==0.24
 itsdangerous==0.24
 Jinja2==2.8
 Jinja2==2.8

+ 1 - 1
setup.py

@@ -84,7 +84,7 @@ setup(
         'Flask-Script',
         'Flask-Script',
         'Flask-SQLAlchemy',
         'Flask-SQLAlchemy',
         'Flask-Themes2',
         'Flask-Themes2',
-        'Flask-WhooshAlchemy',
+        'flask-whooshee',
         'Flask-WTF',
         'Flask-WTF',
         'itsdangerous',
         'itsdangerous',
         'Jinja2',
         'Jinja2',