Skip to content

Commit d9608fc

Browse files
committed
init commit
0 parents  commit d9608fc

17 files changed

+552
-0
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
**/*.pyc
2+
venv/

Diff for: config.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# coding: utf-8
2+
3+
import os
4+
from datetime import timedelta
5+
6+
7+
class Config(object):
8+
9+
XNM = 2016
10+
XQM = 3
11+
12+
13+
config = {
14+
'develop': Config,
15+
'test': Config,
16+
17+
'default': Config
18+
}

Diff for: manage.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# coding: utf-8
2+
3+
import sys
4+
from tables import app
5+
from gevent import monkey
6+
monkey.patch_all()
7+
8+
9+
if __name__ == '__main__':
10+
if len(sys.argv) == 3:
11+
path = sys.argv[2]
12+
host, port = path.split(':')
13+
else:
14+
host = "127.0.0.1"; port = "5060";
15+
if len(sys.argv) > 1 and sys.argv[1] == 'runserver':
16+
app.run(debug=True, host=host, port=int(port))

Diff for: readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# restccnu_table
2+
3+
table service for restccnu

Diff for: requirements.txt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
beautifulsoup4==4.5.1
2+
bs4==0.0.1
3+
click==6.6
4+
Flask==0.11.1
5+
futures==3.0.5
6+
gevent==1.1.2
7+
greenlet==0.4.10
8+
itsdangerous==0.24
9+
Jinja2==2.8
10+
MarkupSafe==0.23
11+
mongokit==0.9.1.1
12+
msgpack-python==0.4.8
13+
neovim==0.1.9
14+
pymongo==2.8
15+
requests==2.11.1
16+
six==1.10.0
17+
trollius==2.1
18+
Werkzeug==0.11.11

Diff for: tables/__init__.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# coding: utf-8
2+
3+
from flask import Flask, render_template, request
4+
from config import config
5+
6+
7+
def create_app(config_name='default'):
8+
app = Flask(__name__)
9+
app.config.from_object(config[config_name])
10+
11+
from apis import api
12+
app.register_blueprint(api, url_prefix='/api')
13+
14+
return app
15+
16+
17+
app = create_app()

Diff for: tables/apis/__init__.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# coding: utf-8
2+
3+
from flask import Blueprint, jsonify
4+
5+
6+
api = Blueprint('api', __name__)
7+
8+
9+
@api.route('/')
10+
def api_index():
11+
return jsonify({
12+
'meta': {
13+
'project': 'restccnu',
14+
'version': 'v1',
15+
'source code': 'https://github.com/Muxi-Studio/restccnu',
16+
'author': ['@neo1218', '@kasheemlew'],
17+
},
18+
'apis': {
19+
'Information Portal Login': '/api/info/login/',
20+
'Library': [
21+
{'library login': '/api/lib/login/'},
22+
{'book search': '/api/lib/search/?keyword=xxx&page=n'},
23+
{'book detail': '/api/lib/?id=xxxxxx&book=xxxx&author=xxxxx'},
24+
{'my library': '/api/lib/me/'},
25+
],
26+
'Class Schedule': [
27+
{'class schedule query': '/api/table/?xnm=n&xqm=n'},
28+
{'add personal class': '/api/table/'},
29+
{'delete personal class': '/api/table/id/'}
30+
],
31+
'Grade Query': {
32+
'query': '/api/grade/search/?xnm=n&xqm=n',
33+
'detail query': '/api/grade/detail/search/?xnm=x&xqm=x&course=x&jxb_id=x'
34+
},
35+
'Info API': '/api/info/',
36+
'Electric bill API': '/api/ele/',
37+
'Apartment info API': '/api/apartment/',
38+
'Static Management': [
39+
{'banner api': '/api/banner/'},
40+
{'calendar api': '/api/calendar'},
41+
{'start api': '/api/start/'}
42+
],
43+
'Version Management': {
44+
'app version management': [
45+
{'all ccnubox version': '/api/app/'},
46+
{'add a new version': '/api/app/'},
47+
{'delete a specific version': '/api/app/'},
48+
{'ccnubox latest version': '/api/app/latest/'}
49+
],
50+
'patch version management': [
51+
{'all ccnubox patches version': '/api/patch/'},
52+
{'add a new patch version': '/api/patch/'},
53+
{'delete a specific patch version': '/api/patch/'},
54+
{'latest ccnubox patch version': '/api/patch/latest/'}
55+
],
56+
},
57+
'muxistudio products': [
58+
{'muxistudio products': '/api/product/'},
59+
{'add a product': '/api/product/'},
60+
{'delete a product': '/api/product/'},
61+
{'update a product': '/api/product/'},
62+
],
63+
},
64+
}), 200
65+
66+
67+
from . import table, login

Diff for: tables/apis/decorators.py

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# coding: utf-8
2+
3+
import os
4+
import base64
5+
import functools
6+
import json
7+
from flask import make_response, jsonify, request, abort
8+
from tables.spiders.login import info_login
9+
from tables.errors import ForbiddenError
10+
11+
12+
def tojson(f):
13+
@functools.wraps(f)
14+
def decorator(*args, **kwargs):
15+
rv = f(*args, **kwargs)
16+
status_or_headers = None
17+
headers = None
18+
if isinstance(rv, tuple):
19+
rv, status_or_headers, headers = rv + (None, ) * (3 - len(rv))
20+
if isinstance(status_or_headers, (dict, list)):
21+
headers, status_or_headers = status_or_headers, None
22+
23+
rv = json.dumps(rv, indent=1, ensure_ascii=False)
24+
rv = make_response(rv)
25+
if status_or_headers is not None:
26+
rv.status_code = status_or_headers
27+
if headers is not None:
28+
rv.headers.extend(headers)
29+
return rv
30+
return decorator
31+
32+
33+
def require_info_login(f):
34+
@functools.wraps(f)
35+
def decorator(*args, **kwargs):
36+
try:
37+
s, sid = info_login()
38+
except ForbiddenError as e:
39+
return jsonify({}), e.status_code
40+
else:
41+
rv = f(s, sid, *args, **kwargs)
42+
return rv
43+
return decorator
44+
45+
46+
def admin_required(f):
47+
@functools.wraps(f)
48+
def decorator(*args, **kwargs):
49+
# http basic auth: Basic base64(email:password)
50+
token_header = request.headers.get('authorization', None)
51+
if token_header:
52+
email_pass = base64.b64decode(token_header[6:])
53+
email = email_pass.split(':')[0]
54+
password = email_pass.split(':')[1]
55+
if email == os.getenv('QINIU_EMAIL') and \
56+
password == os.getenv('QINIU_PASS'):
57+
return f(*args, **kwargs)
58+
else:
59+
return jsonify({'msg': 'unauthorized'}), 401
60+
else:
61+
return jsonify({'msg': 'forbidden'}), 403
62+
return decorator

Diff for: tables/apis/login.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# coding: utf-8
2+
3+
from . import api
4+
from flask import jsonify
5+
from .decorators import require_info_login
6+
7+
8+
@api.route('/info/login/')
9+
@require_info_login
10+
def api_info_login(s, sid):
11+
return jsonify({}), 200

Diff for: tables/apis/table.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# coding: utf-8
2+
3+
import base64
4+
import json
5+
from flask import request, jsonify, current_app
6+
from .decorators import require_info_login, tojson
7+
from . import api
8+
from ..spiders.table import get_table
9+
from ..spiders.login import info_login
10+
from tables.errors import ForbiddenError, NotfoundError
11+
from tables.models import connection, User, _zero # 占位课程(id=0)
12+
13+
14+
@api.route('/table/')
15+
@require_info_login
16+
@tojson
17+
def api_get_table(s, sid):
18+
# xnm = request.args.get('xnm')
19+
# xqm = request.args.get('xqm')
20+
xnm = current_app.config['XNM']
21+
xqm = current_app.config['XQM']
22+
23+
rv = get_table(s, sid, xnm, xqm)
24+
user = connection.User.find_one({'sid': sid})
25+
if user is None:
26+
u = connection.User()
27+
u['sid'] = sid; u['table'] = [_zero]
28+
u.save()
29+
user = connection.User.find_one({'sid': sid})
30+
31+
infocourse_dict = []
32+
for index, course in enumerate(rv):
33+
course.update({'color': index - 4*(index//4)})
34+
infocourse_dict.append(course)
35+
36+
return user['table'] + infocourse_dict
37+
38+
39+
@api.route('/table/', methods=['POST'])
40+
@require_info_login
41+
def api_add_table(s, sid):
42+
if request.method == 'POST':
43+
user = connection.User.find_one({'sid': sid})
44+
if user is None:
45+
return jsonify({}), 404
46+
47+
course = request.get_json().get('course')
48+
teacher = request.get_json().get('teacher')
49+
weeks = request.get_json().get('weeks')
50+
day = request.get_json().get('day')
51+
start = request.get_json().get('start')
52+
during = request.get_json().get('during')
53+
place = request.get_json().get('place')
54+
remind = request.get_json().get('remind')
55+
id = request.get_json().get('id')
56+
new_json = {'course': course, 'teacher': teacher, 'weeks': weeks,
57+
'day': day, 'start': start, 'during': during,
58+
'place': place, 'remind': remind, 'id': id, 'color': 0}
59+
table = user['table']
60+
for item in table:
61+
if item.get('id') == str(id):
62+
return jsonify({'bad request':
63+
'id already exist in database'}), 400
64+
table.append(new_json)
65+
user['table'] = table;
66+
user.save()
67+
68+
return jsonify({}), 201
69+
70+
71+
@api.route('/table/<int:id>/', methods=['DELETE'])
72+
@require_info_login
73+
def api_delete_table(s, sid, id):
74+
if request.method == 'DELETE':
75+
user = connection.User.find_one({'sid': sid})
76+
if user is None:
77+
return jsonify({}), 404
78+
table = user['table']
79+
for i, item in enumerate(table):
80+
if item.get('id') == str(id):
81+
del table[i]
82+
user.save()
83+
return jsonify({}), 200

Diff for: tables/errors.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# coding: utf-8
2+
3+
4+
class ForbiddenError(Exception):
5+
def __init__(self):
6+
self.status_code = 403
7+
8+
def __repr__(self):
9+
return "{'msg': 'forbidden'}"
10+
11+
12+
class NotfoundError(Exception):
13+
def __init__(self):
14+
self.status_code = 404
15+
16+
def __repr__(self):
17+
return "{'msg': 'notfound'}"

Diff for: tables/models/__init__.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# coding: utf-8
2+
from .mongodoc import User, Dormitory
3+
from mongokit import Connection
4+
5+
6+
# config
7+
MONGODB_HOST = '123.56.41.13'
8+
MONGODB_PORT = 27020
9+
10+
# 使用mongodb进行课表数据存储
11+
connection = Connection(host=MONGODB_HOST, port=MONGODB_PORT)
12+
connection.register([User])
13+
connection.register([Dormitory])
14+
15+
# _zero: 占位课程, id=0
16+
## mongodb😓 的特性, 只有数据写入的时候创建数据库
17+
_zero = {
18+
"id": "0",
19+
"course": "re:从零开始的异世界生活",
20+
"teacher": "neo1218",
21+
"weeks": "1",
22+
"day": "2",
23+
"start": "3",
24+
"during": "4",
25+
"place": "5",
26+
"remind": False
27+
}

Diff for: tables/models/mongodoc.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# coding: utf-8
2+
from mongokit import Document
3+
4+
5+
class User(Document):
6+
"""
7+
存储用户对应的课表json数据(全部)
8+
mongodb文档结构: db->collection->data
9+
"""
10+
__collection__ = 'users'
11+
__database__ = 'userdb'
12+
structure = {
13+
'sid': basestring,
14+
'table': list
15+
}
16+
required_fields = ['sid', 'table']
17+
18+
def __repr__(self):
19+
return '<Mongo User>'
20+
21+
22+
class Dormitory(Document):
23+
"""
24+
存储 _meter_index 字典
25+
"""
26+
__collection__ = 'dormitories'
27+
__database__ = 'dordb'
28+
structure = {
29+
'meter': dict
30+
}
31+
required_fields = ['meter']
32+
33+
def __repr__(self):
34+
return '<Mongo Dormitory>'

0 commit comments

Comments
 (0)