-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 35c0dde
Showing
23 changed files
with
694 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.