Просмотр исходного кода

squash commits
initial work on flask-whooshalchemy search functionality

more search work

functional search on the admin/users page

remove not functional old search

added optional length requirement (if entered, length has to be >2 <51)

Casper Van Gheluwe 11 лет назад
Родитель
Сommit
3b17a8ac7f

+ 2 - 0
.gitignore

@@ -18,6 +18,7 @@
 *.log
 *.sql
 *.sqlite
+whoosh_index
 
 # OS generated files #
 ######################
@@ -40,6 +41,7 @@ __pycache__
 *.sublime-workspace
 *.sublime-project
 *.egg-info
+*.iml
 flaskbb/configs/production.py
 flaskbb/configs/development.py
 

+ 11 - 4
flaskbb/admin/views.py

@@ -16,6 +16,7 @@ from flask import (Blueprint, current_app, request, redirect, url_for, flash,
 from flask.ext.login import current_user
 
 from flaskbb import __version__ as flaskbb_version
+from flaskbb.forum.forms import SearchForm
 from flaskbb.utils.helpers import render_template
 from flaskbb.utils.decorators import admin_required
 from flaskbb.extensions import db
@@ -45,15 +46,21 @@ def overview():
                            post_count=post_count)
 
 
-@admin.route("/users")
+@admin.route("/users", methods=['GET', 'POST'])
 @admin_required
 def users():
     page = request.args.get("page", 1, type=int)
+    search_form = SearchForm(search_types=['user'])
+
+    if search_form.validate():
+        users = search_form.get_results()['user'].paginate(page, current_app.config['USERS_PER_PAGE'], False)
+        return render_template("admin/users.html", users=users, search_form=search_form)
+    else:
+        users = User.query. \
+            paginate(page, current_app.config['USERS_PER_PAGE'], False)
+        return render_template("admin/users.html", users=users, search_form=search_form)
 
-    users = User.query.\
-        paginate(page, current_app.config['USERS_PER_PAGE'], False)
 
-    return render_template("admin/users.html", users=users)
 
 
 @admin.route("/groups")

+ 10 - 0
flaskbb/app.py

@@ -24,9 +24,11 @@ from flaskbb.auth.views import auth
 from flaskbb.admin.views import admin
 # Import the forum blueprint
 from flaskbb.forum.views import forum
+from flaskbb.forum.models import Post, Topic, Category, Forum
 # extenesions
 from flaskbb.extensions import db, login_manager, mail, cache, redis, \
     debugtoolbar, migrate, themes
+from flask.ext.whooshalchemy import whoosh_index
 # various helpers
 from flaskbb.utils.helpers import format_date, time_since, crop_title, \
     is_online, render_markup, mark_online, forum_is_unread, topic_is_unread, \
@@ -94,6 +96,14 @@ def configure_extensions(app):
     # Flask-And-Redis
     redis.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-Login
     login_manager.login_view = app.config["LOGIN_VIEW"]
     login_manager.refresh_view = app.config["REAUTH_VIEW"]

+ 1 - 1
flaskbb/configs/default.py

@@ -91,7 +91,7 @@ class DefaultConfig(object):
     TITLE_LENGTH = 15
 
     # This is really handy if you do not have an redis instance like on windows
-    REDIS_ENABLED = True
+    REDIS_ENABLED = False
     REDIS_HOST = 'localhost'
     REDIS_PORT = 6379
     REDIS_DB = 0

+ 34 - 3
flaskbb/forum/forms.py

@@ -9,10 +9,12 @@
     :license: BSD, see LICENSE for more details.
 """
 from flask.ext.wtf import Form
-from wtforms import TextAreaField, TextField
-from wtforms.validators import Required
+import flask.ext.whooshalchemy
+from wtforms import TextAreaField, TextField, BooleanField, FormField, SelectMultipleField
+from wtforms.validators import Required, Optional, Length
 
-from flaskbb.forum.models import Topic, Post, Report
+from flaskbb.forum.models import Topic, Post, Report, Forum, Category
+from flaskbb.user.models import User
 
 
 class QuickreplyForm(Form):
@@ -54,3 +56,32 @@ class ReportForm(Form):
     def save(self, user, post):
         report = Report(**self.data)
         return report.save(user, post)
+
+
+class SearchForm(Form):
+
+    def __init__(self, search_types=list()):
+        super(SearchForm, self).__init__()
+        self.search_types = search_types
+
+    search_query = TextField("Search", validators=[Optional(), Length(min=3, max=50)])
+
+    def get_types(self):
+        return self.search_types
+
+    def get_results(self):
+        results = {}
+        types = self.get_types()
+        query = self.search_query.data
+        for type in types:
+            if type == 'user':
+                results['user'] = User.query.whoosh_search(query)
+            elif type == 'post':
+                results['post'] = Post.query.whoosh_search(query)
+            elif type == 'topic':
+                results['topic'] = Topic.query.whoosh_search(query)
+            elif type == 'forum':
+                results['forum'] = Forum.query.whoosh_search(query)
+            elif type == 'category':
+                results['category'] = Category.query.whoosh_search(query)
+        return results

+ 5 - 1
flaskbb/forum/models.py

@@ -134,6 +134,7 @@ class Report(db.Model):
 
 class Post(db.Model):
     __tablename__ = "posts"
+    __searchable__ = ['content', 'username']
 
     id = db.Column(db.Integer, primary_key=True)
     topic_id = db.Column(db.Integer,
@@ -234,6 +235,7 @@ class Post(db.Model):
 
 class Topic(db.Model):
     __tablename__ = "topics"
+    __searchable__ = ['title', 'username']
 
     query_class = TopicQuery
 
@@ -526,6 +528,7 @@ class Topic(db.Model):
 
 class Forum(db.Model):
     __tablename__ = "forums"
+    __searchable__ = ['title', 'description']
 
     id = db.Column(db.Integer, primary_key=True)
     category_id = db.Column(db.Integer, db.ForeignKey("categories.id"),
@@ -640,6 +643,7 @@ class Forum(db.Model):
 
 class Category(db.Model):
     __tablename__ = "categories"
+    __searchable__ = ['title', 'description']
 
     id = db.Column(db.Integer, primary_key=True)
     title = db.Column(db.String(63), nullable=False)
@@ -688,4 +692,4 @@ class Category(db.Model):
         # and finally delete the category itself
         db.session.delete(self)
         db.session.commit()
-        return self
+        return self

+ 2 - 2
flaskbb/forum/views.py

@@ -25,7 +25,7 @@ from flaskbb.utils.permissions import (can_post_reply, can_post_topic,
 from flaskbb.forum.models import (Category, Forum, Topic, Post, ForumsRead,
                                   TopicsRead)
 from flaskbb.forum.forms import (QuickreplyForm, ReplyForm, NewTopicForm,
-                                 ReportForm)
+                                 ReportForm, SearchForm)
 from flaskbb.utils.helpers import get_forums
 from flaskbb.user.models import User
 
@@ -500,4 +500,4 @@ def untrack_topic(topic_id, slug=None):
     topic = Topic.query.filter_by(id=topic_id).first_or_404()
     current_user.untrack_topic(topic)
     current_user.save()
-    return redirect(topic.url)
+    return redirect(topic.url)

+ 27 - 10
flaskbb/templates/admin/users.html

@@ -1,6 +1,7 @@
 {% extends theme("admin/admin_layout.html") %}
 {% block admin_content %}
 {% from theme('macros.html') import render_pagination %}
+{% from theme("macros.html") import render_field, inline_field %}
 
 <legend>Manage Users | <a href="{{ url_for('admin.add_user') }}">Add User</a></legend>
 
@@ -8,6 +9,14 @@
     {{ render_pagination(users, url_for('admin.users')) }}
 </div>
 
+<div style="padding-bottom: 10px">
+    <form class="form" role="form" method="post">
+        {{ search_form.hidden_tag() }}
+        {{ inline_field(search_form.search_query, div_class="col-sm-12", rows=12) }}
+        <button type="submit" class="btn btn-primary">Search</button>
+    </form>
+</div>
+
 <table class="table table-bordered">
     <thead>
         <tr>
@@ -20,19 +29,27 @@
         </tr>
     </thead>
     <tbody>
-        {% for user in users.items %}
+        {% if not users.items %}
         <tr>
-            <td>{{ user.id }}</td>
-            <td><a href="{{ url_for('user.profile', username=user.username) }}">{{ user.username }}</a></td>
-            <td>{{ user.post_count }}</td>
-            <td>{{ user.date_joined|format_date('%b %d %Y') }}</td>
-            <td>{{ user.primary_group.name }}</td>
-            <td>
-                <a href="{{ url_for('admin.edit_user', user_id = user.id) }}">Edit</a> |
-                <a href="{{ url_for('admin.delete_user', user_id = user.id) }}">Delete</a>
+            <td colspan="6">
+                No users found matching your search query
             </td>
         </tr>
-        {% endfor %}
+        {% else %}
+            {% for user in users.items %}
+            <tr>
+                <td>{{ user.id }}</td>
+                <td><a href="{{ url_for('user.profile', username=user.username) }}">{{ user.username }}</a></td>
+                <td>{{ user.post_count }}</td>
+                <td>{{ user.date_joined|format_date('%b %d %Y') }}</td>
+                <td>{{ user.primary_group.name }}</td>
+                <td>
+                    <a href="{{ url_for('admin.edit_user', user_id = user.id) }}">Edit</a> |
+                    <a href="{{ url_for('admin.delete_user', user_id = user.id) }}">Delete</a>
+                </td>
+            </tr>
+            {% endfor %}
+        {% endif %}
     </tbody>
 </table>
 {% endblock %}

+ 1 - 0
flaskbb/user/models.py

@@ -72,6 +72,7 @@ class Group(db.Model):
 
 class User(db.Model, UserMixin):
     __tablename__ = "users"
+    __searchable__ = ['username', 'email']
 
     id = db.Column(db.Integer, primary_key=True)
     username = db.Column(db.String(15), unique=True, nullable=False)

+ 1 - 0
setup.py

@@ -58,6 +58,7 @@ setup(
         'itsdangerous==0.23',
         'postmarkup==1.2.0',
         'wsgiref==0.1.2',
+        'Flask-WhooshAlchemy==0.55'
     ],
     classifiers=[
         'Development Status :: 4 - Beta',