Skip to content

Commit

Permalink
At least can run
Browse files Browse the repository at this point in the history
  • Loading branch information
selfboot committed Jul 1, 2016
0 parents commit 35c0dde
Show file tree
Hide file tree
Showing 23 changed files with 694 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# vim cache
*.swp

.idea/
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# About

A Forum(BBS) based on Flask.



# Features

Major features:

1. Whole user manage system, contains registration, login, change password, retrieve;
2. Users can create topics, append topics, have comments on topics.
3. Send notifications when others @YOU in anywhere.
4. Markdown supported, whether in topics or comments.
5. A convenient administrator page, one can manage users, topics, nodes.
6. A simple keyword search egine, one can search some specific topics.

# How to Run

1. Firstly, make sure all the relevant requirements installed.
2. Do some configure in SYSUVoice/settings.py.



3. Start corresponding database service.
4. Change directory , run `python manage.py runserver`. Just looks like the followings:


36 changes: 36 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
basedir = os.path.abspath(os.path.dirname(__file__))


class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or '!@#$%^&*12345678'
SQLALCHEMY_RECORD_QUERIES = True
SQLALCHEMY_TRACK_MODIFICATIONS = True

MAIL_SERVER = 'smtp.googlemail.com'
MAIL_PORT = 587
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
FLASKY_MAIL_SENDER = 'Flasky Admin <1291023320@qq.com>'

@staticmethod
def init_app(app):
pass


class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = (os.environ.get('DEV_DATABASE_URL') or
'mysql://root:123456@localhost/nahan')


class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = (os.environ.get('DEV_DATABASE_URL') or
'mysql://root:123456@localhost/nahan')

config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
15 changes: 15 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
from nahan import create_app, db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)

manager.add_command('db', MigrateCommand)


if __name__ == '__main__':
manager.run()
38 changes: 38 additions & 0 deletions nahan/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: xuezaigds@gmail.com
# @Last Modified time: 2016-07-01 10:15:12

from flask import Flask
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

from config import config


mail = Mail()
bootstrap = Bootstrap()
db = SQLAlchemy()

login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'


def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)

bootstrap.init_app(app)
mail.init_app(app)
db.init_app(app)
login_manager.init_app(app)

from .user import user as user_blueprint
app.register_blueprint(user_blueprint, url_prefix='/user')
from .voice import voice as voice_blueprint
app.register_blueprint(voice_blueprint)
return app
144 changes: 144 additions & 0 deletions nahan/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: xuezaigds@gmail.com
# @Last Modified time: 2016-07-01 15:57:33
import hashlib
import urllib
from . import db, login_manager
from datetime import datetime
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash


class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
email = db.Column(db.String(64), unique=True, index=True)

is_superuser = db.Column(db.Boolean, default=False)

nickname = db.Column(db.String(64), nullable=True)
use_avatar = db.Column(db.Boolean, default=True)
avatar_url = db.Column(db.String(64), nullable=True)
website = db.Column(db.String(64), nullable=True)

last_login = db.Column(db.DateTime(), default=datetime.utcnow)
date_joined = db.Column(db.DateTime(), default=datetime.utcnow)

@property
def password(self):
raise AttributeError('password is not a readable attribute')

@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)

@property
def print_name(self):
if self.nickname:
return self.nickname
else:
return self.username

def avatar(self):
da = '' # default avatar
dic = {}
if self.use_avatar:
mail = self.email.lower()
avatar_url = "http://www.gravatar.com/avatar/"
base_url = avatar_url + hashlib.md5(mail).hexdigest() + "?"
dic['small'] = base_url + urllib.urlencode({'d': da, 's': '40'})
dic['middle'] = base_url + urllib.urlencode({'d': da, 's': '48'})
dic['large'] = base_url + urllib.urlencode({'d': da, 's': '80'})
return dic
elif self.avatar_url:
dic['small'] = self.avatar_url
dic['middle'] = self.avatar_url
dic['large'] = self.avatar_url
return dic

def verify_password(self, password):
return check_password_hash(self.password_hash, password)

def is_administrator(self):
return self.is_superuser


@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))


class Topic(db.Model):
__tablename__ = "topic"
id = db.Column(db.Integer, primary_key=True)

title = db.Column(db.String(128))
content = db.Column(db.Text())
content_rendered = db.Column(db.Text())

click = db.Column(db.Integer, default=0)
reply_count = db.Column(db.Integer, default=0)

deleted = db.Column(db.Boolean(), default=False)
time_created = db.Column(db.DateTime(), default=datetime.utcnow)
last_replied = db.Column(db.DateTime(), default=datetime.utcnow)

# User create a topic at topic_id which belong to the node.
user_id = db.Column(db.Integer)
node_id = db.Column(db.Integer)


class TopicAppend(db.Model):
__tablename__ = "append"
id = db.Column(db.Integer, primary_key=True)

time_created = db.Column(db.DateTime(), default=datetime.utcnow)
content = db.Column(db.Text())
content_rendered = db.Column(db.Text())
deleted = db.Column(db.Boolean(), default=False)

topic_id = db.Column(db.Integer)


class Comment(db.Model):
__tablename__ = "comment"
id = db.Column(db.Integer, primary_key=True)

content = db.Column(db.Text())
content_rendered = db.Column(db.Text())

deleted = db.Column(db.Boolean(), default=False)
time_created = db.Column(db.DateTime(), default=datetime.utcnow)

# User make a comment at one topic.
user_id = db.Column(db.Integer)
topic_id = db.Column(db.Integer)


class Node(db.Model):
__tablename__ = "node"
id = db.Column(db.Integer, primary_key=True)

title = db.Column(db.String(64))
description = db.Column(db.Text())

def __unicode__(self):
return self.title


class Notify(db.Model):
__tablename__ = "notify"
id = db.Column(db.Integer, primary_key=True)

content = db.Column(db.Text())
is_read = db.Column(db.Boolean(), default=False)
time_created = db.Column(db.DateTime(), default=datetime.utcnow)

# Sender send a message at comment_id of topic_id to receiver_id
sender_id = db.Column(db.Integer)
receiver_id = db.Column(db.Integer)
comment_id = db.Column(db.Integer)
topic_id = db.Column(db.Integer)
12 changes: 12 additions & 0 deletions nahan/templates/403.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% block title %}
403 Forbidden
{% endblock %}
{% block inside_row %}
<div class="panel panel-default col-md-6 col-md-offset-3">
<div class="text-center alert alert-danger" style="margin-top:10px;">
<p>无权访问</p>
</div>
<a href="{% url 'index' %}" class="btn btn-block btn-info" style="margin-bottom:10px;">Go back</a>
</div>
{% endblock %}
12 changes: 12 additions & 0 deletions nahan/templates/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% block title %}
404 Not Found-页面未找到
{% endblock %}
{% block inside_row %}
<div class="panel panel-default col-md-6 col-md-offset-3">
<div class="text-center alert alert-danger" style="margin-top:10px;">
<p>页面未找到</p>
</div>
<a href="{% url 'index' %}" class="btn btn-block btn-info" style="margin-bottom:10px;">Go back</a>
</div>
{% endblock %}
12 changes: 12 additions & 0 deletions nahan/templates/500.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% block title %}
500 Internal Error
{% endblock %}
{% block inside_row %}
<div class="panel panel-default col-md-6 col-md-offset-3">
<div class="text-center alert alert-danger" style="margin-top:10px;">
<p>Internal Error Detected</p>
</div>
<a href="{% url 'index' %}" class="btn btn-block btn-info" style="margin-bottom:10px;">Go back</a>
</div>
{% endblock %}
74 changes: 74 additions & 0 deletions nahan/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{% extends "bootstrap/base.html" %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=360, initial-scale=0.75 user-scalable=no">
{% block header_ext%}
{% endblock %}
<title>
{% spaceless %}
{% block title %}
{{title}}-
{% if pager %}
{% blocktrans %}page {{ pager }}{% endblocktrans %}
-
{% endif %}
{% conf_value "sitename" %}
{% endblock %}
{% endspaceless %}
</title>

<!-- Bootstrap -->
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/base.css' %}" rel="stylesheet">
<link href="{% static 'css/codehilite.css' %}" rel="stylesheet">

</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'index' %}">{% trans 'bbs name' %}</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class=""><a href="{% url 'hottest' %}">{% trans 'hottest post' %}</a></li>
<li class=""><a href="{% url 'node_all' %}">{% trans 'all nodes' %}</a></li>

</ul>
<div class="navbar-form navbar-right" role="search">
<div class="form-group">
<input onkeydown="if(event.keyCode==13){search();}" type="text" id="search" class="form-control" name="search" placeholder="{% trans 'enter key words' %}">
</div>
<a class="btn btn-default" id="search-btn">
{% trans 'Search' %}
</a>
</div>
</div>
</div><!--end nav container-->
</nav><!--end nav-->

<div id="wrap">
<div class="container" id="main">
<div class="row">
{% block inside_row %}
{% endblock %}
</div><!--end outter row-->
</div><!--end main-->
</div><!--end wrap-->

<footer id="footer">
<div class="container clearfix">
<p class="muted credit pull-right"> {% trans "copyright by" %}
</p>
</div>
</footer>

<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/search.js' %}"></script>
{% block footer_ext %}{% endblock %}
</body>
</html>
Loading

0 comments on commit 35c0dde

Please sign in to comment.