├── .gitattributes
├── app
├── __pycache__
│ ├── models.cpython-35.pyc
│ ├── __init__.cpython-35.pyc
│ └── decorators.cpython-35.pyc
├── auth
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── forms.cpython-35.pyc
│ │ ├── views.cpython-35.pyc
│ │ └── __init__.cpython-35.pyc
│ ├── forms.py
│ └── views.py
├── main
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── views.cpython-35.pyc
│ │ └── __init__.cpython-35.pyc
│ └── views.py
├── decorators.py
├── templates
│ ├── index.html
│ ├── auth
│ │ └── login.html
│ └── subject
│ │ ├── questions.html
│ │ ├── list.html
│ │ ├── question.html
│ │ ├── edit_question.html
│ │ └── edit.html
├── __init__.py
├── static
│ └── js
│ │ ├── template.js
│ │ └── jquery.min.js
└── models.py
├── tornado_server.py
├── requirements.txt
├── README.md
├── config.py
└── manage.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=python
2 | *.css linguist-language=python
3 | *.html linguist-language=python
4 |
--------------------------------------------------------------------------------
/app/__pycache__/models.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/__pycache__/models.cpython-35.pyc
--------------------------------------------------------------------------------
/app/auth/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint
2 |
3 | auth = Blueprint('auth', __name__)
4 |
5 | from . import views
--------------------------------------------------------------------------------
/app/main/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint
2 |
3 | main = Blueprint('main', __name__)
4 |
5 | from . import views
--------------------------------------------------------------------------------
/app/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/app/__pycache__/decorators.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/__pycache__/decorators.cpython-35.pyc
--------------------------------------------------------------------------------
/app/auth/__pycache__/forms.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/auth/__pycache__/forms.cpython-35.pyc
--------------------------------------------------------------------------------
/app/auth/__pycache__/views.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/auth/__pycache__/views.cpython-35.pyc
--------------------------------------------------------------------------------
/app/main/__pycache__/views.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/main/__pycache__/views.cpython-35.pyc
--------------------------------------------------------------------------------
/app/auth/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/auth/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/app/main/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsian/flask-exampy/HEAD/app/main/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/tornado_server.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | from tornado.wsgi import WSGIContainer
3 | from tornado.httpserver import HTTPServer
4 | from tornado.ioloop import IOLoop
5 | from manage import app
6 |
7 | http_server = HTTPServer(WSGIContainer(app))
8 | http_server.listen(9000) #flask默认的端口
9 | IOLoop.instance().start()
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | alembic==0.8.9
2 | click==6.7
3 | dominate==2.3.1
4 | Flask==0.12
5 | Flask-Bootstrap==3.3.7.0
6 | Flask-Login==0.4.0
7 | Flask-Migrate==2.0.2
8 | Flask-Script==2.0.5
9 | Flask-SQLAlchemy==2.1
10 | Flask-WTF==0.14
11 | itsdangerous==0.24
12 | Jinja2==2.9.3
13 | Mako==1.0.6
14 | Markdown==2.6.7
15 | MarkupSafe==0.23
16 | python-editor==1.0.3
17 | SQLAlchemy==1.1.4
18 | tornado==4.4.2
19 | visitor==0.1.3
20 | Werkzeug==0.11.15
21 | WTForms==2.1
22 |
--------------------------------------------------------------------------------
/app/decorators.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | from flask import abort
3 | from flask_login import current_user
4 | from .models import Permission
5 |
6 | def permission_required(permission):
7 | def decorator(f):
8 | @wraps(f)
9 | def decorated_function(*args, **kwargs):
10 | if not current_user.can(permission):
11 | abort(403)
12 | return f(*args, **kwargs)
13 | return decorated_function
14 | return decorator
15 |
16 | def admin_required(f):
17 | return permission_required(Permission.ADMINISTER)(f)
--------------------------------------------------------------------------------
/app/auth/forms.py:
--------------------------------------------------------------------------------
1 | from flask_wtf import Form
2 | from wtforms import StringField, PasswordField, BooleanField, SubmitField
3 | from wtforms.validators import Required, Length, Email, Regexp, EqualTo
4 | from wtforms import ValidationError
5 | from ..models import User
6 |
7 | class LoginForm(Form):
8 | username = StringField('username', validators=[Required(), Length(1, 64)])
9 | password = PasswordField('Password', validators=[Required()])
10 | remember_me = BooleanField('Keep me logged in')
11 | submit = SubmitField('Log In');
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
17 |
18 |
19 |
20 |
hello {{ current_user.username }} 退出
21 |
22 | {% if current_user.is_administrator() %}
23 |
24 | {% endif %}
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # exampy 考试系统
2 |
3 | ## step
4 |
5 | - install python3.x https://www.python.org/downloads/
6 |
7 | - `pip install virtualenv`
8 |
9 | - create new folder `exam`
10 |
11 | - `cd exam` and `git clone https://github.com/hsian/exampy.git`
12 |
13 | - `cd exampy` create virtualenv `virtualenv venv` and switch to `venv\scripts\activate`
14 |
15 | - installation dependency `pip install -r requirements.txt`
16 |
17 | ## deploy
18 |
19 | - initialization db `python manage.py db init` `python manage.py db migrate` `python manage.py db upgrade`
20 |
21 | - insert data `python manage.py deploy`
22 |
23 | - run server `python manage.py runserver` or 'python tornado_server.py`
24 |
25 | 开发使用 python manage.py runserver ,管理员用户名:admin, 密码:123456; <详见配置文件 config.py>
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_bootstrap import Bootstrap
3 | from flask_sqlalchemy import SQLAlchemy
4 | from flask_login import LoginManager
5 | from config import config
6 |
7 |
8 | bootstrap = Bootstrap()
9 | db = SQLAlchemy()
10 |
11 | login_manager = LoginManager()
12 | login_manager.session_protection = 'strong'
13 | login_manager.login_view = 'auth.login'
14 |
15 | from .models import User
16 |
17 | def create_app(config_name):
18 | app = Flask(__name__)
19 | app.config.from_object(config[config_name])
20 | config[config_name].init_app(app)
21 |
22 | bootstrap.init_app(app)
23 | db.init_app(app)
24 | login_manager.init_app(app)
25 |
26 | from .main import main as main_blueprint
27 | app.register_blueprint(main_blueprint)
28 |
29 | from .auth import auth as auth_blueprint
30 | app.register_blueprint(auth_blueprint, url_prefix='/auth')
31 |
32 | return app
--------------------------------------------------------------------------------
/app/templates/auth/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
17 |
18 |
19 |
20 | {% for message in get_flashed_messages() %}
21 |
22 |
23 | {{ message }}
24 |
25 | {% endfor %}
26 |
27 | {% import "bootstrap/wtf.html" as wtf %}
28 |
31 |
32 | {{ wtf.quick_form(form) }}
33 |
34 |
35 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | basedir = os.path.abspath(os.path.dirname(__file__))
3 |
4 | class Config:
5 | SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
6 | SQLALCHEMY_COMMIT_ON_TEARDOWN = True
7 | SQLALCHEMY_RECORD_QUERIES = True
8 | SQLALCHEMY_TRACK_MODIFICATIONS = True
9 | FLASKY_ADMIN = "admin"
10 | FLASKY_ADMIN_PASSWORD = "123456"
11 |
12 | ALLUSERS = ["测试1","测试2","测试3"]
13 |
14 | @staticmethod
15 | def init_app(app):
16 | pass
17 |
18 | class DevelopmentConfig(Config):
19 | DEBUG = True
20 | SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
21 | 'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
22 |
23 | class ProductionConfig(Config):
24 | DEBUG = True
25 | SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
26 | 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
27 |
28 | config = {
29 | 'development': DevelopmentConfig,
30 | 'default': DevelopmentConfig,
31 | 'production': ProductionConfig,
32 | }
33 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 |
4 | from app import create_app, db
5 | from app.models import User, Role, Permission
6 | from flask_script import Manager, Shell, Server
7 | from flask_migrate import Migrate, MigrateCommand
8 |
9 |
10 | app = create_app('production')
11 | manager = Manager(app)
12 | migrate = Migrate(app, db)
13 |
14 | def make_shell_context():
15 | return dict(app=app, db=db, User=User, Role=Role,
16 | Permission=Permission)
17 | manager.add_command("shell", Shell(make_context=make_shell_context))
18 | manager.add_command('db', MigrateCommand)
19 | manager.add_command("runserver", Server(host = '0.0.0.0'))
20 |
21 | @manager.command
22 | def deploy():
23 | """Run deployment tasks."""
24 | from flask_migrate import upgrade
25 | from app.models import Role, User
26 |
27 | # migrate database to latest revision
28 | upgrade()
29 |
30 | # create user roles
31 | Role.insert_roles()
32 |
33 | # create users
34 | User.insert_users()
35 |
36 | # create admin
37 | User.insert_admin()
38 |
39 | if __name__ == '__main__':
40 | manager.run()
--------------------------------------------------------------------------------
/app/templates/subject/questions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 回答列表
5 |
6 |
36 |
37 |
38 |
39 |
40 |
43 | 第 {{current_period}} 期
44 |
45 |
46 |
47 | {% for quest in quests %}
48 |
问题:{{quest.title|safe}}
49 | {% for answer in quest.answers %}
50 |
{{answer.username}}: {{answer.ans | safe}}
51 | {% endfor %}
52 | {% endfor %}
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/auth/views.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, redirect, request, url_for, flash
2 | from flask_login import login_user, logout_user, login_required, \
3 | current_user
4 | from . import auth
5 | from .. import db
6 | from ..models import User
7 | from .forms import LoginForm
8 | import socket
9 |
10 | @auth.route('/login', methods=['GET', 'POST'])
11 | def login():
12 | form = LoginForm()
13 | isEqual = 1
14 | exist = False
15 |
16 | ## get local ip
17 | localIP = request.remote_addr
18 |
19 | if form.validate_on_submit():
20 | user = User.query.filter_by(username=form.username.data).first()
21 | if user is not None and user.verify_password(form.password.data):
22 |
23 | # if user.local_ip is None and User.set_local_ip(user,localIP) or \
24 | # localIP == user.local_ip:
25 | # login_user(user, form.remember_me.data)
26 | # return redirect(url_for('main.index'))
27 | # elif localIP != user.local_ip:
28 | # isEqual = 0
29 |
30 | if user.local_ip is None:
31 | exist = User.set_local_ip(user,localIP)
32 |
33 |
34 | if exist or user.local_ip == localIP or User.is_administrator(user):
35 | login_user(user, form.remember_me.data)
36 | return redirect(url_for('main.index'))
37 | else:
38 | isEqual = 0
39 |
40 | else:
41 | flash('Invalid username or password.')
42 | return render_template('auth/login.html', form=form,isEqual=isEqual)
43 |
44 | @auth.route('/logout')
45 | @login_required
46 | def logout():
47 | logout_user()
48 | flash('You have been logged out.')
49 | return redirect(url_for('main.index'))
--------------------------------------------------------------------------------
/app/static/js/template.js:
--------------------------------------------------------------------------------
1 | /*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
2 | !function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(//g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(B){throw B.temp="function anonymous($data,$filename) {"+z+"}",B}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a,b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"<",">":">",'"':""","'":"'","&":"&"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;d>c;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(j){return j.filename=h||"anonymous",j.name="Syntax Error",p(j)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;e.openTag="{{",e.closeTag="}}";var z=function(a,b){var c=b.split(":"),d=c.shift(),e=c.join(":")||"";return e&&(e=", "+e),"$helpers."+d+"("+a+e+")"};e.parser=function(a){a=a.replace(/^\s/,"");var b=a.split(" "),c=b.shift(),e=b.join(" ");switch(c){case"if":a="if("+e+"){";break;case"else":b="if"===b.shift()?" if("+b.join(" ")+")":"",a="}else"+b+"{";break;case"/if":a="}";break;case"each":var f=b[0]||"$data",g=b[1]||"as",h=b[2]||"$value",i=b[3]||"$index",j=h+","+i;"as"!==g&&(f="[]"),a="$each("+f+",function("+j+"){";break;case"/each":a="});";break;case"echo":a="print("+e+");";break;case"print":case"include":a=c+"("+b.join(",")+");";break;default:if(/^\s*\|\s*[\w\$]/.test(e)){var k=!0;0===a.indexOf("#")&&(a=a.substr(1),k=!1);for(var l=0,m=a.split("|"),n=m.length,o=m[l++];n>l;l++)o=z(o,m[l]);a=(k?"=":"=#")+o}else a=d.helpers[c]?"=#"+c+"("+b.join(",")+");":"="+a}return a},"function"==typeof define?define(function(){return d}):"undefined"!=typeof exports?module.exports=d:this.template=d}();
--------------------------------------------------------------------------------
/app/templates/subject/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 试题列表
5 |
6 |
7 |
97 |
98 |
99 |
100 |
试题列表
101 |
102 |
选择题 (每道3分)
103 |
104 | {% for select in selects %}
105 | -
106 |
{{select.as_title | safe}}
107 | {% if select.isMulit == True %}
108 | (不定项)
109 | {% endif %}
110 |
111 |
112 | {% for option in select.options %}
113 |
{{option}}
114 | {% endfor %}
115 |
116 | 答案:
117 |
118 | {% endfor %}
119 |
120 |
121 |
问答题 (1-7每道5分 第8道10分)
122 |
123 | {% for question in questions %}
124 |
125 |
126 | {{question.as_title | safe}}
127 |
128 |
131 |
132 | {% endfor %}
133 |
134 |
135 |
136 |
137 |
138 |
139 |
220 |
221 |
--------------------------------------------------------------------------------
/app/templates/subject/question.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 编辑题目
5 |
6 |
59 |
60 |
61 |
62 |
63 |
66 | 第 {{current_period}} 期
67 |
68 |
71 |
72 |
73 | {% for question in questions %}
74 |
75 |
编辑
76 |
确认
77 |
78 |
79 |
80 |
81 |
82 | {% endfor %}
83 |
84 |
85 |
86 |
87 |
95 |
96 |
97 |
98 |
99 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/app/main/views.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, redirect, url_for, abort, flash, request,\
2 | current_app, make_response
3 | from flask_login import login_required, current_user
4 | from . import main
5 | from ..auth import auth
6 | from .. import db
7 | from ..models import Role, User, Select, Score ,Question, Answer
8 | from ..decorators import admin_required, permission_required
9 |
10 | import json
11 | import base64
12 | import types
13 |
14 | @main.route('/', methods=['GET', 'POST'])
15 | def index():
16 | if current_user.is_authenticated is False:
17 | return redirect(url_for('auth.login'))
18 | return render_template('index.html')
19 |
20 |
21 | @main.route('/subject', methods=['GET', 'POST'])
22 | @admin_required
23 | def subject():
24 | maxPeriod = Select.get_max_period()
25 | return render_template('subject/edit.html',maxPeriod=maxPeriod,current_period=0)
26 |
27 | @main.route('/subject/', methods=['GET', 'POST'])
28 | @admin_required
29 | def show_subjects(id):
30 |
31 | maxPeriod = Select.get_max_period()
32 | selects = Select.query.filter_by(period=id)
33 |
34 | return render_template('subject/edit.html',maxPeriod=maxPeriod,selects=selects,current_period=id)
35 |
36 | @main.route('/subject/release', methods=['GET', 'POST'])
37 | @admin_required
38 | def subject_release():
39 |
40 | data = json.loads(request.form.get('list'))
41 |
42 | for n in data:
43 | select = Select(title=data[n]["title"],
44 | answer=data[n]["answer"],
45 | option=data[n]["option"],
46 | period=data[n]["period"])
47 | db.session.add(select)
48 | db.session.commit()
49 |
50 | return "True"
51 |
52 | @main.route('/edit_subject/', methods=['GET', 'POST'])
53 | @admin_required
54 | def edit_subject(id):
55 |
56 | select = Select.query.get_or_404(id)
57 | data = json.loads(request.form.get('list'))
58 |
59 | select.title = data["title"]
60 | select.answer = data["answer"]
61 | select.option = data["option"]
62 |
63 | return "True"
64 |
65 | @main.route('/show_subject/',methods=['GET','POST'])
66 | @login_required
67 | def show_subject(id):
68 |
69 | # if id is not 2:
70 | # return "error"
71 |
72 | selects = Select.query.filter_by(period=id)
73 | first = "ABCDEFGHIJK"
74 | index = 0
75 | data = []
76 |
77 | for n in selects:
78 |
79 | index = index + 1
80 | n.as_title = str(index) + ". " + n.title
81 |
82 | arr = n.option.split("###")
83 | for i in range(0,len(arr)):
84 | if arr[i].strip() is not "":
85 | arr[i] = first[i] + ". " + arr[i]
86 | n.options = arr
87 |
88 | if len(n.answer) >= 2:
89 | n.isMulit = True
90 | else:
91 | n.isMulit = False
92 |
93 | data.append(n)
94 |
95 | questions = Question.query.filter_by(period=id)
96 | q_index = 0
97 | q_data = []
98 |
99 | for n in questions:
100 | q_index = q_index + 1
101 | n.as_title = str(q_index) + ". " + n.title
102 |
103 | q_data.append(n)
104 |
105 | return render_template('subject/list.html',selects=data,period=id,questions=q_data)
106 |
107 | @main.route('/figure//',methods=['GET','POST'])
108 | @login_required
109 | def figure_score(id,username):
110 | data = json.loads(request.form.get('list'))
111 |
112 | if username == current_user.username:
113 | exist = Score.query.filter_by(period=id,u_id=current_user.id).first()
114 | if exist is None:
115 | score = 0
116 | selects = Select.query.filter_by(period=id)
117 |
118 | for n in selects:
119 | if data[str(n.id)] == n.answer:
120 | score = score + 1
121 |
122 | o_score = Score(u_id=current_user.id,
123 | username=current_user.username,
124 | score=score,
125 | period=id)
126 | db.session.add(o_score)
127 | db.session.commit()
128 |
129 | return str(score)
130 | else:
131 | return "不能重复提交"
132 | else:
133 | return "用户信息错误"
134 |
135 | @main.route('/figure_quest//',methods=['GET','POST'])
136 | @login_required
137 | def figure_quest(id,username):
138 | data = json.loads(request.form.get('list'))
139 |
140 | if username == current_user.username:
141 |
142 | for n in data:
143 | exist = Answer.query.filter_by(period=id,u_id=current_user.id,quest_id=n).first()
144 | if exist is None:
145 |
146 | answer = Answer(u_id=current_user.id,
147 | username=current_user.username,
148 | period=id,
149 | quest_id=n,
150 | ans=data[n])
151 | db.session.add(answer)
152 |
153 | db.session.commit()
154 |
155 | return "True"
156 |
157 | else:
158 | return "用户信息错误"
159 |
160 | @main.route('/question/',methods=['GET','POST'])
161 | @login_required
162 | @admin_required
163 | def question_by_period(id):
164 | maxPeriod = Select.get_max_period()
165 | questions = Question.query.filter_by(period=id)
166 |
167 | return render_template('subject/question.html',maxPeriod=maxPeriod,questions=questions,current_period=id)
168 |
169 | @main.route('/question/release', methods=['GET', 'POST'])
170 | @login_required
171 | @admin_required
172 | def question_release():
173 |
174 | data = json.loads(request.form.get('list'))
175 |
176 | for n in data:
177 | question = Question(title=data[n]["title"],
178 | period=data[n]["period"])
179 | db.session.add(question)
180 | db.session.commit()
181 |
182 | return "True"
183 |
184 |
185 | @main.route('/edit_question/', methods=['GET', 'POST'])
186 | @login_required
187 | @admin_required
188 | def edit_question(id):
189 |
190 | question = Question.query.get_or_404(id)
191 | data = json.loads(request.form.get('list'))
192 |
193 | question.title = data["title"]
194 | return "True"
195 |
196 |
197 | @main.route('/show_question/',methods=['GET','POST'])
198 | @login_required
199 | @admin_required
200 | def show_question(id):
201 |
202 | quests = Question.query.filter_by(period=id).all()
203 | #answers = Question.query.filter_by(period=id).all()
204 | print(quests)
205 | return render_template('subject/questions.html',quests=quests)
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/app/models.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | import hashlib
3 | from werkzeug.security import generate_password_hash, check_password_hash
4 | from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
5 | from markdown import markdown
6 | from flask import current_app, request, url_for
7 | from flask_login import UserMixin, AnonymousUserMixin
8 | from . import db, login_manager
9 |
10 |
11 |
12 | class Permission:
13 | #FOLLOW = 0x01
14 | COMMENT = 0x02
15 | #WRITE_ARTICLES = 0x04
16 | #MODERATE_COMMENTS = 0x08
17 | ADMINISTER = 0x80
18 |
19 | class Role(db.Model):
20 | __tablename__ = 'roles'
21 | id = db.Column(db.Integer, primary_key=True)
22 | name = db.Column(db.String(64), unique=True)
23 | default = db.Column(db.Boolean, default=False, index=True)
24 | permissions = db.Column(db.Integer)
25 | users = db.relationship('User', backref='role', lazy='dynamic')
26 |
27 | @staticmethod
28 | def insert_roles():
29 | roles = {
30 | 'User': (Permission.COMMENT, True),
31 | 'Administrator': (0xff, False)
32 | }
33 | for r in roles:
34 | role = Role.query.filter_by(name=r).first()
35 | if role is None:
36 | role = Role(name=r)
37 | role.permissions = roles[r][0]
38 | role.default = roles[r][1]
39 | db.session.add(role)
40 | db.session.commit()
41 |
42 | def __repr__(self):
43 | return '' % self.name
44 |
45 | class User(UserMixin, db.Model):
46 | __tablename__ = 'users'
47 | id = db.Column(db.Integer, primary_key=True)
48 | username = db.Column(db.String(64), unique=True, index=True)
49 | role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
50 | password_hash = db.Column(db.String(128))
51 | confirmed = db.Column(db.Boolean, default=False)
52 | #posts = db.relationship('Post', backref='author', lazy='dynamic')
53 | inline = db.Column(db.Boolean, default=False)
54 | local_ip = db.Column(db.String(64), unique=True, index=True)
55 |
56 | def __init__(self, **kwargs):
57 | super(User, self).__init__(**kwargs)
58 | if self.role is None:
59 | if self.username == current_app.config['FLASKY_ADMIN']:
60 | self.role = Role.query.filter_by(permissions=0xff).first()
61 | if self.role is None:
62 | self.role = Role.query.filter_by(default=True).first()
63 |
64 | @property
65 | def password(self):
66 | raise AttributeError('password is not a readable attribute')
67 |
68 | @password.setter
69 | def password(self, password):
70 | self.password_hash = generate_password_hash(password)
71 |
72 | def verify_password(self, password):
73 | return check_password_hash(self.password_hash, password)
74 |
75 | def can(self, permissions):
76 | return self.role is not None and \
77 | (self.role.permissions & permissions) == permissions
78 |
79 | def is_administrator(self):
80 | return self.can(Permission.ADMINISTER)
81 |
82 | @staticmethod
83 | def insert_users():
84 |
85 | users = current_app.config['ALLUSERS']
86 |
87 | for u in users:
88 | user = User(username=u,
89 | password= "12345")
90 | db.session.add(user)
91 | db.session.commit()
92 | print("sucessful insert users");
93 |
94 | @staticmethod
95 | def insert_admin():
96 | user = User(username="hsian",
97 | password= current_app.config["FLASKY_ADMIN_PASSWORD"])
98 | db.session.add(user)
99 | db.session.commit()
100 |
101 | def set_local_ip(self,ip):
102 | exist = User.query.filter_by(local_ip=ip).first()
103 |
104 | if exist is None:
105 | self.local_ip = ip;
106 | db.session.add(self)
107 | return True
108 | else:
109 | return False
110 |
111 | def __repr__(self):
112 | return '' % self.username
113 |
114 | # must add user_loader
115 | @login_manager.user_loader
116 | def load_user(user_id):
117 | return User.query.get(int(user_id))
118 |
119 | class Select(db.Model):
120 | __tablename__ = 'selects'
121 | id = db.Column(db.Integer, primary_key=True)
122 | title = db.Column(db.String(256))
123 | option = db.Column(db.String(256))
124 | answer = db.Column(db.String(64))
125 | period = db.Column(db.Integer)
126 | edited_time = db.Column(db.DateTime(), default=datetime.utcnow)
127 |
128 | def get_max_period():
129 | res = Select.query.order_by(db.desc(Select.period)).first()
130 | if res is not None:
131 | maxPeriod = res.period;
132 | else:
133 | maxPeriod = 0;
134 |
135 | return maxPeriod;
136 |
137 | def __repr__(self):
138 | return '