├── .idea ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── modules.xml └── vcs.xml ├── Procfile ├── README.md ├── app ├── __init__.py ├── api_1_0 │ ├── __init__.py │ ├── authentication.py │ ├── comments.py │ ├── decorators.py │ ├── errors.py │ ├── posts.py │ └── users.py ├── auth │ ├── __init__.py │ ├── forms.py │ └── views.py ├── config ├── decorators.py ├── email.py ├── main │ ├── __init__.py │ ├── errors.py │ ├── forms.py │ └── views.py ├── models.py ├── static │ ├── bootstrap-material-design.css │ ├── bootstrap-material-design.css.map │ ├── bootstrap-material-design.min.css │ ├── bootstrap-material-design.min.css.map │ ├── codehilite.css │ ├── index.js │ ├── jquery.dropdown.css │ ├── jquery.dropdown.js │ ├── material.js │ ├── material.min.js │ ├── material.min.js.map │ ├── ripples.css │ ├── ripples.css.map │ ├── ripples.js │ ├── ripples.min.css │ ├── ripples.min.css.map │ ├── ripples.min.js │ ├── ripples.min.js.map │ └── site.css └── templates │ ├── 403.html │ ├── 404.html │ ├── base.html │ ├── blog.html │ ├── confirm.html │ ├── confirm.txt │ ├── edit_post.html │ ├── edit_profile.html │ ├── followers.html │ ├── include │ ├── _comment.html │ ├── _header.html │ ├── _macros.html │ ├── _navbar.html │ └── _post.html │ ├── index.html │ ├── login.html │ ├── md_editor.html │ ├── moderate.html │ ├── post.html │ ├── register.html │ ├── unconfirmed.html │ ├── upload.html │ └── user.html ├── config.py ├── images ├── 1.png ├── 2.png ├── 3.png ├── 4.png └── 5.png ├── manager.py ├── requirements.txt └── tests ├── __init__.py ├── test_api.py ├── test_basic.py ├── test_client.py └── test_selenium.py /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn manager:app -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于flask的博客系统搭建 2 | - 1.部署的具体网址为http://www.unrealblue.xin/, 360安全浏览器和ie浏览器不兼容 3 | - 2.下载代码到本地,先建立一个virtualenv坏境,我用的是pycharm软件,直接可以建立flask坏境,如下图所示: 4 | ![image](https://github.com/happyte/flask-blog/blob/master/images/1.png) 5 | - 3.激活virtualenv环境,`. venv/bin/activate`。安装所有requirements.txt中的模块,`pip install -r requirements.txt`。因为网络的原因可能会其中某几个会安装失败,多安装几次就好。 6 | - 4.导入坏境变量,需要导入以下三个变量 7 | * export MAIL_USERNAME=(开启了smtp服务的邮箱账号,程序里默认使用163邮箱,可以修改成其它类型邮箱) 8 | * export MAIL_PASSWORD=(不一定是你的邮箱密码,比如163邮箱开启smtp服务会让你设置一个密码,该密码即为password,qq邮箱开启smtp会提示给你一个密码) 9 | * export FLASK_ADMIN=(默认是管理者邮箱,用该邮箱创建账号就是管理者) 10 | - 5.安装数据库迁移。输入以下命令 11 | * `python manager.py db init` (使用init命令创建迁移仓库) 12 | * `python manager.py db migrate -m "initial migration"`(migrate命令用来自动创建迁移脚本) 13 | * `python manager.py db upgrade`(更新数据库,第一次使用该命令会新建一个数据库,可以利用pycharm右侧的Database查看该数据库) 14 | - 6.部署程序,`python manager.py deploy` 15 | - 7.在本地运行程序,`python manager.py runserver`打开http://127.0.0.1:5000端口查看, 按Ctrl+C退出程序。 16 | 17 | ## 实际运行的效果 18 | ![image](https://github.com/happyte/flask-blog/blob/master/images/2.png) 19 | 20 | 21 | ![image](https://github.com/happyte/flask-blog/blob/master/images/3.png) 22 | 23 | 24 | ![image](https://github.com/happyte/flask-blog/blob/master/images/4.png) 25 | 26 | 27 | ![image](https://github.com/happyte/flask-blog/blob/master/images/5.png) 28 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from os import path, environ 3 | from flask import Flask, request 4 | from flask_bootstrap import Bootstrap 5 | from flask_sqlalchemy import SQLAlchemy 6 | from flask_login import LoginManager 7 | from flask_mail import Mail 8 | from flask_moment import Moment 9 | from flask_pagedown import PageDown 10 | from werkzeug.routing import BaseConverter 11 | from config import conifg 12 | 13 | 14 | class RegexConverter(BaseConverter): 15 | def __init__(self, url_map, *items): 16 | super(RegexConverter, self).__init__(url_map) 17 | self.regex = items[0] 18 | 19 | bootstrap = Bootstrap() 20 | db = SQLAlchemy() 21 | login_manager = LoginManager() 22 | mail = Mail() 23 | moment = Moment() 24 | pagedown = PageDown() 25 | login_manager.session_protection = 'strong' 26 | login_manager.login_view = 'auth.login' # login_view设置登陆页面的端点 27 | basedir = path.abspath(path.dirname(__file__)) 28 | 29 | def create_app(config_name): 30 | app = Flask(__name__) 31 | app.config.from_object(conifg[config_name]) # 配置都在config.py这个文件中 32 | conifg[config_name].init_app(app) 33 | 34 | bootstrap.init_app(app) 35 | db.init_app(app) 36 | login_manager.init_app(app) 37 | mail.init_app(app) 38 | moment.init_app(app) 39 | pagedown.init_app(app) 40 | 41 | from .main import main as main_blueprint 42 | from .auth import auth as auth_blueprint 43 | from .api_1_0 import api as api_1_0_blueprint # 注册api蓝图 44 | app.register_blueprint(main_blueprint, static_folder='static', template_folder='templates') 45 | app.register_blueprint(auth_blueprint, url_prefix='/auth') 46 | app.register_blueprint(api_1_0_blueprint, url_prefix='/api/v1_0') 47 | 48 | @app.template_test('current_link') 49 | def current_link(link): 50 | return link == request.path 51 | 52 | return app 53 | 54 | -------------------------------------------------------------------------------- /app/api_1_0/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import Blueprint 3 | 4 | api = Blueprint('api', __name__) 5 | 6 | from . import authentication, decorators, comments, users, posts, errors -------------------------------------------------------------------------------- /app/api_1_0/authentication.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import g, jsonify 3 | from flask_httpauth import HTTPBasicAuth 4 | from ..models import User, AnonymousUser 5 | from . import api 6 | from .errors import unauthorized, forbidden 7 | 8 | 9 | auth = HTTPBasicAuth() 10 | 11 | # api验证用户是否登陆,每次验证api先来到这个装饰器函数,在来到before_request函数 12 | @auth.verify_password 13 | def verify_password(email_or_token, password): 14 | if email_or_token == '': # 匿名用户 15 | g.current_user = AnonymousUser() 16 | return True 17 | if password == '': # 用token进行验证 18 | g.current_user = User.verify_auth_token(email_or_token) 19 | g.token_used = True 20 | return g.current_user is not None 21 | user = User.query.filter_by(email=email_or_token).first() # 按正常的邮箱查询 22 | if not user: 23 | return False 24 | g.current_user = user 25 | g.token_used = False 26 | return user.verify_password(password) 27 | 28 | 29 | @api.route('/token') 30 | def get_token(): 31 | if g.current_user.is_anonymous or g.token_used: # 匿名用户或者令牌已经被使用 32 | return unauthorized('Invalid credentials') 33 | return jsonify({'token': g.current_user.generate_auth_token(expiration=3600), 'expiration': 3600}) 34 | 35 | # 在每次请求前检查该用户是否已经通过验证 36 | @api.before_app_request 37 | @auth.login_required 38 | def before_request(): 39 | if not g.current_user.is_anonymous and not g.current_user.confirmed: 40 | return forbidden('Unconfirmed account') 41 | 42 | @auth.error_handler 43 | def auth_error(): 44 | return unauthorized('Invalid credentials') -------------------------------------------------------------------------------- /app/api_1_0/comments.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import jsonify, request, url_for, g 3 | from . import api 4 | from ..models import Post, User, Comment, Permission 5 | from .decorators import permission_required 6 | from app import db 7 | 8 | # 所有的评论 9 | @api.route('/comments') 10 | def get_comments(): 11 | page = request.args.get('page', 1, type=int) 12 | pagination = Comment.query.paginate(page=page, per_page=10, error_out=False) 13 | comments = pagination.items 14 | prev = None 15 | if pagination.has_prev: 16 | prev = url_for('api.get_comments', page=page - 1, _external=True) 17 | next = None 18 | if pagination.has_next: 19 | next = url_for('api.get_comments', page=page + 1, _external=True) 20 | return jsonify({ 21 | 'posts': [comment.to_json() for comment in comments], 22 | 'prev': prev, 23 | 'next': next, 24 | 'count': pagination.total 25 | }) 26 | 27 | # 具体一条评论 28 | @api.route('/comments/') 29 | def get_comment(id): 30 | comment = Comment.query.get_or_404(id) 31 | return jsonify(comment.to_json()) 32 | 33 | # 某篇文章的所有评论 34 | @api.route('/posts//comments') 35 | def get_post_comments(id): 36 | post = Post.query.get_or_404(id) 37 | page = request.args.get('page', 1, type=int) 38 | pagination = post.comments.order_by(Comment.timestamp.desc()).paginate(page=page, per_page=10, error_out=False) 39 | comments = pagination.items 40 | prev = None 41 | if pagination.has_prev: 42 | prev = url_for('api.get_post_comments', id=id, page=page - 1, _external=True) 43 | next = None 44 | if pagination.has_next: 45 | next = url_for('api.get_post_comments', id=id, page=page + 1, _external=True) 46 | return jsonify({ 47 | 'posts': [comment.to_json() for comment in comments], 48 | 'prev': prev, 49 | 'next': next, 50 | 'count': pagination.total 51 | }) 52 | 53 | # 发表某篇文章的评论 54 | @api.route('/posts//comments', methods=['POST']) 55 | @permission_required(Permission.COMMENT) 56 | def new_comment(id): 57 | comment = Comment.from_json(request.json) 58 | post = Post.query.get_or_404(id) 59 | comment.post = post 60 | comment.author = g.current_user 61 | db.session.add(comment) 62 | db.session.commit() 63 | return jsonify(comment.to_json()), 201, {'Location': url_for('api.get_comment', id=comment.id, _external=True)} 64 | -------------------------------------------------------------------------------- /app/api_1_0/decorators.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import g 3 | from .errors import forbidden 4 | from functools import wraps 5 | 6 | 7 | # 装饰器函数,带参数,3层函数 8 | def permission_required(permissions): 9 | def decorator(f): 10 | @wraps(f) 11 | def wrapper(*args, **kwargs): 12 | if not g.current_user.can(permissions): 13 | return forbidden(u'没有相应的权限') 14 | return f(*args, **kwargs) 15 | return wrapper 16 | return decorator -------------------------------------------------------------------------------- /app/api_1_0/errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import jsonify 3 | 4 | def bad_request(message): 5 | response = jsonify({'error': 'bad request', 'message': message}) 6 | response.status_code = 400 7 | return response 8 | 9 | def unauthorized(message): 10 | response = jsonify({'error': 'unauthorized', 'message': message}) 11 | response.status_code = 401 12 | return response 13 | 14 | def forbidden(message): 15 | response = jsonify({'error': 'forbidden', 'message': message}) 16 | response.status_code = 403 17 | return response -------------------------------------------------------------------------------- /app/api_1_0/posts.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import jsonify, request, url_for, g 3 | from . import api 4 | from ..models import Post, Permission 5 | from app import db 6 | from .decorators import permission_required 7 | from .errors import forbidden 8 | 9 | # 返回所有文章的集合 10 | @api.route('/posts') 11 | def get_posts(): 12 | page = request.args.get('page', 1, type=int) 13 | pagination = Post.query.paginate(page=page, per_page=10, error_out=False) 14 | posts = pagination.items 15 | prev = None 16 | if pagination.has_prev: 17 | prev = url_for('api.get_posts', page=page-1, _external=True) 18 | next = None 19 | if pagination.has_next: 20 | next = url_for('api.get_posts', page=page+1, _external=True) 21 | return jsonify({ 22 | 'posts': [post.to_json() for post in posts], 23 | 'prev': prev, 24 | 'next': next, 25 | 'count': pagination.total 26 | }) 27 | 28 | # 返回具体一篇博客的API 29 | @api.route('/posts/') 30 | def get_post(id): 31 | post = Post.query.get_or_404(id) 32 | return jsonify(post.to_json()) 33 | 34 | # 发布一篇新文章API 35 | @api.route('/posts', methods=['POST']) 36 | @permission_required(Permission.WRITE_ARTICLES) 37 | def new_post(): 38 | post = Post.from_json(request.json) 39 | post.author = g.current_user 40 | db.session.add(post) 41 | db.session.commit() 42 | return jsonify(post.to_json()), 201, {'Location': url_for('api.get_post', id=post.id, _external=True)} 43 | 44 | # 编辑修改某一篇博客的API 45 | @api.route('/posts/', methods=['PUT']) 46 | @permission_required(Permission.WRITE_ARTICLES) 47 | def edit_post(id): 48 | post = Post.query.get_or_404(id) 49 | if g.current_user != post.author and \ 50 | not g.current_user.can(Permission.ADMINISTRATOR): 51 | return forbidden('Insufficient permission') 52 | post.title = request.json.get('title') 53 | post.body = request.json.get('body') 54 | db.session.add(post) 55 | return jsonify(post.to_json()) -------------------------------------------------------------------------------- /app/api_1_0/users.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import jsonify, request, url_for, g 3 | from . import api 4 | from ..models import Post, User 5 | 6 | 7 | # 查询所有用户 8 | @api.route('/users') 9 | def get_users(): 10 | page = request.args.get('page', 1, type=int) 11 | pagination = User.query.paginate(page=page, per_page=10, error_out=False) 12 | prev = None 13 | if pagination.has_prev: 14 | prev = url_for('api.get_users', page=page-1, _external=True) 15 | next = None 16 | if pagination.has_next: 17 | next = url_for('api.get_users', page=page+1, _external=True) 18 | users = pagination.items 19 | return jsonify({ 20 | 'users': [user.to_json() for user in users], 21 | 'prev': prev, 22 | 'next': next, 23 | 'count': pagination.total 24 | }) 25 | 26 | # 查询某个具体用户 27 | @api.route('/users/') 28 | def get_user(id): 29 | user = User.query.get_or_404(id) 30 | return jsonify(user.to_json()) 31 | 32 | # 查询某个用户的所有发表博客 33 | @api.route('/users//posts') 34 | def get_user_posts(id): 35 | user = User.query.get_or_404(id) 36 | page = request.args.get('page', 1, type=int) 37 | pagination = user.posts.order_by(Post.timestamp.desc()).paginate(page=page, per_page=10, error_out=False) 38 | prev = None 39 | if pagination.has_prev: 40 | prev = url_for('api.get_user_posts', id=id, page=page - 1, _external=True) 41 | next = None 42 | if pagination.has_next: 43 | next = url_for('api.get_user_posts', id=id, page=page + 1, _external=True) 44 | posts = pagination.items 45 | return jsonify({ 46 | 'posts': [post.to_json() for post in posts], 47 | 'prev': prev, 48 | 'next': next, 49 | 'count': pagination.total 50 | }) 51 | 52 | # 查询某个用户的所有followers的博客 53 | @api.route('/users//timeline') 54 | def get_followers_posts(id): 55 | user = User.query.get_or_404(id) 56 | page = request.args.get('page', 1, type=int) 57 | pagination = user.followed_posts.order_by(Post.timestamp.desc()).paginate(page=page, per_page=10, error_out=False) 58 | prev = None 59 | if pagination.has_prev: 60 | prev = url_for('api.get_user_posts', id=id, page=page - 1, _external=True) 61 | next = None 62 | if pagination.has_next: 63 | next = url_for('api.get_user_posts', id=id, page=page + 1, _external=True) 64 | posts = pagination.items 65 | return jsonify({ 66 | 'posts': [post.to_json() for post in posts], 67 | 'prev': prev, 68 | 'next': next, 69 | 'count': pagination.total 70 | }) -------------------------------------------------------------------------------- /app/auth/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import Blueprint 3 | 4 | auth = Blueprint('auth',__name__) 5 | 6 | from . import views -------------------------------------------------------------------------------- /app/auth/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask_wtf import FlaskForm 3 | from wtforms import StringField, SubmitField, PasswordField, BooleanField 4 | from wtforms.validators import DataRequired, Email, Length, EqualTo 5 | 6 | #登陆表 7 | class LoginForm(FlaskForm): 8 | email = StringField(label=u'邮箱',validators=[DataRequired(), Length(1,64), Email()], id='loginlength') 9 | password = PasswordField(label=u'密码',validators=[DataRequired()], id='loginlength') 10 | remember_me = BooleanField(label=u'记住我', id='loginlength') 11 | submit = SubmitField(label=u'登陆') 12 | 13 | #注册表 14 | class RegisterForm(FlaskForm): 15 | email = StringField(label=u'邮箱地址',validators=[DataRequired(), Length(1,64), Email()], id='registerlength') 16 | username = StringField(label=u'用户名',validators=[DataRequired(), Length(1,64)], 17 | id='registerlength') 18 | password = PasswordField(label=u'密码',validators=[DataRequired(), 19 | EqualTo('password2', message=u'密码必须相同')], id='registerlength') 20 | password2 = PasswordField(label=u'确认密码',validators=[DataRequired()], id='registerlength') 21 | submit = SubmitField(label=u'马上注册') -------------------------------------------------------------------------------- /app/auth/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import render_template, flash, redirect, url_for, request 3 | from flask_login import login_user, logout_user, login_required, current_user 4 | 5 | from ..email import send_mail 6 | from . import auth 7 | from .. import db 8 | from ..models import User 9 | 10 | 11 | @auth.route('/login', methods=['GET', 'POST']) 12 | def login(): 13 | from app.auth.forms import LoginForm 14 | form = LoginForm() 15 | if form.validate_on_submit(): 16 | user = User.query.filter_by(email=form.email.data).first() 17 | if user is not None and user.verify_password(form.password.data): # 密码验证成功 18 | login_user(user, form.remember_me.data) 19 | return redirect(url_for('main.index')) 20 | flash(u'帐号或者密码错误') 21 | return render_template('login.html', title=u'登陆', form=form) 22 | 23 | @auth.route('/logout', methods=['GET', 'POST']) 24 | @login_required 25 | def logout(): 26 | logout_user() 27 | flash(u'您已退出登陆') 28 | return redirect(url_for('auth.login')) 29 | 30 | 31 | @auth.route('/register', methods=['GET', 'POST']) 32 | def register(): 33 | from app.auth.forms import RegisterForm 34 | form = RegisterForm() 35 | if form.validate_on_submit(): 36 | user = User(username=form.username.data, 37 | password=form.password.data, email=form.email.data) # 新添加一个用户到数据库中 38 | db.session.add(user) 39 | db.session.commit() 40 | User.add_self_follows() # 把自己添加成自己的关注 41 | token = user.generate_confirm_token() # 产生一个令牌 42 | send_mail(user.email, u'请确认您的帐号', 'confirm', user=user, token=token) # 发送邮件 43 | flash(u'有一份邮件已经发往您的邮箱') 44 | return redirect(url_for('auth.login')) # 这一步一直有问题,无法重定向,直接跳到下面去了 45 | else: 46 | return render_template('register.html', title=u'注册', form=form) 47 | 48 | @auth.route('/confirm/') 49 | @login_required 50 | def confirm(token): 51 | if current_user.confirmed: 52 | return redirect(url_for('main.index')) # 重复点击邮箱的令牌 53 | if current_user.confirm(token): 54 | flash(u'感谢您的确认') 55 | else: 56 | flash(u'链接已经失效或者过期') 57 | return redirect(url_for('main.index')) 58 | 59 | @auth.before_app_request # 用户已登陆、用户帐号还未确认、请求的的端点不在auth认证蓝本中 60 | def before_request(): 61 | if current_user.is_authenticated: 62 | current_user.ping() # 在每次请求前刷新上次访问时间 63 | if not current_user.confirmed \ 64 | and request.endpoint[:5] != 'auth.': 65 | return redirect(url_for('auth.unconfirmed')) 66 | 67 | @auth.route('/unconfirmed') # 如果当前是匿名帐号活着已经确认,直接返回首页,否则显示未确认 68 | def unconfirmed(): 69 | if current_user.is_anonymous or current_user.confirmed: 70 | return redirect(url_for('main.index')) 71 | return render_template('unconfirmed.html') 72 | 73 | @auth.route('/resend_email') 74 | @login_required 75 | def resend_email(): 76 | token = current_user.generate_confirm_token() 77 | send_mail(current_user.email, u'确认您的帐号', 'confirm', user=current_user, token=token) 78 | flash(u'一份新的邮件已经发往您的邮箱') 79 | return redirect(url_for('main.index')) -------------------------------------------------------------------------------- /app/config: -------------------------------------------------------------------------------- 1 | SECRET_KEY = 'hard to guess string' -------------------------------------------------------------------------------- /app/decorators.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from functools import wraps 3 | from flask import abort 4 | from flask_login import current_user 5 | from .models import Permission 6 | 7 | 8 | # 装饰器函数,带参数,3层函数 9 | def permission_required(permissions): 10 | def decorator(f): 11 | @wraps(f) 12 | def wrapper(*args, **kwargs): 13 | if not current_user.can(permissions): 14 | abort(403) 15 | return f(*args, **kwargs) 16 | return wrapper 17 | return decorator 18 | 19 | # 调用上面装饰器函数 20 | def admin_required(f): 21 | return permission_required(Permission.ADMINISTRATOR)(f) # 带参数,且传递函数 -------------------------------------------------------------------------------- /app/email.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from threading import Thread 3 | from flask_mail import Message 4 | from flask import render_template 5 | from . import mail 6 | from flask import current_app # 这样就不用使用from manager import app 7 | import os 8 | 9 | def send_async_mail(app, msg): 10 | with app.app_context(): 11 | mail.send(msg) 12 | 13 | 14 | # 四个参数分别为(1.接收者邮箱地址 2.主题 3.模板 4.可变参数) 15 | def send_mail(to, subject, template, **kw): 16 | app = current_app._get_current_object() 17 | msg = Message(subject=subject, sender=app.config['FLASKY_MAIL_SENDER'], 18 | recipients=[to]) # 主题,发送者(从环境变量中读出),接收者 19 | msg.body = render_template(template + '.txt', **kw) # 文本内容 20 | msg.html = render_template(template + '.html', **kw) # 文本渲染 21 | thr = Thread(target=send_async_mail, args=[app, msg]) 22 | thr.start() 23 | return thr -------------------------------------------------------------------------------- /app/main/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import Blueprint 3 | 4 | main = Blueprint('main', __name__) 5 | 6 | import views, errors -------------------------------------------------------------------------------- /app/main/errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from . import main 3 | from flask import render_template, request, jsonify 4 | 5 | # 对于只接受json格式不接受html格式的客户端只提供json响应 6 | @main.app_errorhandler(404) 7 | def page_not_found(error): 8 | if request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html: 9 | response = jsonify({'error': 'not found'}) 10 | response.status_code = 404 11 | return response 12 | return render_template('404.html'), 404 13 | 14 | @main.app_errorhandler(403) 15 | def forbidden_enter(error): 16 | if request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html: 17 | response = jsonify({'error': 'forbidden'}) 18 | response.status_code = 403 19 | return response 20 | return render_template('403.html'), 403 21 | 22 | 23 | @main.app_errorhandler(500) 24 | def forbidden_enter(error): 25 | if request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html: 26 | response = jsonify({'error': 'server internal error'}) 27 | response.status_code = 500 28 | return response 29 | return render_template('403.html'), 500 -------------------------------------------------------------------------------- /app/main/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask_wtf import FlaskForm 3 | from wtforms import StringField, SubmitField, SelectField, BooleanField, TextAreaField 4 | from wtforms.validators import DataRequired, Email, Length 5 | from flask_pagedown.fields import PageDownField 6 | from ..models import Role 7 | 8 | # 首页的博客文章表单 9 | class PostForm(FlaskForm): 10 | title = StringField(label=u'博客标题', validators=[DataRequired()], id='titlecode') 11 | body = PageDownField(label=u'博客内容', validators=[DataRequired()]) 12 | submit = SubmitField(label=u'提交') 13 | 14 | class CommentForm(FlaskForm): 15 | body = PageDownField(label=u'发表评论', validators=[DataRequired()]) 16 | submit = SubmitField(label=u'提交') 17 | 18 | 19 | # 普通用户登陆表单 20 | class EditProfileForm(FlaskForm): 21 | name = StringField(label=u'真实姓名', validators=[Length(0,64)]) 22 | location = StringField(label=u'地址', validators=[Length(0,64)]) 23 | about_me = TextAreaField(label=u'关于我') 24 | submit = SubmitField(label=u'提交') 25 | 26 | 27 | # 管理员登陆表单,能编辑用户的电子邮件,用户名,确认状态和角色 28 | class EditProfileAdministratorForm(FlaskForm): 29 | email = StringField(label=u'邮箱', validators=[DataRequired(), Length(1,64), Email()]) 30 | username = StringField(label=u'用户名', validators=[DataRequired(), Length(1, 64)]) 31 | confirmed = BooleanField(label=u'确认') 32 | role = SelectField(label=u'角色', coerce=int) 33 | 34 | name = StringField(label=u'真实姓名', validators=[Length(0, 64)]) 35 | location = StringField(label=u'地址', validators=[Length(0, 64)]) 36 | about_me = TextAreaField(label=u'关于我') 37 | submit = SubmitField(label=u'提交') 38 | 39 | # 初始化时要对role的复选框进行搭建 40 | def __init__(self, user, *args, **kwargs): 41 | super(EditProfileAdministratorForm, self).__init__(*args, **kwargs) 42 | self.role.choices = [(role.id, role.name) for role in Role.query.order_by(Role.name)] 43 | self.user = user -------------------------------------------------------------------------------- /app/main/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from flask import render_template, flash, abort, redirect, url_for, request, current_app, make_response 3 | from flask_login import login_required, current_user 4 | from ..decorators import admin_required, permission_required 5 | from ..models import Permission, User, Role, Post, Comment 6 | from . import main 7 | from .forms import EditProfileForm, EditProfileAdministratorForm, PostForm, CommentForm 8 | from .. import db 9 | from flask_sqlalchemy import get_debug_queries 10 | 11 | 12 | @main.route('/', methods=['GET','POST']) 13 | def index(): 14 | show_followed = False 15 | if current_user.is_authenticated: 16 | show_followed = bool(request.cookies.get('show_followed')) # 判断cookie是否大于0 17 | if show_followed: 18 | query = current_user.followed_posts 19 | else: 20 | query = Post.query 21 | page = request.args.get('page',1, type=int) # 1代表如果没有明确指定,则默认渲染第一页,为2的话默认来到第二页 22 | pagination = query.order_by(Post.timestamp.desc()).paginate( 23 | page, per_page=10, 24 | error_out=False) # error_out=True页数超出范围返回404错误,False返回空列表 25 | posts = pagination.items 26 | return render_template('index.html', show_followed=show_followed, 27 | posts=posts, pagination=pagination) 28 | 29 | @main.route('/all') 30 | @login_required 31 | def show_all(): 32 | response = make_response(redirect(url_for('main.index'))) 33 | response.set_cookie('show_followed','',max_age=30*24*60*60) # 通过cookie的值判断点击了all还是followed 34 | return response 35 | 36 | @main.route('/followed') 37 | @login_required 38 | def show_followed(): 39 | response = make_response(redirect(url_for('main.index'))) 40 | response.set_cookie('show_followed','2',max_age=30*24*60*60) 41 | return response 42 | 43 | # 首页中文章固定链接路由,加上评论表单 44 | @main.route('/post/', methods=['GET','POST']) 45 | def post(id): 46 | post = Post.query.get_or_404(id) 47 | form = CommentForm() 48 | if form.validate_on_submit(): 49 | comment = Comment(body=form.body.data, 50 | post=post, 51 | author=current_user._get_current_object(), 52 | ) 53 | db.session.add(comment) 54 | db.session.commit() 55 | return redirect(url_for('main.post', id=post.id, page=-1)) # 来到评论的最后一页 56 | page = request.args.get('page',1,type=int) 57 | if page == -1: 58 | page = (post.comments.count()-1)/10 + 1 59 | pagination = post.comments.order_by(Comment.timestamp.asc()).paginate( 60 | page, per_page=10, error_out=False 61 | ) 62 | comments = pagination.items 63 | return render_template('post.html', posts=[post], form=form, 64 | comments=comments, pagination=pagination) 65 | 66 | @main.route('/blog',methods=['GET','POST']) 67 | @login_required 68 | def blog(): 69 | form = PostForm() 70 | if current_user.can(Permission.WRITE_ARTICLES) and \ 71 | form.validate_on_submit(): 72 | post = Post(title=form.title.data,body=form.body.data, 73 | author=current_user._get_current_object()) 74 | db.session.add(post) 75 | db.session.commit() 76 | return redirect(url_for('main.index')) 77 | return render_template('blog.html',form=form) 78 | 79 | 80 | @main.route('/admin') # 在登陆状态下只允许管理者进入,否则来到403禁止登陆界面 81 | @login_required 82 | @admin_required 83 | def for_admin_only(): 84 | return u'管理者进入' 85 | 86 | @main.route('/moderator') 87 | @login_required 88 | @permission_required(Permission.MODERATE_COMMENTS) 89 | def for_moderator_only(): 90 | return u'管理者进入' 91 | 92 | @main.route('/user/') 93 | def user(username): 94 | user = User.query.filter_by(username=username).first() 95 | if user is None: 96 | abort(404) 97 | posts = user.posts.order_by(Post.timestamp.desc()).all() 98 | return render_template('user.html', user=user, posts=posts) 99 | 100 | # 关注用户 101 | @main.route('/follow/') 102 | def follow(username): 103 | u = User.query.filter_by(username=username).first() 104 | if u is None: 105 | flash(u'没有该用户') 106 | return redirect(url_for('main.index')) 107 | if current_user.is_following(u): 108 | flash(u'已经关注了该用户') 109 | return redirect(url_for('main.user', username=username)) 110 | current_user.follow(u) 111 | flash(u'关注了 %s' % username) 112 | return redirect(url_for('main.user', username=username)) 113 | 114 | # 取消关注 115 | @main.route('/unfollow/') 116 | def unfollow(username): 117 | u = User.query.filter_by(username=username).first() 118 | if u is None: 119 | flash(u'没有该用户') 120 | return redirect(url_for('main.index')) 121 | if u.is_followed_by(current_user): 122 | current_user.unfollow(u) 123 | flash(u'取消对 %s 的关注' % username) 124 | return redirect(url_for('main.user', username=username)) 125 | 126 | # 列出所有的粉丝 127 | @main.route('/followers/') 128 | def followers(username): 129 | u = User.query.filter_by(username=username).first() 130 | page = request.args.get('page', 1, type=int) 131 | pagination = u.followers.paginate(page, per_page=10, error_out=False) 132 | follows = [{'user':item.follower,'timestamp':item.timestamp} 133 | for item in pagination.items] # 转换成一个字典列表 134 | return render_template('followers.html', title=u'的粉丝',user=u, pagination=pagination, follows=follows) 135 | 136 | # 列出所有我的关注 137 | @main.route('/followed-by/') 138 | def followed_by(username): 139 | u = User.query.filter_by(username=username).first() 140 | page = request.args.get('page', 1, type=int) 141 | pagination = u.followed.paginate(page, per_page=10, error_out=False) 142 | follows = [{'user':item.followed,'timestamp':item.timestamp} 143 | for item in pagination.items] # 转换成一个字典列表 144 | return render_template('followers.html', title=u'的关注',user=u, pagination=pagination, follows=follows) 145 | 146 | 147 | # 普通用户级别的编辑 148 | @main.route('/edit-profile',methods=['GET','POST']) 149 | @login_required 150 | def edit_profile(): 151 | form = EditProfileForm() 152 | if form.validate_on_submit(): 153 | current_user.name = form.name.data 154 | current_user.location = form.location.data 155 | current_user.about_me = form.about_me.data 156 | flash(u'你的个人信息已经被更改') 157 | db.session.add(current_user) # 更新个人资料 158 | db.session.commit() 159 | return redirect(url_for('main.user', username=current_user.username)) 160 | form.name.data = current_user.name 161 | form.location.data = current_user.location 162 | form.about_me.data = current_user.about_me 163 | return render_template('edit_profile.html',form=form) 164 | 165 | # 管理员级别的编辑 166 | @main.route('/edit-profile/',methods=['GET','POST']) 167 | @login_required 168 | @admin_required 169 | def edit_profile_admin(id): 170 | user = User.query.get_or_404(id) # 查找这个用户 171 | form = EditProfileAdministratorForm(user=user) 172 | if form.validate_on_submit(): 173 | user.email = form.email.data 174 | user.username = form.username.data 175 | user.confirmed = form.confirmed.data 176 | user.itsrole = Role.query.get(form.role.data) 177 | user.name = form.name.data 178 | user.location = form.location.data 179 | user.about_me = form.about_me.data 180 | db.session.add(user) 181 | db.session.commit() 182 | flash(u'该用户的信息已经更新了') 183 | return redirect(url_for('main.user',username=user.username)) 184 | form.email.data = user.email 185 | form.username.data = user.username 186 | form.confirmed.data = user.confirmed 187 | form.role.data = user.role_id # role_id 与 itsrole是关联的 188 | form.name.data = user.name 189 | form.location.data = user.location 190 | form.about_me.data = user.about_me 191 | return render_template('edit_profile.html',form=form,user=user) 192 | 193 | # 编辑博客文章路由 194 | @main.route('/edit/', methods=['GET','POST']) 195 | @login_required 196 | def edit(id): 197 | post = Post.query.get_or_404(id) 198 | if current_user != post.author and \ 199 | not current_user.can(Permission.ADMINISTRATOR): # 当前作者不是发表博客的人且不是管理员 200 | abort(403) 201 | form = PostForm() 202 | if form.validate_on_submit(): 203 | post.title = form.title.data 204 | post.body = form.body.data 205 | db.session.add(post) 206 | db.session.commit() 207 | return redirect(url_for('main.post',id=post.id)) 208 | form = PostForm() 209 | form.title.data = post.title 210 | form.body.data = post.body 211 | return render_template('edit_post.html', form=form) 212 | 213 | # 协管员管理评论,所有评论 214 | @main.route('/moderate', methods=['GET','POST']) 215 | @login_required 216 | @permission_required(Permission.MODERATE_COMMENTS) 217 | def moderate(): 218 | page = request.args.get('page',1,type=int) 219 | pagination = Comment.query.order_by(Comment.timestamp.desc()).paginate( 220 | page, per_page=10, error_out=False) 221 | comments = pagination.items 222 | return render_template('moderate.html', 223 | comments=comments, pagination=pagination, page=page) 224 | 225 | # 禁止该条评论 226 | @main.route('/moderate/disable/') 227 | @login_required 228 | @permission_required(Permission.MODERATE_COMMENTS) 229 | def moderate_disable(id): 230 | comment = Comment.query.get_or_404(id) 231 | comment.disabled = True 232 | db.session.add(comment) 233 | db.session.commit() 234 | return redirect(url_for('main.moderate',page=request.args.get('page',1,type=int))) 235 | 236 | # 使能该条评论 237 | @main.route('/moderate/enable/') 238 | @login_required 239 | @permission_required(Permission.MODERATE_COMMENTS) 240 | def moderate_enable(id): 241 | comment = Comment.query.get_or_404(id) 242 | comment.disabled = False 243 | db.session.add(comment) 244 | db.session.commit() 245 | return redirect(url_for('main.moderate', page=request.args.get('page', 1, type=int))) 246 | 247 | @main.app_context_processor 248 | def inject_permissions(): 249 | return dict(Permission=Permission) 250 | 251 | @main.route('/shutdown') 252 | def server_shutdown(): 253 | if not current_app.testing: 254 | abort(404) 255 | shutdown = request.environ.get('werkzeug.server,shutdown') 256 | if not shutdown: 257 | abort(500) 258 | shutdown() 259 | return '-----Shutting down------' 260 | 261 | @main.after_app_request 262 | def after_request(response): 263 | for query in get_debug_queries(): 264 | if query.duration >= current_app.config['FLASKY_SLOW_DB_QUERY_TIME']: 265 | current_app.logger.warning( 266 | 'Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' 267 | % (query.statement, query.parameters, query.duration, 268 | query.context)) 269 | return response 270 | 271 | 272 | -------------------------------------------------------------------------------- /app/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from . import db, login_manager 3 | from flask_login import UserMixin, AnonymousUserMixin 4 | from werkzeug.security import generate_password_hash, check_password_hash 5 | from itsdangerous import TimedJSONWebSignatureSerializer as Serializer 6 | from flask import current_app, request, url_for 7 | from datetime import datetime 8 | import hashlib 9 | from markdown import markdown 10 | import bleach 11 | 12 | class Permission: 13 | FOLLOW = 0x01 # 关注用户 14 | COMMENT = 0x02 # 在他人的文章中发表评论 15 | WRITE_ARTICLES = 0x04 # 写文章 16 | MODERATE_COMMENTS = 0x08 # 管理他人发表的评论 17 | ADMINISTRATOR = 0xff # 管理者权限 18 | 19 | class Role(db.Model): 20 | __tablename__ = 'roles' 21 | id = db.Column(db.Integer, primary_key=True) 22 | name = db.Column(db.String, nullable=True, unique=True) 23 | default = db.Column(db.Boolean, default=False) # 只有一个角色的字段要设为True,其它都为False 24 | permissions = db.Column(db.Integer) # 不同角色的权限不同 25 | users = db.relationship('User', backref='itsrole') # Role对象引用users,User对象引用itsrole 26 | # 是隐形存在的属性,一对多 27 | @staticmethod 28 | def insert_roles(): 29 | roles = { 30 | 'User':(Permission.FOLLOW|Permission.COMMENT| 31 | Permission.WRITE_ARTICLES, True), # 只有普通用户的default为True 32 | 'Moderare':(Permission.FOLLOW|Permission.COMMENT| 33 | Permission.WRITE_ARTICLES|Permission.MODERATE_COMMENTS, False), 34 | 'Administrator':(0xff, False) 35 | } 36 | for r in roles: 37 | role = Role.query.filter_by(name=r).first() 38 | if role is None: 39 | role = Role(name=r) 40 | role.permissions = roles[r][0] 41 | role.default = roles[r][1] 42 | db.session.add(role) 43 | db.session.commit() 44 | 45 | 46 | class Follow(db.Model): 47 | __tablename__ = 'follows' 48 | follower_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True) # 代表关注者,与relationship的follower对应 49 | followed_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True) # 代表被关注者,与relationship的followed对应 50 | timestamp = db.Column(db.DateTime, default=datetime.utcnow) 51 | 52 | 53 | class User(UserMixin, db.Model): 54 | __tablename__ = 'users' 55 | id = db.Column(db.Integer, primary_key=True) 56 | username = db.Column(db.String, nullable=True) 57 | password = db.Column(db.String, nullable=True) 58 | email = db.Column(db.String, nullable=True, unique=True) # 新建一个邮箱字段 59 | role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) 60 | password_hash = db.Column(db.String, nullable=True) # 模型中加入密码散列值 61 | confirmed = db.Column(db.Boolean, default=False) # 邮箱令牌是否点击 62 | name = db.Column(db.String(64)) # 用户信息中的昵称 63 | location = db.Column(db.String(64)) # 用户地址 64 | about_me = db.Column(db.Text()) # 用户介绍 65 | member_since = db.Column(db.DateTime, default=datetime.utcnow) # 注册时间 66 | last_seen = db.Column(db.DateTime, default=datetime.utcnow) # 上次访问时间 67 | posts = db.relationship('Post', backref='author', lazy='dynamic', 68 | cascade='all, delete-orphan') # 一个用户有多条发表,一对多 69 | followed = db.relationship('Follow', foreign_keys=[Follow.follower_id], # 该用户关注了其它用户,对于其它用户而言,该用户就是它的追随者(关注者) 70 | backref=db.backref('follower', lazy='joined'), # 对应follower_id 71 | lazy='dynamic', 72 | cascade='all, delete-orphan') 73 | followers = db.relationship('Follow', foreign_keys=[Follow.followed_id], # 该用户的关注者们,对于关注者们而言,关注者们关注了该用户 74 | backref=db.backref('followed', lazy='joined'), # 对应followed_id 75 | lazy='dynamic', 76 | cascade='all, delete-orphan') 77 | comments = db.relationship('Comment', backref='author', lazy='dynamic') 78 | 79 | def to_json(self): 80 | user_json = { 81 | 'url': url_for('api.get_user', id=self.id, _external=True), 82 | 'username': self.username, 83 | 'member_since': self.member_since, 84 | 'last_seen': self.last_seen, 85 | 'post_count': self.posts.count() 86 | } 87 | return user_json 88 | 89 | 90 | def __init__(self, **kwargs): 91 | super(User, self).__init__(**kwargs) # 初始化父类 92 | if self.itsrole is None: 93 | if self.email == current_app.config['FLASK_ADMIN']: # 邮箱与管理者邮箱相同 94 | self.itsrole = Role.query.filter_by(permissions=0xff).first() # 权限为管理者 95 | else: 96 | self.itsrole = Role.query.filter_by(default=True).first() # 默认用户 97 | 98 | def follow(self, user): # 关注user 99 | if not self.is_following(user): 100 | f = Follow(follower=self, followed=user) # self为关注者,follower_id与之对应,与此同时self.followed(self关注了其它用户)添加一个新值 101 | db.session.add(f) # user为被关注者,followed_id与之对应,与此同时user.followers(user被其它用户关注)添加一个新值 102 | db.session.commit() 103 | 104 | def unfollow(self, user): # 取消对user的关注 105 | f = self.followed.filter_by(followed_id=user.id).first() # 从该用户关注的其它用户中找出followed_id=user.id的用户 106 | if f is not None: 107 | db.session.delete(f) 108 | db.session.commit() 109 | 110 | def is_following(self, user): # 是否关注该user 111 | return self.followed.filter_by(followed_id=user.id).first() is not None 112 | 113 | def is_followed_by(self, user): # 是否被user关注 114 | return self.followers.filter_by(follower_id=user.id).first() is not None 115 | 116 | @property 117 | def followed_posts(self): # 列出该用户关注的所有文章 118 | return Post.query.join(Follow, Follow.followed_id == Post.author_id)\ 119 | .filter(Follow.follower_id == self.id) 120 | 121 | 122 | def can(self, permissions): # 检查用户的权限 123 | return self.itsrole is not None and \ 124 | (self.itsrole.permissions & permissions) == permissions 125 | 126 | def is_administrator(self): # 检查是否为管理者 127 | return self.can(Permission.ADMINISTRATOR) 128 | 129 | def ping(self): 130 | self.last_seen = datetime.utcnow() # 刷新上次访问时间 131 | db.session.add(self) 132 | db.session.commit() 133 | 134 | def gravatar(self, size=100, default='identicon', rating='g'): 135 | if request.is_secure: 136 | url = 'https://secure.gravatar.com/avatar' 137 | else: 138 | url = 'http://www.gravatar.com/avatar' 139 | hash = hashlib.md5(self.email.encode('utf-8')).hexdigest() 140 | return '{url}/{hash}?s={size}&r={rating}&d={default}'.format(url=url, hash=hash, 141 | size=size, rating=rating, 142 | default=default) 143 | 144 | @property # 试图读取password的值,返回错误, 因为password已经不可能恢复了 145 | def password(self): 146 | raise AttributeError('password is not a readable attribute') 147 | 148 | @password.setter # 设置password属性的值时,赋值函数会调用generate_password_hash函数 149 | def password(self, password): 150 | self.password_hash = generate_password_hash(password) 151 | 152 | def verify_password(self, password): 153 | return check_password_hash(self.password_hash, password) 154 | 155 | def generate_confirm_token(self, expiration=3600): 156 | s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) 157 | return s.dumps({'confirm': self.id}) # 返回一个token 158 | 159 | def confirm(self, token): 160 | s = Serializer(current_app.config['SECRET_KEY']) 161 | try: 162 | data = s.loads(token) 163 | except: 164 | return False 165 | if data.get('confirm') != self.id: 166 | return False 167 | self.confirmed = True 168 | db.session.add(self) # 把confirmed字段更新到数据库中,但是还没有提交 169 | db.session.commit() 170 | return True 171 | 172 | # 产生虚拟用户 173 | @staticmethod 174 | def generate_fake(count=10): 175 | from sqlalchemy.exc import IntegrityError 176 | from random import seed 177 | import forgery_py 178 | 179 | seed() 180 | for i in range(count): 181 | u = User(email=forgery_py.internet.email_address(), 182 | username=forgery_py.internet.user_name(True), 183 | password=forgery_py.lorem_ipsum.word(), 184 | confirmed=True, 185 | name=forgery_py.name.full_name(), 186 | location=forgery_py.address.city(), 187 | about_me=forgery_py.lorem_ipsum.sentence(), 188 | member_since=forgery_py.date.date(True)) 189 | db.session.add(u) 190 | try: 191 | db.session.commit() 192 | except IntegrityError: 193 | db.session.rollback() 194 | 195 | @staticmethod # 自己关注自己 196 | def add_self_follows(): 197 | for user in User.query.all(): 198 | if not user.is_following(user): 199 | user.follow(user) 200 | db.session.add(user) 201 | db.session.commit() 202 | 203 | def generate_auth_token(self, expiration=3600): 204 | s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) 205 | return s.dumps({'id': self.id}) 206 | 207 | @staticmethod 208 | def verify_auth_token(token): 209 | s = Serializer(current_app.config['SECRET_KEY']) 210 | try: 211 | data = s.loads(token) 212 | except: 213 | return None 214 | return User.query.get(data['id']) 215 | 216 | 217 | 218 | class Comment(db.Model): 219 | __tablename__ = 'comments' 220 | id = db.Column(db.Integer, primary_key=True) 221 | body = db.Column(db.Text) 222 | body_html = db.Column(db.Text) 223 | timestamp = db.Column(db.DateTime, default=datetime.utcnow) 224 | disabled = db.Column(db.Boolean) 225 | post_id = db.Column(db.Integer, db.ForeignKey('posts.id')) 226 | author_id = db.Column(db.Integer, db.ForeignKey('users.id')) 227 | 228 | @staticmethod # 这个为静态方法是因为客户端不能指定评论所属博客和作者,只有服务器可以指定为当前用户 229 | def from_json(json_body): 230 | body = json_body.get('body') 231 | if body is None or body == '': 232 | print 'error' 233 | return Comment(body=body) 234 | 235 | def to_json(self): 236 | comment_json = { 237 | 'url': url_for('api.get_comment', id=self.id, _external=True), 238 | 'body': self.body, 239 | 'body_html': self.body_html, 240 | 'timestamp': self.timestamp 241 | } 242 | return comment_json 243 | 244 | @staticmethod 245 | def on_body_changed(target, value, oldvalue, initiator): 246 | allow_tags = ['a', 'abbr', 'acronym', 'b', 'code', 247 | 'em', 'strong'] 248 | target.body_html = bleach.linkify(bleach.clean(markdown(value, output_format='html'), 249 | tags=allow_tags, strip=True)) 250 | 251 | class AnonymousUser(AnonymousUserMixin): # 匿名用户 252 | def can(self, permissions): 253 | return False 254 | 255 | def is_administrator(self): 256 | return False 257 | 258 | class Post(db.Model): 259 | __tablename__ = 'posts' 260 | id = db.Column(db.Integer, primary_key=True) 261 | title = db.Column(db.Text) 262 | body = db.Column(db.Text) 263 | body_html = db.Column(db.Text) # 服务器上的富文本处理字段 264 | timestamp = db.Column(db.DateTime, default=datetime.utcnow) 265 | author_id = db.Column(db.Integer, db.ForeignKey('users.id')) 266 | comments = db.relationship('Comment', backref='post', lazy='dynamic') 267 | 268 | @staticmethod # 这个为静态方法是因为客户端不能指定文章作者,只有服务器可以指定为当前用户 269 | def from_json(json_body): 270 | title = json_body.get('title') 271 | body = json_body.get('body') 272 | if body is None or body == '': 273 | print 'error' 274 | return Post(title=title, body=body) 275 | 276 | def to_json(self): 277 | json_post = { 278 | 'url': url_for('api.get_post', id=self.id, _external=True), 279 | 'title': self.title, 280 | 'body': self.body, 281 | 'body_html': self.body_html, 282 | 'timestamp': self.timestamp, 283 | 'comment_count': self.comments.count() 284 | } 285 | return json_post 286 | 287 | @staticmethod 288 | def generate_fake(count=10): 289 | from random import seed, randint 290 | import forgery_py 291 | 292 | seed() 293 | user_count = User.query.count() 294 | for i in range(count): 295 | u = User.query.offset(randint(0, user_count-1)).first() 296 | p = Post(title=forgery_py.lorem_ipsum.sentence(), 297 | body=forgery_py.lorem_ipsum.sentences(randint(1,3)), 298 | timestamp=forgery_py.date.date(True), 299 | author=u) 300 | db.session.add(p) 301 | db.session.commit() 302 | 303 | @staticmethod # 给所有发表博客文章添加标题 304 | def generate_title(): 305 | from random import seed 306 | import forgery_py 307 | 308 | seed() 309 | posts = Post.query.all() 310 | for post in posts: 311 | if post.title is None: 312 | post.title = forgery_py.lorem_ipsum.sentence() 313 | db.session.add(post) 314 | db.session.commit() 315 | 316 | @staticmethod 317 | def on_body_changed(target, value, oldvalue, initiator): 318 | allow_tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 319 | 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 320 | 'h1', 'h2', 'h3', 'p', 'span', 'code', 'pre', 321 | 'img', 'hr', 'div'] 322 | allow_attributes = ['src', 'alt', 'href', 'class'] 323 | target.body_html = bleach.linkify(bleach.clean(markdown(value, output_format='html',extensions=['markdown.extensions.extra','markdown.extensions.codehilite']), 324 | tags=allow_tags, attributes=allow_attributes, strip=True)) 325 | 326 | 327 | @login_manager.user_loader # 加载用户的回调函数,成功后得到当前用户 328 | def load_user(user_id): 329 | return User.query.get(int(user_id)) 330 | 331 | login_manager.anonymous_user = AnonymousUser # 将其设为用户未登陆时的current_user的值 332 | 333 | db.event.listen(Post.body, 'set', Post.on_body_changed) 334 | db.event.listen(Comment.body, 'set', Comment.on_body_changed) -------------------------------------------------------------------------------- /app/static/bootstrap-material-design.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["bootstrap-material-design.css","/less/_core.less","/less/_form.less","/less/_welljumbo.less","/less/_shadows.less","/less/_mixins.less","/less/_buttons.less","/less/_checkboxes.less","/less/_togglebutton.less","/less/_radios.less","/less/_inputs-size.less","/less/_inputs.less","/less/_lists.less","/less/_navbar.less","/less/_alerts.less","/less/_progress.less","/less/_typography.less","/less/_tabs.less","/less/_popups.less","/less/_cards.less","/less/_dialogs.less","/less/_panels.less","/less/_dividers.less","/less/plugins/_plugin-snackbarjs.less","/less/plugins/_plugin-nouislider.less","/less/plugins/_plugin-selectize.less","/less/plugins/_plugin-dropdownjs.less"],"names":[],"mappings":"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;;;;EQuNM,+BAAA;Cbw2DP;AK9jEC;;;;EQsNM,+BAAA;Cb82DP;AKnkEC;;;;EQqNM,+BAAA;Cbo3DP;AK7hEC;;EQ6KI,mBAAA;Cbo3DL;Aa92DK;EAwCN;;IA3CU,0BAAA;Gbs3DP;CACF;AKviEC;;EQoLM,gBAAA;EACA,mBAAA;Cbu3DP;Aat3DO;;;;EAEE,eAAA;EACA,0BAAA;Cb03DT;AKnjEC;;EQiMM,0BAAA;EACA,+BAAA;Cbs3DP;Aa33DO;;;;EAEE,+BAAA;Cb+3DT;AKxjEC;EQ6JE,0BAAA;EACA,eAAA;Cb85DH;AKhnEC;;EQuNM,eAAA;Cb65DP;AKnnEC;;EQsNM,eAAA;Cbi6DP;AKtnEC;;EQqNM,eAAA;Cbq6DP;AKxkEC;EQuKI,mBAAA;Cbo6DL;Aa95DK;EAwCN;IA3CU,0BAAA;Gbq6DP;CACF;AKhlEC;EQ8KM,gBAAA;EACA,mBAAA;Cbq6DP;Aap6DO;;EAEE,eAAA;EACA,0BAAA;Cbs6DT;AKzlEC;EQ2LM,0BAAA;EACA,eAAA;Cbi6DP;Aat6DO;;EAEE,eAAA;Cbw6DT;AK3lEC;EQuJE,0BAAA;EACA,+BAAA;Cbu8DH;AKzpEC;;EQuNM,+BAAA;Cbs8DP;AK5pEC;;EQsNM,+BAAA;Cb08DP;AK/pEC;;EQqNM,+BAAA;Cb88DP;AK3mEC;EQiKI,mBAAA;Cb68DL;Aav8DK;EAwCN;IA3CU,0BAAA;Gb88DP;CACF;AKnnEC;EQwKM,gBAAA;EACA,mBAAA;Cb88DP;Aa78DO;;EAEE,eAAA;EACA,0BAAA;Cb+8DT;AK5nEC;EQqLM,0BAAA;EACA,+BAAA;Cb08DP;Aa/8DO;;EAEE,+BAAA;Cbi9DT;AK/nEC;EQkJE,0BAAA;EACA,+BAAA;Cbg/DH;AKlsEC;;EQuNM,+BAAA;Cb++DP;AKrsEC;;EQsNM,+BAAA;Cbm/DP;AKxsEC;;EQqNM,+BAAA;Cbu/DP;AK/oEC;EQ4JI,mBAAA;Cbs/DL;Aah/DK;EAwCN;IA3CU,0BAAA;Gbu/DP;CACF;AKvpEC;EQmKM,gBAAA;EACA,mBAAA;Cbu/DP;Aat/DO;;EAEE,eAAA;EACA,0BAAA;Cbw/DT;AKhqEC;EQgLM,0BAAA;EACA,+BAAA;Cbm/DP;Aax/DO;;EAEE,+BAAA;Cb0/DT;AKnqEC;EQ6IE,0BAAA;EACA,+BAAA;CbyhEH;AK3uEC;;EQuNM,+BAAA;CbwhEP;AK9uEC;;EQsNM,+BAAA;Cb4hEP;AKjvEC;;EQqNM,+BAAA;CbgiEP;AKnrEC;EQuJI,mBAAA;Cb+hEL;AazhEK;EAwCN;IA3CU,0BAAA;GbgiEP;CACF;AK3rEC;EQ8JM,gBAAA;EACA,mBAAA;CbgiEP;Aa/hEO;;EAEE,eAAA;EACA,0BAAA;CbiiET;AKpsEC;EQ2KM,0BAAA;EACA,+BAAA;Cb4hEP;AajiEO;;EAEE,+BAAA;CbmiET;AKvsEC;EQwIE,0BAAA;EACA,+BAAA;CbkkEH;AKpxEC;;EQuNM,+BAAA;CbikEP;AKvxEC;;EQsNM,+BAAA;CbqkEP;AK1xEC;;EQqNM,+BAAA;CbykEP;AKvtEC;EQkJI,mBAAA;CbwkEL;AalkEK;EAwCN;IA3CU,0BAAA;GbykEP;CACF;AK/tEC;EQyJM,gBAAA;EACA,mBAAA;CbykEP;AaxkEO;;EAEE,eAAA;EACA,0BAAA;Cb0kET;AKxuEC;EQsKM,0BAAA;EACA,+BAAA;CbqkEP;Aa1kEO;;EAEE,+BAAA;Cb4kET;AK3uEC;EQmIE,0BAAA;EACA,+BAAA;Cb2mEH;AK7zEC;;EQuNM,+BAAA;Cb0mEP;AKh0EC;;EQsNM,+BAAA;Cb8mEP;AKn0EC;;EQqNM,+BAAA;CbknEP;AK3vEC;EQ6II,mBAAA;CbinEL;Aa3mEK;EAwCN;IA3CU,0BAAA;GbknEP;CACF;AKnwEC;EQoJM,gBAAA;EACA,mBAAA;CbknEP;AajnEO;;EAEE,eAAA;EACA,0BAAA;CbmnET;AK5wEC;EQiKM,0BAAA;EACA,+BAAA;Cb8mEP;AannEO;;EAEE,+BAAA;CbqnET;Aa7mEC;EACE,0BAAA;Cb+mEH;Aa7lED;EACA;IAbM,aAAA;IACA,mBAAA;Gb6mEH;EajmEH;IATM,iBAAA;Gb6mEH;EapmEH;IALM,kBAAA;IACA,qBAAA;Gb4mEH;CACF;AC/zED;EACE,UAAA;EACA,oDAAA;UAAA,4CAAA;CDi0ED;ACn0ED;EAII,sCAAA;CDk0EH;ACt0ED;EAOI,iBAAA;EACA,mBAAA;CDk0EH;AC10ED;EAUM,8BAAA;EACA,eAAA;CDm0EL;Acn4ED;EACI,UAAA;EACA,iBAAA;Cdq4EH;AKv1EC;;ES1CM,0CAAA;EACA,+BAAA;Cdq4EP;AK51EC;;;;EStCU,+BAAA;Cdw4EX;AK51EC;EShDM,0BAAA;EACA,eAAA;Cd+4EP;AKh2EC;;ES5CU,eAAA;Cdg5EX;AK91EC;EStDM,0BAAA;EACA,+BAAA;Cdu5EP;AKl2EC;;ESlDU,+BAAA;Cdw5EX;AKj2EC;ES3DM,0BAAA;EACA,+BAAA;Cd+5EP;AKr2EC;;ESvDU,+BAAA;Cdg6EX;AKp2EC;EShEM,0BAAA;EACA,+BAAA;Cdu6EP;AKx2EC;;ES5DU,+BAAA;Cdw6EX;AKv2EC;ESrEM,0BAAA;EACA,+BAAA;Cd+6EP;AK32EC;;ESjEU,+BAAA;Cdg7EX;AK12EC;ES1EM,0BAAA;EACA,+BAAA;Cdu7EP;AK92EC;;EStEU,+BAAA;Cdw7EX;Acp7EG;;;;EACI,+BAAA;Cdy7EP;Act7EG;;EAEQ,yBAAA;Cdw7EX;Ae58ED;EACI,YAAA;EACA,iBAAA;EACA,yBAAA;UAAA,iBAAA;EACA,oBAAA;Cf88EH;Ael9ED;EAMQ,yBAAA;UAAA,iBAAA;Cf+8EP;AKr6EC;;EArCE,0BAAA;CL88EH;AKn6EC;EA3CE,0BAAA;CLi9EH;AKh6EC;EAjDE,0BAAA;CLo9EH;AK95EC;EAtDE,0BAAA;CLu9EH;AK55EC;EA3DE,0BAAA;CL09EH;AK15EC;EAhEE,0BAAA;CL69EH;AKx5EC;EArEE,0BAAA;CLg+EH;AgB3+ED;EACE,eAAA;ChB6+ED;AgB3+ED;EACE,eAAA;ChB6+ED;AgB3+ED;EACE,eAAA;ChB6+ED;AgB3+ED;EACE,eAAA;ChB6+ED;AgB3+ED;EACE,eAAA;ChB6+ED;AiB1/ED;EACI,oBAAA;CjB4/EH;AiB7/ED;EAIY,eAAA;EACA,UAAA;EACA,UAAA;CjB4/EX;AiB3/EW;EACI,8BAAA;EACA,UAAA;CjB6/Ef;AiB1/EO;;;EACI,yCAAA;EACA,qBAAA;EACA,0BAAA;EACA,iBAAA;CjB8/EX;AiB5/EO;;EACI,gCAAA;CjB+/EX;AkBlhFD;;EACE,eAAA;EACA,iBAAA;EACA,qCAAA;EACA,aAAA;EACA,mBAAA;EdJA,qFAAA;UAAA,6EAAA;CJ0hFD;AkBlhFD;;EACE,WAAA;ClBqhFD;AkBlhFD;;;;EAEI,cAAA;ClBshFH;AmBriFD;EnBuiFE,4EAA4E;EmBniF1E,sBAAA;EACA,mBAAA;EACA,YAAA;EnBqiFF,4EAA4E;EmBthF1E,mBAAA;EACA,yBAAA;EACA,iBAAA;EfVF,sFAAA;UAAA,8EAAA;CJmiFD;AmBhjFD;EAQQ,iBAAA;CnB2iFP;AmBnjFD;EAWQ,mBAAA;EACA,OAAA;EACA,UAAA;EACA,QAAA;EACA,SAAA;CnB2iFP;AmB1jFD;EA4BQ,YAAA;EACA,mBAAA;EACA,iBAAA;CnBiiFP;AmB/jFD;EAgCY,YAAA;EACA,aAAA;EACA,4BAAA;EACA,6BAAA;EACA,qBAAA;CnBkiFX;AmBtkFD;EAuCY,mBAAA;EACA,aAAA;EACA,WAAA;EACA,YAAA;EACA,eAAA;CnBkiFX;AmB7kFD;EAgDQ,YAAA;EACA,cAAA;CnBgiFP;AmBjlFD;EAqDQ,YAAA;EACA,cAAA;CnB+hFP;AmBrlFD;;EAwDY,qBAAA;EACA,mBAAA;EACA,aAAA;EACA,YAAA;CnBiiFX;AmBhiFW;;EACI,YAAA;CnBmiFf;AoB5lFD;EhB2BE,wFAAA;UAAA,gFAAA;EgBzBA,mBAAA;EACA,aAAA;CpB8lFD;AoBjmFD;EAOI,oBAAA;EACA,kBAAA;EACA,oBAAA;EACA,kBAAA;EACA,mBAAA;CpB6lFH;AoBxmFD;EAgBI,kBAAA;EACA,oBAAA;EACA,qBAAA;EACA,mBAAA;CpB2lFH;AoB9mFD;EAuBI,iBAAA;EACA,aAAA;CpB0lFH;AoBlnFD;EA0BM,UAAA;EACA,mBAAA;EACA,oBAAA;EACA,YAAA;CpB2lFL;AoB1lFK;EACE,kBAAA;EACA,mBAAA;EACA,mBAAA;EACA,WAAA;CpB4lFP;AoB9nFD;EAsCM,oBAAA;CpB2lFL;AoBjoFD;EA0CI,eAAA;CpB0lFH;AoBvlFD;EACE,+BAAA;CpBylFD;AqB3oFD;EACE,mBAAA;EACA,UAAA;EjBDA,qFAAA;UAAA,6EAAA;CJ+oFD;AKhmFC;;EArCE,0BAAA;CLyoFH;AK9lFC;EA3CE,0BAAA;CL4oFH;AK3lFC;EAjDE,0BAAA;CL+oFH;AKzlFC;EAtDE,0BAAA;CLkpFH;AKvlFC;EA3DE,0BAAA;CLqpFH;AKrlFC;EAhEE,0BAAA;CLwpFH;AKnlFC;EArEE,0BAAA;CL2pFH;AqB7pFD;EACE,+BAAA;EACA,UAAA;CrB+pFD;AqB7pFD;;EAEI,yBAAA;CrB+pFH;AqB5pFD;EACE,0BAAA;CrB8pFD;AsBhrFC;EACE,eAAA;CtBkrFH;AsB/qFC;EACE,eAAA;CtBirFH;AsBrqFC;EAqDF;IAxDM,eAAA;GtB4qFH;CACF;AsBlqFC;EA6CF;IA/CM,YAAA;GtBwqFH;CACF;AsB/pFC;EAqCF;IAvCM,gBAAA;GtBqqFH;CACF;AsB3pFC;EA4BF;IA/BM,cAAA;GtBkqFH;CACF;AsBvpFC;EAmBF;IAtBM,YAAA;GtB8pFH;CACF;AsBnpFC;EAUF;IAbM,YAAA;GtB0pFH;CACF;AsB/oFD;EACA;IAJM,YAAA;GtBspFH;CACF;AC1oFD;EACE,oDAAA;EACA,yCAAA;CD4oFD;AC3oFC;EACE,WAAA;CD6oFH;AuB9tFD;EAEI,0BAAA;EACA,+BAAA;EACA,gBAAA;EACA,mBAAA;EnBPF,qFAAA;UAAA,6EAAA;EmBWE,UAAA;EACA,mJAAA;OAAA,yIAAA;UAAA,mIAAA;EACA,oCAAA;MAAA,gCAAA;OAAA,+BAAA;UAAA,4BAAA;CvB6tFH;AuB1tFD;EAEI,mBAAA;EACA,oBAAA;EAGA,aAAA;EACA,2HAAA;OAAA,iHAAA;UAAA,2GAAA;EACA,wBAAA;MAAA,oBAAA;OAAA,mBAAA;UAAA,gBAAA;CvBytFH;AuBrtFD;EACI,qBAAA;CvButFH;AwBrvFD;;EAEI,4BAAA;EACA,uBAAA;EACA,0BAAA;KAAA,uBAAA;MAAA,sBAAA;UAAA,kBAAA;EACA,+BAAA;KAAA,4BAAA;UAAA,uBAAA;CxBuvFH;AwBrvFD;EACI,YAAA;EACA,aAAA;EACA,mBAAA;CxBuvFH;AwBrvFD;EACI,mBAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;CxBuvFH;AwBrvFD;EACI,mBAAA;EACA,WAAA;EACA,+BAAA;KAAA,4BAAA;UAAA,uBAAA;CxBuvFH;AwBrvFD;EACI,YAAA;CxBuvFH;AwBlvFD;EACI,wCAAA;OAAA,mCAAA;UAAA,gCAAA;CxBovFH;AwBlvFD;EACI,2BAAA;CxBovFH;AwBlvFD;EACI,aAAA;CxBovFH;AwBlvFD;EACI,+BAAA;KAAA,4BAAA;UAAA,uBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,UAAA;EACA,kBAAA;EACA,oBAAA;EACA,sCAAA;OAAA,iCAAA;UAAA,8BAAA;EACA,kBAAA;CxBovFH;AwBlvFD;EACI,iBAAA;EACA,kBAAA;CxBovFH;AwBlvFD;EACI,gBAAA;CxBovFH;AwBlvFD;EACI,aAAA;CxBovFH;AwBlvFD;EACI,YAAA;EACA,eAAA;CxBovFH;AwBlvFD;EACI,UAAA;EACA,iBAAA;EACA,YAAA;EACA,oBAAA;CxBovFH;AwBnvFG;EACI,uBAAA;EACA,0BAAA;CxBqvFP;AwBpvFO;EACI,kBAAA;CxBsvFX;AwBlvFD;EACI,mBAAA;CxBovFH;AwBlvFD;EACI,YAAA;EACA,eAAA;CxBovFH;AwBlvFD;EACI,aAAA;EACA,WAAA;EACA,eAAA;EACA,sBAAA;CxBovFH;AwBlvFD;EACI,wCAAA;UAAA,gCAAA;CxBovFH;AwBlvFD;EACI,aAAA;CxBovFH;AwBlvFD;EACI,oBAAA;CxBovFH;AwBjvFD;EACI,oBAAA;CxBmvFH;AKxyFC;;EArCE,0BAAA;CLi1FH;AKtyFC;EA3CE,0BAAA;CLo1FH;AKnyFC;EAjDE,0BAAA;CLu1FH;AKjyFC;EAtDE,0BAAA;CL01FH;AK/xFC;EA3DE,0BAAA;CL61FH;AK7xFC;EAhEE,0BAAA;CLg2FH;AK3xFC;EArEE,0BAAA;CLm2FH;AK9zFC;;EArCE,0BAAA;CLu2FH;AK5zFC;EA3CE,0BAAA;CL02FH;AKzzFC;EAjDE,0BAAA;CL62FH;AKvzFC;EAtDE,0BAAA;CLg3FH;AKrzFC;EA3DE,0BAAA;CLm3FH;AKnzFC;EAhEE,0BAAA;CLs3FH;AKjzFC;EArEE,0BAAA;CLy3FH;AKp1FC;;EArCE,0BAAA;CL63FH;AKl1FC;EA3CE,0BAAA;CLg4FH;AK/0FC;EAjDE,0BAAA;CLm4FH;AK70FC;EAtDE,0BAAA;CLs4FH;AK30FC;EA3DE,0BAAA;CLy4FH;AKz0FC;EAhEE,0BAAA;CL44FH;AKv0FC;EArEE,0BAAA;CL+4FH;AK12FC;;EArCE,sBAAA;CLm5FH;AKx2FC;EA3CE,sBAAA;CLs5FH;AKr2FC;EAjDE,sBAAA;CLy5FH;AKn2FC;EAtDE,sBAAA;CL45FH;AKj2FC;EA3DE,sBAAA;CL+5FH;AK/1FC;EAhEE,sBAAA;CLk6FH;AK71FC;EArEE,sBAAA;CLq6FH;AyB76FD;;EACI,WAAA;CzBg7FH;AyBj7FD;;;;EAIQ,aAAA;EACA,wBAAA;EACA,yBAAA;UAAA,iBAAA;EACA,UAAA;EACA,WAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;CzBm7FP;AyB97FD;;;;EAaY,WAAA;CzBu7FX;AyBr7FO;;;;EACI,WAAA;EACA,mBAAA;EACA,gBAAA;EACA,iBAAA;EACA,8BAAA;EACA,YAAA;EACA,mBAAA;EACA,oBAAA;EACA,qBAAA;EACA,qBAAA;EACA,eAAA;EACA,oCAAA;EACA,mCAAA;CzB07FX;AyBt9FD;;;;EA+BY,gBAAA;EACA,WAAA;EACA,UAAA;EACA,wBAAA;CzB67FX;AyB37FO;;;;EACI,WAAA;CzBg8FX;AyBr+FD;;;;;;;;EAwCY,sBAAA;EACA,oBAAA;EACA,WAAA;EACA,wBAAA;EACA,UAAA;CzBu8FX;AyBt8FW;;;;;;;;EACI,aAAA;CzB+8Ff;AyB78FW;;;;;;;;EACI,YAAA;CzBs9Ff;AyBp9FW;;;;;;;;EACI,kBAAA;EACA,wBAAA;EACA,UAAA;CzB69Ff;AyBnhGD;;EA2DQ,mBAAA;EACA,cAAA;EACA,UAAA;EACA,uBAAA;EACA,mBAAA;EACA,aAAA;EACA,uBAAA;EACA,iFAAA;UAAA,yEAAA;EACA,mBAAA;EACA,WAAA;EACA,gBAAA;CzB49FP;AyBjiGD;;EAuEY,0BAAA;CzB89FX;AyBriGD;;EA0EY,0BAAA;CzB+9FX;AyBziGD;;;;EA6EY,0BAAA;CzBk+FX;AyB/iGD;;;;EAgFY,mBAAA;EACA,gBAAA;CzBq+FX;AyBtjGD;;EAqFQ,eAAA;CzBq+FP;A0B7jGD;EACE,WAAA;EACA,SAAA;EACA,gBAAA;EACA,mBAAA;EAGA,8BAAA;EACA,mBAAA;EACA,iBAAA;EACA,iBAAA;EAEA,qBAAA;EACA,eAAA;C1B4jGD","file":"bootstrap-material-design.css"} -------------------------------------------------------------------------------- /app/static/bootstrap-material-design.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/_core.less","less/_form.less","less/_welljumbo.less","less/_shadows.less","less/_mixins.less","less/_buttons.less","less/_checkboxes.less","dist/css/bootstrap-material-design.css","bootstrap-material-design.css","less/_togglebutton.less","less/_radios.less","less/_inputs-size.less","less/_inputs.less","less/_lists.less","less/_navbar.less","less/_alerts.less","less/_progress.less","less/_typography.less","less/_tabs.less","less/_popups.less","less/_cards.less","less/_dialogs.less","less/_panels.less","less/_dividers.less","less/plugins/_plugin-snackbarjs.less","less/plugins/_plugin-nouislider.less","less/plugins/_plugin-selectize.less"],"names":[],"mappings":"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AAS,KAAK,KO9qEN,iDPgrEV,iDCjTC,MAAA,QJxjEC,iBAAA,KU8JE,gDN85DH,iBAAA,QJhnEC,MAAA,sBIonED,sDM75DO,sDVtNN,MAAA,sBUsNM,uBNi6DP,iBAAA,QJtnEC,MAAA,sBUqNM,qFNq6DP,yEJxkEC,MAAA,sBI2kED,yFM95DK,6EAwCJ,MAAO,sBN03DN,8FACF,kFJhlEC,MAAA,sBU+KM,sCNq6DP,cAAA,IDqTD,yBOvtEU,uDACA,iBAAA,SAQF,2CACA,UAAA,KNi6DP,QAAA,KAAA,KMp6DS,iDPytEV,iDCjTC,MAAA,QJ3lEC,iBAAA,KUwJE,gDNu8DH,iBAAA,QJzpEC,MAAA,sBI6pED,sDMt8DO,sDVtNN,MAAA,sBUsNM,oBN08DP,iBAAA,QJ/pEC,MAAA,sBUqNM,kFN88DP,sEJ3mEC,MAAA,sBI8mED,sFMv8DK,0EAwCJ,MAAO,sBNm6DN,2FACF,+EJnnEC,MAAA,sBUyKM,mCN88DP,cAAA,IDqTD,yBOhwEU,oDACA,iBAAA,SAQF,wCACA,UAAA,KN08DP,QAAA,KAAA,KM78DS,8CPkwEV,8CCjTC,MAAA,QJ/nEC,iBAAA,KUmJE,6CNg/DH,iBAAA,QJlsEC,MAAA,sBIssED,mDM/+DO,mDVtNN,MAAA,sBUsNM,uBNm/DP,iBAAA,QJxsEC,MAAA,sBUqNM,qFNu/DP,yEJ/oEC,MAAA,sBIkpED,yFMh/DK,6EAwCJ,MAAO,sBN48DN,8FACF,kFJvpEC,MAAA,sBUoKM,sCNu/DP,cAAA,IDqTD,yBOzyEU,uDACA,iBAAA,SAQF,2CACA,UAAA,KNm/DP,QAAA,KAAA,KMt/DS,iDP2yEV,iDCjTC,MAAA,QJnqEC,iBAAA,KU8IE,gDNyhEH,iBAAA,QJ3uEC,MAAA,sBI+uED,sDMxhEO,sDVtNN,MAAA,sBUsNM,sBN4hEP,iBAAA,QJjvEC,MAAA,sBUqNM,oFNgiEP,wEJnrEC,MAAA,sBIsrED,wFMzhEK,4EAwCJ,MAAO,sBNq/DN,6FACF,iFJ3rEC,MAAA,sBU+JM,qCNgiEP,cAAA,IDqTD,yBOl1EU,sDACA,iBAAA,SAQF,0CACA,UAAA,KN4hEP,QAAA,KAAA,KM/hES,gDPo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"} -------------------------------------------------------------------------------- /app/static/codehilite.css: -------------------------------------------------------------------------------- 1 | .hll { background-color: #ffffcc } 2 | .c { color: #408080; font-style: italic } /* Comment */ 3 | .err { border: 1px solid #FF0000 } /* Error */ 4 | .k { color: #008000; font-weight: bold } /* Keyword */ 5 | .o { color: #666666 } /* Operator */ 6 | .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ 7 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 8 | .cp { color: #BC7A00 } /* Comment.Preproc */ 9 | .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ 10 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 11 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 12 | .gd { color: #A00000 } /* Generic.Deleted */ 13 | .ge { font-style: italic } /* Generic.Emph */ 14 | .gr { color: #FF0000 } /* Generic.Error */ 15 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 16 | .gi { color: #00A000 } /* Generic.Inserted */ 17 | .go { color: #888888 } /* Generic.Output */ 18 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 19 | .gs { font-weight: bold } /* Generic.Strong */ 20 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 21 | .gt { color: #0044DD } /* Generic.Traceback */ 22 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 23 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 24 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 25 | .kp { color: #008000 } /* Keyword.Pseudo */ 26 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 27 | .kt { color: #B00040 } /* Keyword.Type */ 28 | .m { color: #666666 } /* Literal.Number */ 29 | .s { color: #BA2121 } /* Literal.String */ 30 | .na { color: #7D9029 } /* Name.Attribute */ 31 | .nb { color: #008000 } /* Name.Builtin */ 32 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 33 | .no { color: #880000 } /* Name.Constant */ 34 | .nd { color: #AA22FF } /* Name.Decorator */ 35 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 36 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 37 | .nf { color: #0000FF } /* Name.Function */ 38 | .nl { color: #A0A000 } /* Name.Label */ 39 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 40 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 41 | .nv { color: #19177C } /* Name.Variable */ 42 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 43 | .w { color: #bbbbbb } /* Text.Whitespace */ 44 | .mb { color: #666666 } /* Literal.Number.Bin */ 45 | .mf { color: #666666 } /* Literal.Number.Float */ 46 | .mh { color: #666666 } /* Literal.Number.Hex */ 47 | .mi { color: #666666 } /* Literal.Number.Integer */ 48 | .mo { color: #666666 } /* Literal.Number.Oct */ 49 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 50 | .sc { color: #BA2121 } /* Literal.String.Char */ 51 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 52 | .s2 { color: #BA2121 } /* Literal.String.Double */ 53 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 54 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 55 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 56 | .sx { color: #008000 } /* Literal.String.Other */ 57 | .sr { color: #BB6688 } /* Literal.String.Regex */ 58 | .s1 { color: #BA2121 } /* Literal.String.Single */ 59 | .ss { color: #19177C } /* Literal.String.Symbol */ 60 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 61 | .vc { color: #19177C } /* Name.Variable.Class */ 62 | .vg { color: #19177C } /* Name.Variable.Global */ 63 | .vi { color: #19177C } /* Name.Variable.Instance */ 64 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 65 | -------------------------------------------------------------------------------- /app/static/index.js: -------------------------------------------------------------------------------- 1 | require("./material.js"); 2 | require("./ripples.js"); -------------------------------------------------------------------------------- /app/static/jquery.dropdown.css: -------------------------------------------------------------------------------- 1 | .dropdownjs { 2 | position: relative; 3 | } 4 | .dropdownjs * { 5 | box-sizing: border-box; 6 | } 7 | .dropdownjs > input { 8 | width: 100%; 9 | padding-right: 30px; 10 | text-overflow: ellipsis; 11 | } 12 | .dropdownjs > input.focus ~ ul { 13 | -webkit-transform: scale(1); 14 | -ms-transform: scale(1); 15 | transform: scale(1); 16 | } 17 | .dropdownjs > ul { 18 | position: absolute; 19 | padding: 0; 20 | margin: 0; 21 | min-width: 200px; 22 | -webkit-transform: scale(0); 23 | -ms-transform: scale(0); 24 | transform: scale(0); 25 | z-index: 10000; 26 | } 27 | .dropdownjs > ul[placement=top-left] { 28 | -webkit-transform-origin: bottom left; 29 | -ms-transform-origin: bottom left; 30 | transform-origin: bottom left; 31 | bottom: 0; 32 | left: 0; 33 | } 34 | .dropdownjs > ul[placement=bottom-left] { 35 | -webkit-transform-origin: top left; 36 | -ms-transform-origin: top left; 37 | transform-origin: top left; 38 | top: 0; 39 | left: 0; 40 | } 41 | .dropdownjs > ul > li { 42 | list-style: none; 43 | padding: 10px 20px; 44 | } 45 | .dropdownjs > ul > li.dropdownjs-add { 46 | padding: 0; 47 | } 48 | .dropdownjs > ul > li.dropdownjs-add > input { 49 | border: 0; 50 | padding: 10px 20px; 51 | width: 100%; 52 | } 53 | 54 | /* Theme */ 55 | .dropdownjs > input[readonly] { 56 | cursor: pointer; 57 | } 58 | select[data-dropdownjs][disabled] + .dropdownjs > input[readonly] { 59 | cursor: default; 60 | } 61 | .dropdownjs > ul { 62 | background: #FFF; 63 | box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 6px rgba(0, 0, 0, 0.12); 64 | -webkit-transition: -webkit-transform 0.2s ease-out; 65 | transition: transform 0.2s ease-out; 66 | padding: 10px; 67 | overflow: auto; 68 | max-width: 500px; 69 | } 70 | .dropdownjs > ul > li { 71 | cursor: pointer; 72 | word-wrap: break-word; 73 | } 74 | .dropdownjs > ul > li.selected, 75 | .dropdownjs > ul > li:active { 76 | background-color: #eaeaea; 77 | } 78 | .dropdownjs > ul > li:focus { 79 | outline: 0; 80 | outline: 1px solid #d4d4d4; 81 | } 82 | .dropdownjs > ul > li > .close:before { 83 | content: "\00d7"; 84 | display: block; 85 | position: absolute; 86 | right: 15px; 87 | float: right; 88 | font-size: 21px; 89 | font-weight: 700; 90 | line-height: 1; 91 | color: #000; 92 | text-shadow: 0 1px 0 #fff; 93 | opacity: .6; 94 | } 95 | .dropdownjs > ul > li:h > .close:hover:before { 96 | opacity: .9; 97 | } 98 | -------------------------------------------------------------------------------- /app/static/jquery.dropdown.js: -------------------------------------------------------------------------------- 1 | /* globals jQuery, window, document */ 2 | 3 | (function (factory) { 4 | if (typeof define === 'function' && define.amd) { 5 | // AMD. Register as an anonymous module. 6 | define(['jquery'], factory); 7 | } else if (typeof exports === 'object') { 8 | // Node/CommonJS 9 | module.exports = factory(require('jquery')); 10 | } else { 11 | // Browser globals 12 | factory(jQuery); 13 | } 14 | }(function($) { 15 | 16 | var methods = { 17 | options : { 18 | "optionClass": "", 19 | "dropdownClass": "", 20 | "autoinit": false, 21 | "callback": false, 22 | "onSelected": false, 23 | "destroy": function(element) { 24 | this.destroy(element); 25 | }, 26 | "dynamicOptLabel": "Add a new option..." 27 | }, 28 | init: function(options) { 29 | 30 | // Apply user options if user has defined some 31 | if (options) { 32 | options = $.extend(methods.options, options); 33 | } else { 34 | options = methods.options; 35 | } 36 | 37 | function initElement($select) { 38 | // Don't do anything if this is not a select or if this select was already initialized 39 | if ($select.data("dropdownjs") || !$select.is("select")) { 40 | return; 41 | } 42 | 43 | // Is it a multi select? 44 | var multi = $select.attr("multiple"); 45 | 46 | // Does it allow to create new options dynamically? 47 | var dynamicOptions = $select.attr("data-dynamic-opts"), 48 | $dynamicInput = $(); 49 | 50 | // Create the dropdown wrapper 51 | var $dropdown = $("
"); 52 | $dropdown.addClass("dropdownjs").addClass(options.dropdownClass); 53 | $dropdown.data("select", $select); 54 | 55 | // Create the fake input used as "select" element and cache it as $input 56 | var $input = $(""); 57 | if ($.material) { $input.data("mdproc", true); } 58 | // Append it to the dropdown wrapper 59 | $dropdown.append($input); 60 | 61 | // Create the UL that will be used as dropdown and cache it AS $ul 62 | var $ul = $("
    "); 63 | $ul.data("select", $select); 64 | 65 | // Append it to the dropdown 66 | $dropdown.append($ul); 67 | 68 | // Transfer the placeholder attribute 69 | $input.attr("placeholder", $select.attr("placeholder")); 70 | 71 | // Loop trough options and transfer them to the dropdown menu 72 | $select.find("option").each(function() { 73 | // Cache $(this) 74 | var $this = $(this); 75 | methods._addOption($ul, $this); 76 | 77 | }); 78 | 79 | // If this select allows dynamic options add the widget 80 | if (dynamicOptions) { 81 | $dynamicInput = $(""); 82 | $dynamicInput.append(""); 83 | $dynamicInput.find("input").attr("placeholder", options.dynamicOptLabel); 84 | $ul.append($dynamicInput); 85 | } 86 | 87 | 88 | 89 | // Cache the dropdown options 90 | var selectOptions = $dropdown.find("li"); 91 | 92 | // If is a single select, selected the first one or the last with selected attribute 93 | if (!multi) { 94 | var $selected; 95 | if ($select.find(":selected").length) { 96 | $selected = $select.find(":selected").last(); 97 | } 98 | else { 99 | $selected = $select.find("option, li").first(); 100 | // $selected = $select.find("option").first(); 101 | } 102 | methods._select($dropdown, $selected); 103 | } else { 104 | var selectors = [], val = $select.val() 105 | for (var i in val) { 106 | selectors.push('li[value=' + val[i] + ']') 107 | } 108 | if (selectors.length > 0) { 109 | var $target = $dropdown.find(selectors.join(',')); 110 | $target.removeClass("selected"); 111 | methods._select($dropdown, $target); 112 | } 113 | } 114 | 115 | // Transfer the classes of the select to the input dropdown 116 | $input.addClass($select[0].className); 117 | 118 | // Hide the old and ugly select 119 | $select.hide().attr("data-dropdownjs", true); 120 | 121 | // Bring to life our awesome dropdownjs 122 | $select.after($dropdown); 123 | 124 | // Call the callback 125 | if (options.callback) { 126 | options.callback($dropdown); 127 | } 128 | 129 | //---------------------------------------// 130 | // DROPDOWN EVENTS // 131 | //---------------------------------------// 132 | 133 | // On click, set the clicked one as selected 134 | $ul.on("click", "li:not(.dropdownjs-add)", function(e) { 135 | methods._select($dropdown, $(this)); 136 | // trigger change event, if declared on the original selector 137 | $select.change(); 138 | }); 139 | $ul.on("keydown", "li:not(.dropdownjs-add)", function(e) { 140 | if (e.which === 27) { 141 | $(".dropdownjs > ul > li").attr("tabindex", -1); 142 | return $input.removeClass("focus").blur(); 143 | } 144 | if (e.which === 32 && !$(e.target).is("input")) { 145 | methods._select($dropdown, $(this)); 146 | return false; 147 | } 148 | }); 149 | 150 | $ul.on("focus", "li:not(.dropdownjs-add)", function() { 151 | if ($select.is(":disabled")) { 152 | return; 153 | } 154 | $input.addClass("focus"); 155 | }); 156 | 157 | // Add new options when the widget is used 158 | if (dynamicOptions && dynamicOptions.length) { 159 | $dynamicInput.on("keydown", function(e) { 160 | if(e.which !== 13) return; 161 | var $option = $("