game/addons/game_base/controllers/game_api.py

184 lines
7.4 KiB
Python

# -*- coding: utf-8 -*-
import json
from odoo import http
from odoo.http import request, Response
def _json(data):
"""返回 UTF-8 JSON 响应。"""
return Response(
json.dumps(data, ensure_ascii=False),
content_type='application/json; charset=utf-8',
)
def _post_body():
try:
raw = request.httprequest.get_data(as_text=True) or '{}'
return json.loads(raw)
except Exception:
return {}
class GameApiController(http.Controller):
# ============ 公开只读数据接口(前端从 Odoo 取数) ============
@http.route('/game/api/codex', type='http', auth='public', methods=['GET'], csrf=False)
def codex(self, **kw):
"""图鉴:按分类(cat)分组,每组内按子级(sub)分组。"""
model = request.env['game.codex.entry'].sudo()
cat_labels = dict(model._fields['cat'].selection)
recs = model.search_read([], ['id', 'cat', 'sub', 'name', 'tier', 'desc'])
by_cat = {}
for r in recs:
by_cat.setdefault(r['cat'], []).append(r)
groups = []
for cat in by_cat:
subs = {}
for r in by_cat[cat]:
sub = r['sub'] or '其他'
subs.setdefault(sub, []).append({
'id': r['id'],
'name': r['name'],
'tier': r['tier'],
'sub': r['sub'] or '',
'desc': r['desc'] or '',
'image': '/web/image/game.codex.entry/%s/image' % r['id'],
})
groups.append({
'key': cat,
'label': cat_labels.get(cat, cat),
'subs': [{'name': s, 'items': subs[s]} for s in subs],
})
return _json({'groups': groups})
@http.route('/game/api/rules', type='http', auth='public', methods=['GET'], csrf=False)
def rules(self, **kw):
"""规则 / 等级制度:按类别(type)分组。"""
model = request.env['game.rule'].sudo()
type_labels = dict(model._fields['type'].selection)
recs = model.search_read([], ['id', 'type', 'level', 'name', 'desc'])
by_type = {}
for r in recs:
by_type.setdefault(r['type'], []).append(r)
groups = []
for t in by_type:
groups.append({
'key': t,
'label': type_labels.get(t, t),
'items': [{
'id': r['id'],
'level': r['level'],
'name': r['name'],
'desc': r['desc'] or '',
} for r in by_type[t]],
})
return _json({'groups': groups})
@http.route('/game/api/threads', type='http', auth='public', methods=['GET'], csrf=False)
def threads(self, **kw):
"""论坛主题(含回复),按置顶+时间排序。"""
model = request.env['game.forum.thread'].sudo()
cat_labels = dict(model._fields['category'].selection)
recs = model.search_read(
[], ['id', 'name', 'category', 'author_name', 'pinned', 'create_date', 'body_html'])
out = []
for r in recs:
posts = request.env['game.forum.post'].sudo().search_read(
[('thread_id', '=', r['id'])],
['id', 'author_name', 'body_html', 'create_date'])
out.append({
'id': r['id'],
'name': r['name'],
'category': r['category'],
'category_label': cat_labels.get(r['category'], r['category']),
'author_name': r['author_name'] or '',
'pinned': r['pinned'],
'create_date': str(r['create_date']),
'body_html': r['body_html'] or '',
'replies': posts,
})
return _json(out)
@http.route('/game/api/announcements', type='http', auth='public', methods=['GET'], csrf=False)
def announcements(self, **kw):
"""公告(仅生效的)。"""
model = request.env['game.announcement'].sudo()
pri_labels = dict(model._fields['priority'].selection)
recs = model.search_read(
[('active', '=', True)], ['id', 'name', 'date', 'priority', 'body_html'])
out = [{
'id': r['id'],
'name': r['name'],
'date': str(r['date']),
'priority': r['priority'],
'priority_label': pri_labels.get(r['priority'], r['priority']),
'body_html': r['body_html'] or '',
} for r in recs]
return _json(out)
# ============ 登录 / 注册 / 会话(与 Odoo res.users 打通) ============
@http.route('/game/api/login', type='http', auth='public',
methods=['POST', 'OPTIONS'], csrf=False)
def login(self, **kw):
data = _post_body()
db = data.get('db') or request.session.db or 'game'
login = (data.get('login') or '').strip()
password = data.get('password') or ''
if not login or not password:
return _json({'ok': False, 'error': '账号和密码必填'})
uid = request.session.authenticate(db, login, password)
if uid:
user = request.env['res.users'].sudo().browse(uid)
return _json({'ok': True, 'uid': uid, 'name': user.name, 'login': user.login})
return _json({'ok': False, 'error': '账号或密码错误'})
@http.route('/game/api/register', type='http', auth='public',
methods=['POST', 'OPTIONS'], csrf=False)
def register(self, **kw):
data = _post_body()
name = (data.get('name') or '').strip()
login = (data.get('login') or '').strip()
email = (data.get('email') or '').strip()
password = data.get('password') or ''
if not login or not password:
return _json({'ok': False, 'error': '账号和密码必填'})
if len(password) < 6:
return _json({'ok': False, 'error': '密码至少 6 位'})
User = request.env['res.users'].sudo()
if User.search([('login', '=', login)]):
return _json({'ok': False, 'error': '该账号已存在'})
try:
portal = request.env.ref('base.group_portal')
user = User.create({
'name': name or login,
'login': login,
'email': email or False,
'password': password,
'groups_id': [(6, 0, [portal.id])],
})
db = request.session.db or 'game'
uid = request.session.authenticate(db, login, password)
if uid:
return _json({'ok': True, 'uid': uid, 'name': user.name, 'login': user.login})
return _json({'ok': True, 'uid': user.id, 'name': user.name, 'login': user.login})
except Exception as e:
return _json({'ok': False, 'error': '注册失败:%s' % str(e)})
@http.route('/game/api/me', type='http', auth='public', methods=['GET'], csrf=False)
def me(self, **kw):
uid = request.session.uid
if uid:
user = request.env['res.users'].sudo().browse(uid)
if user.exists():
return _json({'uid': uid, 'name': user.name, 'login': user.login})
return _json({'uid': None})
@http.route('/game/api/logout', type='http', auth='public',
methods=['POST', 'OPTIONS'], csrf=False)
def logout(self, **kw):
request.session.logout()
return _json({'ok': True})