Browse Source

Implemented permissions.

sh4nks 11 years ago
parent
commit
080fefce06

+ 19 - 5
flaskbb/admin/views.py

@@ -1,11 +1,25 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-from flask import Blueprint
-
+from flask import Blueprint, render_template
+from flaskbb.decorators import admin_required
 
 
 admin = Blueprint("admin", __name__)
 admin = Blueprint("admin", __name__)
 
 
 @admin.route("/")
 @admin.route("/")
-def admin_panel():
-    return "Admin Panel"
+@admin_required
+def overview():
+    return render_template("admin/overview.html")
+
+@admin.route("/users")
+@admin_required
+def manage_users():
+    pass
+
+@admin.route("/posts")
+@admin_required
+def manage_posts():
+    pass
 
 
-#TODO: Everything
+@admin.route("/pages")
+@admin_required
+def manage_pages():
+    pass

+ 56 - 3
flaskbb/app.py

@@ -17,7 +17,7 @@ from flask_debugtoolbar import DebugToolbarExtension
 
 
 # Import the user blueprint
 # Import the user blueprint
 from flaskbb.user.views import user
 from flaskbb.user.views import user
-from flaskbb.user.models import User
+from flaskbb.user.models import User, Guest
 # Import the auth blueprint
 # Import the auth blueprint
 from flaskbb.auth.views import auth
 from flaskbb.auth.views import auth
 # Import the admin blueprint
 # Import the admin blueprint
@@ -29,7 +29,7 @@ from flaskbb.forum.views import forum
 from flaskbb.forum.models import *
 from flaskbb.forum.models import *
 
 
 from flaskbb.extensions import db, login_manager, mail, cache #toolbar
 from flaskbb.extensions import db, login_manager, mail, cache #toolbar
-from flaskbb.utils import time_delta_format
+from flaskbb.helpers import time_delta_format, last_seen
 
 
 
 
 DEFAULT_BLUEPRINTS = (
 DEFAULT_BLUEPRINTS = (
@@ -98,6 +98,7 @@ def configure_extensions(app):
     # Flask-Login
     # Flask-Login
     login_manager.login_view = app.config["LOGIN_VIEW"]
     login_manager.login_view = app.config["LOGIN_VIEW"]
     login_manager.refresh_view = app.config["REAUTH_VIEW"]
     login_manager.refresh_view = app.config["REAUTH_VIEW"]
+    login_manager.anonymous_user = Guest
 
 
     @login_manager.user_loader
     @login_manager.user_loader
     def load_user(id):
     def load_user(id):
@@ -106,7 +107,7 @@ def configure_extensions(app):
         """
         """
         return User.query.get(id)
         return User.query.get(id)
 
 
-    login_manager.setup_app(app)
+    login_manager.init_app(app)
 
 
 
 
 def configure_blueprints(app, blueprints):
 def configure_blueprints(app, blueprints):
@@ -134,6 +135,53 @@ def configure_template_filters(app):
     def time_since(value):
     def time_since(value):
         return time_delta_format(value)
         return time_delta_format(value)
 
 
+    @app.template_filter()
+    def is_online(user):
+        if user.lastseen >= last_seen():
+            return True
+        return False
+
+    @app.template_filter()
+    def is_current_user(user, post):
+        """
+        Check if the post is written by the user
+        """
+        return post.user_id == user.id
+
+    @app.template_filter()
+    def edit_post(user, post):
+        """
+        Check if the post can be edited by the user
+        """
+        if not user.is_authenticated():
+            return False
+        if user.permissions['super_mod'] or user.permissions['admin']:
+            return True
+        if post.user_id == user.id and user.permissions['editpost']:
+            return True
+        return False
+
+    @app.template_filter()
+    def delete_post(user, post):
+        """
+        Check if the post can be edited by the user
+        """
+        if not user.is_authenticated():
+            return False
+        if user.permissions['super_mod'] or user.permissions['admin']:
+            return True
+        if post.user_id == user.id and user.permissions['deletepost']:
+            return True
+        return False
+
+    @app.template_filter()
+    def post_reply(user):
+        if user.permissions['super_mod'] or user.permissions['admin']:
+            return True
+        if user.permissions['postreply']:
+            return True
+        return False
+
 
 
 def configure_before_handlers(app):
 def configure_before_handlers(app):
     """
     """
@@ -150,6 +198,11 @@ def configure_before_handlers(app):
             db.session.add(current_user)
             db.session.add(current_user)
             db.session.commit()
             db.session.commit()
 
 
+    @app.before_request
+    def get_user_permissions():
+        current_user.permissions = current_user.get_permissions()
+        current_user.moderate_all = current_user.permissions['admin'] or current_user.permissions['super_mod']
+
 
 
 def configure_errorhandlers(app):
 def configure_errorhandlers(app):
     """
     """

+ 4 - 1
flaskbb/auth/forms.py

@@ -8,6 +8,8 @@
     :copyright: (c) 2013 by the FlaskBB Team.
     :copyright: (c) 2013 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
+from datetime import datetime
+
 from flask.ext.wtf import Form
 from flask.ext.wtf import Form
 from wtforms import TextField, PasswordField, BooleanField, HiddenField
 from wtforms import TextField, PasswordField, BooleanField, HiddenField
 from wtforms.validators import Required, Email, EqualTo, regexp, ValidationError
 from wtforms.validators import Required, Email, EqualTo, regexp, ValidationError
@@ -60,7 +62,8 @@ class RegisterForm(Form):
     def save(self):
     def save(self):
         user = User(username=self.username.data,
         user = User(username=self.username.data,
                     email=self.email.data,
                     email=self.email.data,
-                    password=self.password.data)
+                    password=self.password.data,
+                    date_joined=datetime.utcnow())
         return user.save()
         return user.save()
 
 
 
 

+ 2 - 0
flaskbb/configs/base.py

@@ -63,3 +63,5 @@ class BaseConfig(object):
     POSTS_PER_PAGE = 10
     POSTS_PER_PAGE = 10
     TOPICS_PER_PAGE = 10
     TOPICS_PER_PAGE = 10
     USERS_PER_PAGE = 10
     USERS_PER_PAGE = 10
+
+    LAST_SEEN = 15

+ 4 - 4
flaskbb/decorators.py

@@ -11,7 +11,7 @@
 from threading import Thread
 from threading import Thread
 from functools import wraps
 from functools import wraps
 
 
-from flask import url_for, redirect
+from flask import abort
 from flask.ext.login import current_user
 from flask.ext.login import current_user
 
 
 
 
@@ -29,8 +29,8 @@ def admin_required(f):
     @wraps(f)
     @wraps(f)
     def decorated(*args, **kwargs):
     def decorated(*args, **kwargs):
         if current_user.is_anonymous():
         if current_user.is_anonymous():
-            return redirect(url_for("frontend.index"))
-        if not current_user.is_admin():
-            return redirect(url_for("frontend.index"))
+            abort(403)
+        if not current_user.permissions['admin']:
+            abort(403)
         return f(*args, **kwargs)
         return f(*args, **kwargs)
     return decorated
     return decorated

+ 13 - 2
flaskbb/forum/models.py

@@ -11,7 +11,7 @@
 from datetime import datetime
 from datetime import datetime
 
 
 from flaskbb.extensions import db
 from flaskbb.extensions import db
-
+from flaskbb.helpers import DenormalizedText
 
 
 class Post(db.Model):
 class Post(db.Model):
     __tablename__ = "posts"
     __tablename__ = "posts"
@@ -142,7 +142,6 @@ class Topic(db.Model):
         return self
         return self
 
 
     def delete(self, users=None):
     def delete(self, users=None):
-        # This will delete the whole topic
         topic = Topic.query.filter_by(forum_id=self.forum_id).\
         topic = Topic.query.filter_by(forum_id=self.forum_id).\
             order_by(Topic.last_post_id.desc())
             order_by(Topic.last_post_id.desc())
 
 
@@ -191,6 +190,18 @@ class Forum(db.Model):
     # One-to-many
     # One-to-many
     topics = db.relationship("Topic", backref="forum", lazy="joined")
     topics = db.relationship("Topic", backref="forum", lazy="joined")
 
 
+    moderators = db.Column(DenormalizedText)
+
+    def is_moderator(self, user_id):
+        if user_id in self.moderators:
+            return True
+        return False
+
+    def add_moderator(self, user_id):
+        self.moderators.add(user_id)
+
+    def remove_moderator(self, user_id):
+        self.moderators.remove(user_id)
 
 
 
 
 class Category(db.Model):
 class Category(db.Model):

+ 34 - 12
flaskbb/forum/views.py

@@ -9,13 +9,14 @@
     :copyright: (c) 2013 by the FlaskBB Team.
     :copyright: (c) 2013 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
-from datetime import datetime
+import datetime
 import math
 import math
 
 
 from flask import (Blueprint, render_template, redirect, url_for, current_app,
 from flask import (Blueprint, render_template, redirect, url_for, current_app,
-                   request)
+                   request, flash)
 from flask.ext.login import login_required, current_user
 from flask.ext.login import login_required, current_user
 
 
+from flaskbb.helpers import last_seen
 from flaskbb.forum.models import Category, Forum, Topic, Post
 from flaskbb.forum.models import Category, Forum, Topic, Post
 from flaskbb.forum.forms import QuickreplyForm, ReplyForm, NewTopicForm
 from flaskbb.forum.forms import QuickreplyForm, ReplyForm, NewTopicForm
 from flaskbb.user.models import User
 from flaskbb.user.models import User
@@ -34,11 +35,14 @@ def index():
     post_count = Post.query.count()
     post_count = Post.query.count()
     newest_user = User.query.order_by(User.id.desc()).first()
     newest_user = User.query.order_by(User.id.desc()).first()
 
 
+    online_users = User.query.filter(User.lastseen >= last_seen())
+
     return render_template("forum/index.html", categories=categories,
     return render_template("forum/index.html", categories=categories,
                            stats={'user_count': user_count,
                            stats={'user_count': user_count,
                                   'topic_count': topic_count,
                                   'topic_count': topic_count,
                                   'post_count': post_count,
                                   'post_count': post_count,
-                                  'newest_user': newest_user.username})
+                                  'newest_user': newest_user.username,
+                                  'online_users': online_users})
 
 
 
 
 @forum.route("/category/<int:category_id>")
 @forum.route("/category/<int:category_id>")
@@ -72,14 +76,16 @@ def view_topic(topic_id):
     topic.views += 1
     topic.views += 1
     topic.save()
     topic.save()
 
 
-    form = QuickreplyForm()
-    if form.validate_on_submit():
-        post = form.save(current_user, topic)
-        return view_post(post.id)
+    form = None
+    if current_user.permissions['postreply'] or current_user.can_moderate:
+        form = QuickreplyForm()
+        if form.validate_on_submit():
+            post = form.save(current_user, topic)
+            return view_post(post.id)
 
 
     return render_template("forum/topic.html", topic=topic, posts=posts,
     return render_template("forum/topic.html", topic=topic, posts=posts,
                            per_page=current_app.config['POSTS_PER_PAGE'],
                            per_page=current_app.config['POSTS_PER_PAGE'],
-                           form=form)
+                           last_seen=last_seen(), form=form)
 
 
 
 
 @forum.route("/post/<int:post_id>")
 @forum.route("/post/<int:post_id>")
@@ -99,14 +105,18 @@ def view_post(post_id):
 @forum.route("/forum/<int:forum_id>/topic/new", methods=["POST", "GET"])
 @forum.route("/forum/<int:forum_id>/topic/new", methods=["POST", "GET"])
 @login_required
 @login_required
 def new_topic(forum_id):
 def new_topic(forum_id):
-    form = NewTopicForm()
     forum = Forum.query.filter_by(id=forum_id).first()
     forum = Forum.query.filter_by(id=forum_id).first()
 
 
+    if not (current_user.permissions['posttopic'] or current_user.can_moderate):
+        flash("You do not have the permissions to create a new topic.")
+        return redirect(url_for('forum.view_forum', forum_id=forum.id))
+
+    form = NewTopicForm()
     if form.validate_on_submit():
     if form.validate_on_submit():
         topic = form.save(current_user, forum)
         topic = form.save(current_user, forum)
 
 
         # redirect to the new topic
         # redirect to the new topic
-        return redirect(url_for('forum.view_topic', topic=topic.id))
+        return redirect(url_for('forum.view_topic', topic_id=topic.id))
     return render_template("forum/new_topic.html", forum=forum, form=form)
     return render_template("forum/new_topic.html", forum=forum, form=form)
 
 
 
 
@@ -114,6 +124,10 @@ def new_topic(forum_id):
 @login_required
 @login_required
 def delete_topic(topic_id):
 def delete_topic(topic_id):
     topic = Topic.query.filter_by(id=topic_id).first()
     topic = Topic.query.filter_by(id=topic_id).first()
+    if not (current_user.permissions['deletetopic'] or current_user.can_moderate):
+        flash("You do not have the permissions to delete the topic")
+        return redirect(url_for("forum.view_forum", forum=topic.forum_id))
+
     involved_users = User.query.filter(Post.topic_id == topic.id,
     involved_users = User.query.filter(Post.topic_id == topic.id,
                                        User.id == Post.user_id).all()
                                        User.id == Post.user_id).all()
     topic.delete(users=involved_users)
     topic.delete(users=involved_users)
@@ -123,9 +137,13 @@ def delete_topic(topic_id):
 @forum.route("/topic/<int:topic_id>/post/new", methods=["POST", "GET"])
 @forum.route("/topic/<int:topic_id>/post/new", methods=["POST", "GET"])
 @login_required
 @login_required
 def new_post(topic_id):
 def new_post(topic_id):
-    form = ReplyForm()
     topic = Topic.query.filter_by(id=topic_id).first()
     topic = Topic.query.filter_by(id=topic_id).first()
 
 
+    if not (current_user.permissions['postreply'] or current_user.can_moderate):
+        flash("You do not have the permissions to delete the topic")
+        return redirect(url_for("forum.view_forum", forum=topic.forum_id))
+
+    form = ReplyForm()
     if form.validate_on_submit():
     if form.validate_on_submit():
         post = form.save(current_user, topic)
         post = form.save(current_user, topic)
         return view_post(post.id)
         return view_post(post.id)
@@ -141,7 +159,7 @@ def edit_post(post_id):
     form = ReplyForm(obj=post)
     form = ReplyForm(obj=post)
     if form.validate_on_submit():
     if form.validate_on_submit():
         form.populate_obj(post)
         form.populate_obj(post)
-        post.date_modified = datetime.utcnow()
+        post.date_modified = datetime.datetime.utcnow()
         post.save()
         post.save()
         return redirect(url_for('forum.view_topic', topic=post.topic.id))
         return redirect(url_for('forum.view_topic', topic=post.topic.id))
     else:
     else:
@@ -165,6 +183,10 @@ def delete_post(post_id):
     return redirect(url_for('forum.view_topic', topic=topic_id))
     return redirect(url_for('forum.view_topic', topic=topic_id))
 
 
 
 
+@forum.route("/who_is_online")
+def who_is_online():
+    pass
+
 @forum.route("/memberlist")
 @forum.route("/memberlist")
 def memberlist():
 def memberlist():
     page = request.args.get('page', 1, type=int)
     page = request.args.get('page', 1, type=int)

+ 48 - 3
flaskbb/utils.py → flaskbb/helpers.py

@@ -9,11 +9,19 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import random
 import random
-from datetime import datetime
+import datetime
 
 
+from flask import current_app
+from sqlalchemy import types
+from sqlalchemy.ext.mutable import Mutable
 from wtforms.widgets.core import Select, HTMLString, html_params
 from wtforms.widgets.core import Select, HTMLString, html_params
 
 
 
 
+def last_seen():
+    now = datetime.datetime.utcnow()
+    diff = now - datetime.timedelta(minutes=current_app.config['LAST_SEEN'])
+    return diff
+
 def generate_random_pass(length=8):
 def generate_random_pass(length=8):
     return "".join(chr(random.randint(33, 126)) for i in range(length))
     return "".join(chr(random.randint(33, 126)) for i in range(length))
 
 
@@ -28,7 +36,7 @@ def time_delta_format(dt, default=None):
     if default is None:
     if default is None:
         default = 'just now'
         default = 'just now'
 
 
-    now = datetime.utcnow()
+    now = datetime.datetime.utcnow()
     diff = now - dt
     diff = now - dt
 
 
     periods = (
     periods = (
@@ -54,6 +62,43 @@ def time_delta_format(dt, default=None):
     return default
     return default
 
 
 
 
+class DenormalizedText(Mutable, types.TypeDecorator):
+    """
+    Stores denormalized primary keys that can be
+    accessed as a set.
+
+    :param coerce: coercion function that ensures correct
+                   type is returned
+
+    :param separator: separator character
+
+    Source: https://github.com/imwilsonxu/fbone/blob/master/fbone/user/models.py#L13-L45
+    """
+
+    impl = types.Text
+
+    def __init__(self, coerce=int, separator=" ", **kwargs):
+
+        self.coerce = coerce
+        self.separator = separator
+
+        super(DenormalizedText, self).__init__(**kwargs)
+
+    def process_bind_param(self, value, dialect):
+        if value is not None:
+            items = [str(item).strip() for item in value]
+            value = self.separator.join(item for item in items if item)
+        return value
+
+    def process_result_value(self, value, dialect):
+        if not value:
+            return set()
+        return set(self.coerce(item) for item in value.split(self.separator))
+
+    def copy_value(self, value):
+        return set(value)
+
+
 class SelectDateWidget(object):
 class SelectDateWidget(object):
     """
     """
     Renders a DateTime field with 3 selects.
     Renders a DateTime field with 3 selects.
@@ -70,7 +115,7 @@ class SelectDateWidget(object):
         '%Y': 'select_date_year'
         '%Y': 'select_date_year'
     }
     }
 
 
-    def __init__(self, years=range(1930, datetime.utcnow().year+1)):
+    def __init__(self, years=range(1930, datetime.datetime.utcnow().year+1)):
         super(SelectDateWidget, self).__init__()
         super(SelectDateWidget, self).__init__()
         self.FORMAT_CHOICES['%Y'] = [(x, str(x)) for x in years]
         self.FORMAT_CHOICES['%Y'] = [(x, str(x)) for x in years]
 
 

+ 18 - 0
flaskbb/templates/admin/admin_layout.html

@@ -0,0 +1,18 @@
+{% extends "layout.html" %}
+{% block content %}
+<div class="container">
+    This is the Admin Panel which is still a Work in Progress<br \><br \>
+    <div class="tabbable tabs-left">
+        <ul class="nav nav-tabs nav-left">
+            {%- from 'macros.html' import navlink with context-%}
+            {{ navlink('admin.overview', 'Overview') }}
+            {{ navlink('admin.manage_users', 'Manage Users') }}
+            {{ navlink('admin.manage_posts', 'Manage Posts') }}
+            {{ navlink('admin.manage_pages', 'Manage Pages') }}
+        </ul>
+        <div class="tab-content">
+            {% block admin_content %}{% endblock %}
+        </div>
+    </div>
+</div>
+{% endblock %}

+ 20 - 0
flaskbb/templates/admin/edit_page.html

@@ -0,0 +1,20 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+<form action="{{ url_for('admin.edit_page', page_id=page.pid) }}" method="post" name="edit">
+    <fieldset>
+    {%- from 'macros/wtf_macros.html' import form_field -%}
+    {{ form.hidden_tag() }}
+
+    <legend>New Page</legend>
+
+    {{ form_field(form.title) }}
+
+    {{ form_field(form.position) }}
+
+    {{ form_field(form.content, rows="20", class="span10") }}
+
+    <button type="submit" class="btn">Save!</button>
+
+    </fieldset>
+</form>
+{% endblock %}

+ 36 - 0
flaskbb/templates/admin/manage_groups.html

@@ -0,0 +1,36 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th colspan="4">Global Statistics</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr>
+                        <td><b>SomeBlocks Version</b></td>
+                        <td>someblocks-20130220-git</td>
+                        <td><b>Posts</b></td>
+                        <td>50 Posts</td>
+                    </tr>
+                    <tr>
+                        <td><b>Python Version</b></td>
+                        <td>{{ py_ver }}</td>
+                        <td><b>Comments</b></td>
+                        <td>1237 Comments</td>
+                    </tr>
+                    <tr>
+                        <td><b>Flask Version</b></td>
+                        <td>0.9</td>
+                        <td><b>User</b></td>
+                        <td>456 Users</td>
+                    </tr>
+                    <tr>
+                        <td></td>
+                        <td></td>
+                        <td><b>Group</b></td>
+                        <td>10 Groups</td>
+                    </tr>
+                </tbody>
+            </table>
+{% endblock %}

+ 21 - 0
flaskbb/templates/admin/manage_info.html

@@ -0,0 +1,21 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th>Manage Pages</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr>
+                        <td colspan="2">
+                            <b><a href="#">Page Title</a></b>
+                        </td>
+                        <td colspan="2">
+                            <i class="icon-trash"></i> <a href="#">Edit Page</a>
+                            <i class="icon-edit"></i> <a href="#">Delete Page</a>
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+{% endblock %}

+ 27 - 0
flaskbb/templates/admin/manage_pages.html

@@ -0,0 +1,27 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th>Manage Pages | <small><a href="{{ url_for('admin.new_page') }}">New Page</a><small></th>
+                    </tr>
+                </thead>
+                <tbody>
+                {% for page in pages %}
+                    <tr>
+                        <td colspan="2">
+                            {% if not page.external %}
+                            <b><a href="{{ url_for('frontend.pages', url=page.url) }}">{{ page.title }}</a></b>
+                            {% else %}
+                            <b><a href="{{ page.url }}">{{ page.title }}</a></b> <i class="icon-external-link"></i>
+                            {% endif %}
+                        </td>
+                        <td colspan="2">
+                            <i class="icon-trash"></i> <a href="{{ url_for('admin.edit_page', page_id=page.pid) }}">Edit Page</a>
+                            <i class="icon-edit"></i> <a href="{{ url_for('admin.delete_page', page_id=page.pid) }}">Delete Page</a>
+                        </td>
+                    </tr>
+                {% endfor %}
+                </tbody>
+            </table>
+{% endblock %}

+ 23 - 0
flaskbb/templates/admin/manage_posts.html

@@ -0,0 +1,23 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th>Manage Posts | <small><a href="{{ url_for('blog.new_post') }}">New Post</a><small></th>
+                    </tr>
+                </thead>
+                <tbody>
+                {% for post in posts %}
+                    <tr>
+                        <td colspan="2">
+                            <b><a href="{{ url_for('blog.post', id=post.pid) }}">{{ post.title }}</a></b>
+                        </td>
+                        <td colspan="2">
+                            <i class="icon-trash"></i> <a href="{{ url_for('blog.edit_post', id = post.pid) }}">Edit Post</a>
+                            <i class="icon-edit"></i> <a href="{{ url_for('blog.delete_post', id = post.pid) }}">Delete Post</a>
+                        </td>
+                    </tr>
+                {% endfor %}
+                </tbody>
+            </table>
+{% endblock %}

+ 23 - 0
flaskbb/templates/admin/manage_users.html

@@ -0,0 +1,23 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th>Manage Users</th>
+                    </tr>
+                </thead>
+                <tbody>
+                {% for user in users %}
+                    <tr>
+                        <td colspan="2">
+                            <b><a href="{{ url_for('users.profile', username=user.username) }}">{{ user.username }}</a></b>
+                        </td>
+                        <td colspan="2">
+                            <i class="icon-trash"></i> <a href="{{ url_for('users.editprofile', username = user.username) }}">Edit User</a>
+                            <i class="icon-edit"></i> <a href="{{ url_for('admin.delete_user', username = user.username) }}">Delete User</a>
+                        </td>
+                    </tr>
+                {% endfor %}
+                </tbody>
+            </table>
+{% endblock %}

+ 25 - 0
flaskbb/templates/admin/new_page.html

@@ -0,0 +1,25 @@
+{% extends "admin/admin_base.html" %}
+{% block admin_content %}
+<form action="{{ url_for('admin.new_page') }}" method="post" name="new">
+    <fieldset>
+    {%- from 'macros/wtf_macros.html' import form_field -%}
+
+    {{ form.hidden_tag() }}
+
+    <legend>New Page</legend>
+
+    {{ form_field(form.title) }}
+
+    {{ form_field(form.url, placeholder="e.q. about or about_us") }}
+
+    {{ form_field(form.external) }}
+
+    {{ form_field(form.position) }}
+
+    {{ form_field(form.content, rows="20", class="span10") }}
+
+
+    <button type="submit" class="btn">Submit!</button>
+    </fieldset>
+</form>
+{% endblock %}

+ 32 - 0
flaskbb/templates/admin/overview.html

@@ -0,0 +1,32 @@
+{% extends "admin/admin_layout.html" %}
+{% block admin_content %}
+
+            <table class="table table-stripped table-hover">
+                <thead>
+                    <tr class="success">
+                        <th colspan="4">Global Statistics</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr>
+                        <td><b>FlaskBB Version</b></td>
+                        <td>0.1</td>
+                        <td><b>Posts</b></td>
+                        <td>10 Posts</td>
+                    </tr>
+                    <tr>
+                        <td><b>Python Version</b></td>
+                        <td>2.7.5</td>
+                        <td><b>Comments</b></td>
+                        <td>10 Comments</td>
+                    </tr>
+                    <tr>
+                        <td><b>Flask Version</b></td>
+                        <td>0.10.1</td>
+                        <td><b>User</b></td>
+                        <td>10 Users</td>
+                    </tr>
+                </tbody>
+            </table>
+
+{% endblock %}

+ 4 - 3
flaskbb/templates/forum/category_layout.html

@@ -16,15 +16,16 @@
 
 
         {% for forum in category.forums %}
         {% for forum in category.forums %}
         <tr>
         <tr>
-            <td align="center" valign="center" width="1">INSERT IMAGE</td>
+            <td align="center" valign="center" width="1">
+                New </br> Posts
+            </td>
 
 
             <td valign="top">
             <td valign="top">
                 <strong><a href="{{ url_for('forum.view_forum', forum_id=forum.id) }}">{{ forum.title }}</a></strong>
                 <strong><a href="{{ url_for('forum.view_forum', forum_id=forum.id) }}">{{ forum.title }}</a></strong>
 
 
                 <div class="forum-description">
                 <div class="forum-description">
                     {{ forum.description }}<br />
                     {{ forum.description }}<br />
-                    <!-- Moderators: <a href="#">FlaskBB Team</a><br />
-
+                    <!--
                     <strong>Sub Forums:</strong> <a href="#" title="">Subforum 1</a>, <a href="#" title="">Subforum 2</a>
                     <strong>Sub Forums:</strong> <a href="#" title="">Subforum 1</a>, <a href="#" title="">Subforum 2</a>
                      -->
                      -->
                 </div>
                 </div>

+ 2 - 11
flaskbb/templates/forum/index.html

@@ -14,6 +14,7 @@
         <tr>
         <tr>
             <td colspan="2">
             <td colspan="2">
                 <strong>Board Statistics</strong>
                 <strong>Board Statistics</strong>
+                [<a href="{{ url_for('forum.who_is_online') }}" onclick="window.open(this.href, 'wio_window','width=500,height=500'); return false;">Who is online?</a>]
             </td>
             </td>
         </tr>
         </tr>
     </thead>
     </thead>
@@ -26,21 +27,11 @@
             </td>
             </td>
             <td>
             <td>
                 Newest registered user: <a href="{{ url_for('user.profile', username=stats['newest_user']) }}">{{ stats['newest_user'] }}</a> <br />
                 Newest registered user: <a href="{{ url_for('user.profile', username=stats['newest_user']) }}">{{ stats['newest_user'] }}</a> <br />
-                <strong>#TODO</strong> Registered users online: <strong>2</strong> <br />
+                Registered users online: <strong>{{ stats['online_users'].count() }}</strong> <br />
                 <strong>#TODO</strong> Guests online: <strong>40</strong> <br />
                 <strong>#TODO</strong> Guests online: <strong>40</strong> <br />
             </td>
             </td>
         </tr>
         </tr>
 
 
-        <tr>
-            <td colspan="2"><strong>#TODO</strong> Who is online? [<a href="show_all_online_players.html" target="_blank">Full List</a>]</td>
-        </tr>
-        <tr>
-            <td colspan="2">
-                <a href="profile.html"><span style="color: green;"><strong><em>test1</em></strong></span></a>,
-                <a href="profile.html"><span style=""><em>test2</em></span></a>
-            </td>
-        </tr>
-
     </tbody>
     </tbody>
 </table>
 </table>
 
 

+ 1 - 2
flaskbb/templates/forum/memberlist.html

@@ -9,7 +9,6 @@
     <li class="active">Memberlist</li>
     <li class="active">Memberlist</li>
 </ul>
 </ul>
 
 
-
   <div class="pull-left" style="padding-bottom: 10px">
   <div class="pull-left" style="padding-bottom: 10px">
     {{ render_pagination(users, url_for('forum.memberlist')) }}
     {{ render_pagination(users, url_for('forum.memberlist')) }}
   </div><!-- /.col-lg-6 -->
   </div><!-- /.col-lg-6 -->
@@ -39,7 +38,7 @@
             <td><a href="{{ url_for('user.profile', username=user.username) }}">{{ user.username }}</a></td>
             <td><a href="{{ url_for('user.profile', username=user.username) }}">{{ user.username }}</a></td>
             <td>{{ user.post_count }}</td>
             <td>{{ user.post_count }}</td>
             <td>{{ user.date_joined|format_date('%b %d %Y') }}</td>
             <td>{{ user.date_joined|format_date('%b %d %Y') }}</td>
-            <td>#TODO</td>
+            <td>{{ user.primary_group.name }}</td>
         </tr>
         </tr>
         {% endfor %}
         {% endfor %}
     </tbody>
     </tbody>

+ 19 - 16
flaskbb/templates/forum/topic.html

@@ -16,14 +16,14 @@
     {{ render_pagination(posts, url_for('forum.view_topic', topic_id=topic.id)) }}
     {{ render_pagination(posts, url_for('forum.view_topic', topic_id=topic.id)) }}
 </div> <!-- end span pagination -->
 </div> <!-- end span pagination -->
 
 
-{% if current_user.is_authenticated() %}
 <div class="pull-right" style="padding-bottom: 10px">
 <div class="pull-right" style="padding-bottom: 10px">
+    {% if current_user|post_reply() %}
     <a href="{{ url_for('forum.new_post', topic_id=topic.id) }}" class="btn btn-primary">Reply</a>
     <a href="{{ url_for('forum.new_post', topic_id=topic.id) }}" class="btn btn-primary">Reply</a>
-    {% if current_user.id == topic.user_id %}
+    {% endif %}
+    {% if current_user|delete_topic(topic) %}
     <a href="{{ url_for('forum.delete_topic', topic_id=topic.id) }}" class="btn btn-primary">Delete Topic</a>
     <a href="{{ url_for('forum.delete_topic', topic_id=topic.id) }}" class="btn btn-primary">Delete Topic</a>
     {% endif %}
     {% endif %}
 </div>
 </div>
-{% endif %}
 
 
 <table class="table table-bordered">
 <table class="table table-bordered">
     <tbody>
     <tbody>
@@ -54,23 +54,25 @@
         <td>
         <td>
             <table class="table table-borderless">
             <table class="table table-borderless">
                 <tr>
                 <tr>
-
+                    {% if post.user.avatar %}
                     <td width="1">
                     <td width="1">
                         <img src="{{ post.user.avatar }}" alt="Avatar" height="100" width="100">
                         <img src="{{ post.user.avatar }}" alt="Avatar" height="100" width="100">
                     </td>
                     </td>
-
+                    {% endif %}
                     <td>
                     <td>
                         <a href="{{ url_for('user.profile', username=post.user.username) }}"><span style="color: green;"><strong><em>{{ post.user.username }}</em></strong></span></a>
                         <a href="{{ url_for('user.profile', username=post.user.username) }}"><span style="color: green;"><strong><em>{{ post.user.username }}</em></strong></span></a>
-                        <!-- TODO: Implement online status and groups -->
-                        <span class="label label-success">Online</span><br />
-                        Administrator<br />
+                        {% if post.user|is_online %}
+                        <span class="label label-success">Online</span>
+                        {% else %}
+                        <span class="label label-default">Offline</span>
+                        {% endif %}
+                        <br />
+                        {{ post.user.primary_group.name }}<br />
                     </td>
                     </td>
 
 
                     <td class="pull-right">
                     <td class="pull-right">
                         Posts: {{ post.user.post_count }}<br />
                         Posts: {{ post.user.post_count }}<br />
                         Registered since: {{ post.user.date_joined|format_date('%b %d %Y') }}<br />
                         Registered since: {{ post.user.date_joined|format_date('%b %d %Y') }}<br />
-                        <!-- TODO: Implement Karma functionality -->
-                        Karma: <a href="#">124</a>
                     </td>
                     </td>
 
 
                 </tr>
                 </tr>
@@ -94,17 +96,18 @@
         <tr>
         <tr>
             <td>
             <td>
                 <span class="pull-left">
                 <span class="pull-left">
-                    <a href="{{ url_for('pms.new_message') }}?to_user={{ post.user.username }}">PM</a> | <a href="#">Website</a>
+                    <a href="{{ url_for('pms.new_message') }}?to_user={{ post.user.username }}">PM</a>
+                    {% if post.user.website %}| <a href="{{post.user.website}}">Website</a>{% endif %}
                 </span>
                 </span>
 
 
                 <span class="pull-right">
                 <span class="pull-right">
-                    {% if current_user.is_authenticated() and current_user.id == post.user_id %}
+                    {% if current_user|edit_post(post) %}
                     <a href="{{ url_for('forum.edit_post', post_id=post.id) }}">Edit</a> |
                     <a href="{{ url_for('forum.edit_post', post_id=post.id) }}">Edit</a> |
+                    {% endif %}
+                    {% if current_user|delete_post(post) %}
                     <a href="{{ url_for('forum.delete_post', post_id=post.id) }}">Delete</a> |
                     <a href="{{ url_for('forum.delete_post', post_id=post.id) }}">Delete</a> |
                     {% endif %}
                     {% endif %}
-                    <a href="#">Quote</a> |
-                    <a href="#">Report</a> |
-                    <a href="#">+1</a>
+                    <a href="#">Quote</a>
                 </span>
                 </span>
             </td>
             </td>
         </tr>
         </tr>
@@ -113,7 +116,7 @@
     </tbody>
     </tbody>
 </table>
 </table>
 
 
-{% if current_user.is_authenticated() %}
+{% if current_user|post_reply() %}
 <form class="form" action="#" method="post">
 <form class="form" action="#" method="post">
     {{ form.hidden_tag() }}
     {{ form.hidden_tag() }}
     <div class="form-group">
     <div class="form-group">

+ 7 - 0
flaskbb/templates/layout.html

@@ -48,6 +48,13 @@
                             </button>
                             </button>
                             <ul class="dropdown-menu" role="menu">
                             <ul class="dropdown-menu" role="menu">
                                 <li><a href="{{ url_for('user.settings') }}"><span class="glyphicon glyphicon-cog"></span> Settings</a></li>
                                 <li><a href="{{ url_for('user.settings') }}"><span class="glyphicon glyphicon-cog"></span> Settings</a></li>
+
+                                {% if current_user.permissions['admin'] %}
+                                <li class="divider"></li>
+                                <li><a href="{{ url_for('admin.overview') }}"><span class="glyphicon glyphicon-cog"></span> Admin Panel</a></li>
+                                <li class="divider"></li>
+                                {% endif %}
+
                                 <li><a href="{{ url_for('auth.logout') }}"><span class="glyphicon glyphicon-share-alt"></span> Logout</a></li>
                                 <li><a href="{{ url_for('auth.logout') }}"><span class="glyphicon glyphicon-share-alt"></span> Logout</a></li>
                             </ul>
                             </ul>
                         </div>
                         </div>

+ 3 - 1
flaskbb/templates/pms/view_message.html

@@ -7,15 +7,17 @@
             <table class="table table-borderless" border="0">
             <table class="table table-borderless" border="0">
                 <tr>
                 <tr>
 
 
+                    {% if message.from_user.avatar %}
                     <td width="1">
                     <td width="1">
                         <img src="{{ message.from_user.avatar }}" alt="Avatar" height="100" width="100">
                         <img src="{{ message.from_user.avatar }}" alt="Avatar" height="100" width="100">
                     </td>
                     </td>
+                    {% endif %}
 
 
                     <td>
                     <td>
                         <a href="{{ url_for('user.profile', username=message.from_user.username) }}"><span style="color: green;"><strong><em>{{ message.from_user.username }}</em></strong></span></a>
                         <a href="{{ url_for('user.profile', username=message.from_user.username) }}"><span style="color: green;"><strong><em>{{ message.from_user.username }}</em></strong></span></a>
                         <!-- TODO: Implement online status and groups -->
                         <!-- TODO: Implement online status and groups -->
                         <span class="badge badge-success">Online</span><br />
                         <span class="badge badge-success">Online</span><br />
-                        Administrator<br />
+                        {{ message.from_user.primary_group.name }}<br />
                     </td>
                     </td>
 
 
                     <td class="pull-right">
                     <td class="pull-right">

+ 14 - 2
flaskbb/templates/user/profile.html

@@ -13,10 +13,13 @@
     </thead>
     </thead>
     <tbody>
     <tbody>
         <tr>
         <tr>
+
           <td width="200px">
           <td width="200px">
             <table class="table table-borderless">
             <table class="table table-borderless">
               <tbody>
               <tbody>
+                {% if user.avatar %}
                 <tr><td><img src="{{ user.avatar }}" alt="Avatar" height="100" width="100"> </td></tr>
                 <tr><td><img src="{{ user.avatar }}" alt="Avatar" height="100" width="100"> </td></tr>
+                {% endif %}
                 <!-- TODO: Implement online status -->
                 <!-- TODO: Implement online status -->
                 <tr><td><b></b> <span class="label label-success">Online</span></td></tr>
                 <tr><td><b></b> <span class="label label-success">Online</span></td></tr>
                 <tr><td><a href="{{ url_for('user.view_all_topics', username=user.username) }}">All Topics</a></td></tr>
                 <tr><td><a href="{{ url_for('user.view_all_topics', username=user.username) }}">All Topics</a></td></tr>
@@ -24,13 +27,21 @@
               </tbody>
               </tbody>
             </table>
             </table>
           </td>
           </td>
-          <td>{{ user.notes }}</td>
+
+          <td>
+            {% if user.notes %}
+                {{ user.notes }}
+            {% else %}
+                User has not added any notes about him.
+            {% endif %}
+          </td>
+
           <td width="250px">
           <td width="250px">
             <table class="table table-borderless">
             <table class="table table-borderless">
               <tbody>
               <tbody>
                 <tr>
                 <tr>
                   <td align="right">Group:</td>
                   <td align="right">Group:</td>
-                  <td><b>TODO: </b>Admin</td>
+                  <td>{{ user.primary_group.name }}</td>
                 </tr>
                 </tr>
                 <tr>
                 <tr>
                   <td align="right">Joined:</td>
                   <td align="right">Joined:</td>
@@ -68,6 +79,7 @@
               </tbody>
               </tbody>
             </table>
             </table>
           </td>
           </td>
+
         </tr>
         </tr>
     </tbody>
     </tbody>
 </table>
 </table>

+ 1 - 1
flaskbb/user/forms.py

@@ -16,7 +16,7 @@ from wtforms.validators import (Length, Required, Email, EqualTo, regexp,
 
 
 from flaskbb.user.models import User
 from flaskbb.user.models import User
 from flaskbb.extensions import db
 from flaskbb.extensions import db
-from flaskbb.utils import SelectDateWidget
+from flaskbb.helpers import SelectDateWidget
 
 
 IMG_RE = r'^[^/\\]\.(?:jpg|gif|png)'
 IMG_RE = r'^[^/\\]\.(?:jpg|gif|png)'
 
 

+ 189 - 4
flaskbb/user/models.py

@@ -11,15 +11,45 @@
 from datetime import datetime
 from datetime import datetime
 
 
 from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
 from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
-from itsdangerous import SignatureExpired, BadSignature
+from itsdangerous import SignatureExpired
 from werkzeug import generate_password_hash, check_password_hash
 from werkzeug import generate_password_hash, check_password_hash
 from flask import current_app
 from flask import current_app
-from flask.ext.login import UserMixin
-
-from flaskbb.extensions import db
+from flask.ext.login import UserMixin, AnonymousUserMixin
+from flaskbb.extensions import db, cache
 from flaskbb.forum.models import Post, Topic
 from flaskbb.forum.models import Post, Topic
 
 
 
 
+groups_users = db.Table('groups_users',
+        db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
+        db.Column('group_id', db.Integer(), db.ForeignKey('groups.id')))
+
+moderators = db.Table('moderators',
+        db.Column('forum_id', db.Integer(), db.ForeignKey('forums.id')),
+        db.Column('user_id', db.Integer(), db.ForeignKey('users.id')))
+
+
+class Group(db.Model):
+    __tablename__ = "groups"
+
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String, unique=True)
+    description = db.Column(db.String(80))
+
+    admin = db.Column(db.Boolean)
+    super_mod = db.Column(db.Boolean)
+    mod = db.Column(db.Boolean)
+    guest = db.Column(db.Boolean)
+    banned = db.Column(db.Boolean)
+
+    editpost = db.Column(db.Boolean)
+    deletepost = db.Column(db.Boolean)
+    deletetopic = db.Column(db.Boolean)
+    posttopic = db.Column(db.Boolean)
+    postreply = db.Column(db.Boolean)
+    viewtopic = db.Column(db.Boolean)
+    viewprofile = db.Column(db.Boolean)
+
+
 class User(db.Model, UserMixin):
 class User(db.Model, UserMixin):
     __tablename__ = "users"
     __tablename__ = "users"
 
 
@@ -43,6 +73,16 @@ class User(db.Model, UserMixin):
 
 
     post_count = db.Column(db.Integer, default=0) # Bye bye normalization
     post_count = db.Column(db.Integer, default=0) # Bye bye normalization
 
 
+    primary_group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
+
+    primary_group = db.relationship('Group', backref="user_group", uselist=False, foreign_keys=[primary_group_id])
+
+    groups = db.relationship('Group',
+                             secondary=groups_users,
+                             primaryjoin=(groups_users.c.user_id == id),
+                             backref=db.backref('users', lazy='dynamic'),
+                             lazy='dynamic')
+
     def __repr__(self):
     def __repr__(self):
         return "Username: %s" % self.username
         return "Username: %s" % self.username
 
 
@@ -130,6 +170,85 @@ class User(db.Model, UserMixin):
         return Post.query.filter(Post.user_id == self.id).\
         return Post.query.filter(Post.user_id == self.id).\
             paginate(page, current_app.config['TOPICS_PER_PAGE'], False)
             paginate(page, current_app.config['TOPICS_PER_PAGE'], False)
 
 
+    def add_to_group(self, group):
+        """
+        Adds the user to the `group` if he isn't in it.
+        """
+        if not self.in_group(group):
+            self.groups.append(group)
+            return self
+
+    def in_group(self, group):
+        """
+        Returns True if the user is in the specified group
+        """
+        return self.groups.filter(
+            groups_users.c.group_id == group.id).count() > 0
+
+    @cache.memoize(60*5)
+    def get_permissions(self, exclude=None):
+        """
+        Returns a dictionary with all the permissions the user has.
+        """
+        exclude = exclude or []
+        exclude.extend(['id', 'name', 'description'])
+
+        perms = {}
+        # Iterate over all groups
+        for group in self.groups.all():
+            for c in group.__table__.columns:
+                # try if the permission already exists in the dictionary
+                # and if the permission is true, go to the next permission
+                try:
+                    if perms[c.name]:
+                        continue
+                # if the permission doesn't exist in the dictionary
+                # add it to the dictionary
+                except KeyError:
+                    # if the permission is in the exclude list,
+                    # skip to the next permission
+                    if c.name in exclude:
+                        continue
+                    perms[c.name] = getattr(group, c.name)
+        return perms
+
+    def has_perm(self, perm):
+        """
+        Returns True if the user has the specified permission.
+        """
+        permissions = self.get_permissions()
+        if permissions['admin'] or permissions['super_mod']:
+            return True
+
+        if permissions[perm]:
+            return True
+        return False
+
+    def has_one_perm(self, perms_list):
+        """
+        Returns True if the user has one of the provided permissions.
+        """
+        for perm in perms_list:
+            if self.has_perm(perm):
+                return True
+        return False
+
+    def has_perms(self, perms_list):
+        """
+        Returns True if the user has each of the specified permissions.
+        It is basically the same as has_perm but every permission in the
+        provided list needs to be True to return True.
+        """
+        # Iterate over the list with the permissions
+        for perm in perms_list:
+            if self.has_perm(perm):
+                # After checking the permission,
+                # we can remove the perm from the list
+                perms_list.remove(perm)
+            else:
+                return False
+        return True
+
     def save(self):
     def save(self):
         db.session.add(self)
         db.session.add(self)
         db.session.commit()
         db.session.commit()
@@ -139,3 +258,69 @@ class User(db.Model, UserMixin):
         db.session.delete(self)
         db.session.delete(self)
         db.session.commit()
         db.session.commit()
         return self
         return self
+
+
+class Guest(AnonymousUserMixin):
+    @cache.memoize(60*5)
+    def get_permissions(self, exclude=None):
+        """
+        Returns a dictionary with all permissions the user has
+        """
+        exclude = exclude or []
+        exclude.extend(['id', 'name', 'description'])
+
+        perms = {}
+        # Get the Guest group
+        group = Group.query.filter_by(guest=True).first()
+        for c in group.__table__.columns:
+            # try if the permission already exists in the dictionary
+            # and if the permission is true, go to the next permission
+            try:
+                if perms[c.name]:
+                    continue
+            # if the permission doesn't exist in the dictionary
+            # add it to the dictionary
+            except KeyError:
+                # if the permission is in the exclude list,
+                # skip to the next permission
+                if c.name in exclude:
+                    continue
+                perms[c.name] = getattr(group, c.name)
+        return perms
+
+    def has_perm(self, perm):
+        """
+        Returns True if the user has the specified permission.
+        """
+        group = Group.query.filter_by(guest=True).first()
+        if getattr(group, perm, True):
+            return True
+        return False
+
+    def has_one_perm(self, perms_list):
+        """
+        Returns True if the user has one of the provided permissions.
+        """
+        group = Group.query.filter_by(guest=True).first()
+        for perm in perms_list:
+            if getattr(group, perm, True):
+                return True
+        return False
+
+    def has_perms(self, perms_list):
+        """
+        Returns True if the user has each of the specified permissions.
+        It is basically the same as has_perm but every permission in the
+        provided list needs to be True to return True.
+        """
+        # Iterate overall groups
+        group = Group.query.filter_by(guest=True).first()
+        # Iterate over the list with the permissions
+        for perm in perms_list:
+            if getattr(group, perm, True):
+                # After checking the permission,
+                # we can remove the perm from the list
+                perms_list.remove(perm)
+            else:
+                return False
+        return True

+ 108 - 1
manage.py

@@ -11,6 +11,7 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import os
 import os
+from collections import OrderedDict
 
 
 from flask import current_app
 from flask import current_app
 from flask.ext.script import Manager, Shell, Server
 from flask.ext.script import Manager, Shell, Server
@@ -19,7 +20,7 @@ from flaskbb import create_app
 from flaskbb.configs.development import DevelopmentConfig, BaseConfig
 from flaskbb.configs.development import DevelopmentConfig, BaseConfig
 from flaskbb.extensions import db
 from flaskbb.extensions import db
 
 
-from flaskbb.user.models import User
+from flaskbb.user.models import User, Group
 from flaskbb.forum.models import Post, Topic, Forum, Category
 from flaskbb.forum.models import Post, Topic, Forum, Category
 
 
 app = create_app(DevelopmentConfig)
 app = create_app(DevelopmentConfig)
@@ -58,11 +59,117 @@ def createall():
 
 
     db.create_all()
     db.create_all()
 
 
+    groups = OrderedDict((
+        ('Administrator', {
+             'description': 'The Administrator Group',
+             'admin': True,
+             'super_mod': False,
+             'mod': False,
+             'banned': False,
+             'guest': False,
+             'editpost': True,
+             'deletepost': True,
+             'deletetopic': True,
+             'posttopic': True,
+             'postreply': True,
+             'viewtopic': True,
+             'viewprofile': True
+             }),
+        ('Super Moderator', {
+             'description': 'The Super Moderator Group',
+             'admin': False,
+             'super_mod': True,
+             'mod': False,
+             'banned': False,
+             'guest': False,
+             'editpost': True,
+             'deletepost': True,
+             'deletetopic': True,
+             'posttopic': True,
+             'postreply': True,
+             'viewtopic': True,
+             'viewprofiles': True
+             }),
+        ('Moderator', {
+             'description': 'The Moderator Group',
+             'admin': False,
+             'super_mod': False,
+             'mod': True,
+             'banned': False,
+             'guest': False,
+             'editpost': True,
+             'deletepost': True,
+             'deletetopic': True,
+             'posttopic': True,
+             'postreply': True,
+             'viewtopic': True,
+             'viewprofile': True
+             }),
+        ('Member', {
+             'description': 'The Member Group',
+             'admin': False,
+             'super_mod': False,
+             'mod': False,
+             'banned': False,
+             'guest': False,
+             'editpost': True,
+             'deletepost': False,
+             'deletetopic': False,
+             'posttopic': True,
+             'postreply': True,
+             'viewtopic': True,
+             'viewprofile': True
+             }),
+        ('Banned', {
+             'description': 'The Banned Group',
+             'admin': False,
+             'super_mod': False,
+             'mod': False,
+             'banned': True,
+             'guest': False,
+             'editpost': False,
+             'deletepost': False,
+             'deletetopic': False,
+             'posttopic': False,
+             'postreply': False,
+             'viewtopic': False,
+             'viewprofile': False
+             }),
+        ('Guest', {
+             'description': 'The Guest Group',
+             'admin': False,
+             'super_mod': False,
+             'mod': False,
+             'banned': False,
+             'guest': True,
+             'editpost': False,
+             'deletepost': False,
+             'deletetopic': False,
+             'posttopic': False,
+             'postreply': False,
+             'viewtopic': False,
+             'viewprofile': False
+             })
+    ))
+
+    # create 5 groups
+    for key, value in groups.items():
+        group = Group(name=key)
+
+        for k, v in value.items():
+            setattr(group, k, v)
+
+        db.session.add(group)
+        db.session.commit()
+
     # create 5 users
     # create 5 users
+    groups = Group.query.all()
     for u in range(1, 6):
     for u in range(1, 6):
         username = "test%s" % u
         username = "test%s" % u
         email = "test%s@example.org" % u
         email = "test%s@example.org" % u
         user = User(username=username, password="test", email=email)
         user = User(username=username, password="test", email=email)
+        user.groups.append(groups[u-1])
+        user.primary_group_id = u
         db.session.add(user)
         db.session.add(user)
 
 
     # create 2 categories
     # create 2 categories