id |
avatar_url |
user_name |
alias |
bio |
dev_bio |
created_at |
online_at |
followers_num |
enabled |
SMALLSERIAL | | PRIMARY KEY
simple_name | VARCHAR | 非空、长度小于 20 个字符、只能包含 [A-z]`、[a-z]、[0-9]、`_ | 用户的机器可读名称avatar_url |
VARCHAR | 长度小于 500 字符 | 用户的头像 _URL_user_name |
VARCHAR | 非空、长度小于 100 字符 | 用户名alias |
VARCHAR | 长度小于 50 字符 | 用户别名bio |
VARCHAR | 非空、长度小于 500 字符 | DEFAULT '' 用户自我介绍dev_bio |
VARCHAR | 长度小于 500 字符 | 作为开发者的自我介绍created_at |
TIMESTAMP | 非空 | DEFAULT now() 用户创建时间online_at |
TIMESTAMP | 非空 | DEFAULT now() 用户最近上线时间,由用户手动更新followers_num |
SMALLINT | 非空 | DEFAULT 0 用户的跟随者数目enabled |
BOOLEAN | 非空 | DEFAULT true 用户是否启用id |
category_name |
SMALLSERIAL | | PRIMARY KEYcategory_name |
VARCHAR | 非空 | 分类名,因为只有内部人员操作不加限制id |
author_user |
category |
package_name |
app_name |
alias |
icon_url |
app_description |
visualizer |
button_text |
special |
previews |
app_permissions |
size |
created_at |
updated_at |
stars_num |
comments_num |
VARCHAR | | PRIMARY KEYauthor_user |
SMALLINT | 非空 | 创建者 _UID_category |
SMALLINT | 非空 | 归属 _TID_package_name |
VARCHAR | 长度小于 60 字符 | 包名app_name |
VARCHAR | 非空、长度小于 60 字符 | 应用名alias |
VARCHAR | 长度小于 60 字符 | 别名icon_url |
VARCHAR | 长度小于 500 字符 | 图标 _URL_app_description |
VARCHAR | 非空、长度小于 10000 字符 | DEFAULT '' 应用描述visualizer |
VARCHAR | 长度小于 20 字符 | 应用模型视图button_text |
VARCHAR | 长度小于 60 字符 | _安装卸载按钮_ 文本覆盖special |
VARCHAR | 长度小于 12 字符 | 特殊标识previews |
VARCHAR | 长度小于 4000 字符 | 以 ';' 切分的预览图 _URL_app_permissions |
VARCHAR | 长度小于 10000 字符 | 以 '\n' 切分的权限列表size |
INTEGER | 非空 | DEFAULT 0 应用安装包以 百字节 计体积created_at |
TIMESTAMP | 非空 | DEFAULT now() 创建时间updated_at |
TIMESTAMP | 非空 | DEFAULT now() 更新时间stars_num |
SMALLINT | 非空 | DEFAULT 0 星标数comments_num |
INTEGER | 非空 | DEFAULT 0 评论数id |
author_user |
app |
reply_comment |
content |
replies_num |
created_at |
updated_at |
SERIAL | | PRIMARY KEYauthor_user |
SMALLINT | 非空 | 创建人 _UID_app |
SMALLINT | 非空 | 评论 _AID_reply_comment |
INTEGER | | 回复 _CID_content |
VARCHAR | 非空、长度小于 7000 字符 | 评论内容replies_num |
INTEGER | 非空 | DEFAULT 0 回复数created_at |
TIMESTAMP | 非空 | DEFAULT now() 创建时间updated_at |
TIMESTAMP | | 修改时间user |
followed_user |
SMALLINT | 非空 | 跟随者 _UID_followed_user |
SMALLINT | 非空 | 被跟随者 _UID_user |
metapass |
passhash |
SMALLINT | | PRIMARY KEY 目标用户metapass |
VARCHAR | 非空 | 分发密码passhash |
VARCHAR | | SHA-256 密码取样app |
version_name |
reversion |
install_url |
updates |
api_min |
api_target |
SMALLINT | 非空 | 目标 _AID_version_name |
VARCHAR | 非空,长度小于 40 字符 | 版本名reversion |
SMALLINT | 非空 | 修订号install_url |
VARCHAR | 非空,长度小于 500 字符 | 安装 _GFC_updates |
VARCHAR | 非空,长度小于 6000 字符 | 更新内容api_min |
SMALLINT | | 最低 SDK 版本api_target |
SMALLINT | | 最高 SDK 版本user |
created_at |
line_type |
line_data |
SMALLINT | 非空 | _用户_created_at |
TIMESTAMP | 非空 | DEFAULT now() 创建时间line_type |
SMALLINT | 非空 | 时间线类型line_data |
INTEGER | 非空 | 时间线数据user |
created_at |
notification_type |
notification_data |
enabled |
SMALLINT | 非空 | _用户_created_at |
TIMESTAMP | 非空 | DEFAULT now() 创建时间notification_type |
SMALLINT | 非空 | 通知类型notification_data |
INTEGER | 非空 | 通知数据enabled |
BOOLEAN | 非空 | DEFAULT false 已经阅读通知
GeekApk 里,通知 作为一种对 用户 的提醒而存在,一般在 动作执行后 直接保存等待用户阅读,GeekApk 中有这些通知:
类似 GitHub,GeekApk 也会记录每个 用户 的公开活动并允许所有人自由查询,这个特性被称为 Timeline(时间线),GeekApk 中有这些时间线记录:
用户可按照跟随数目排序,这要在数据库表里增加
应用按照 Star 数、Comment 数、更新时间排序,这要在表里增加
评论只能按照创建时间排序
权限
权限还是用户可写,全服只有一个管理帐号使用
用户还是
计算密码的 Hash 值过程由客户端执行,所有官方客户端都自动取 Hash 值作为密码
简易模型
用户 |
用户可以跟随其他用户,用户有 metahash 和 hash,用户可以发布评论/应用/更新/星标
分类 |
管理员可以创建/删除分类、修改分类名
应用 |
应用可以被附加更新和评论,被用户星标
评论 |
评论可以被附加子评论
具体
用户有简易名称、用户名和不可修改的 UID、头像链接、介绍、创建时间、小黑屋状态
分类有自己不可修改的 ID 和名称,一般以
应用有不可修改的 ID(包名)、创建用户的 ID 引用、所属分类的 ID 引用、名称、图标链接、应用描述、预览图像、创建时间和更新时间
更新有所属应用的 ID 引用、版本名、reversion、安装链接、更新内容、最低和最高适配 SDK 版本
评论有不可修改的 ID、创建用户的 ID 引用、所属应用的 ID 引用、回复评论的 ID 引用、内容、创建时间和更新时间、被回复数
时间线有所属用户引用、创建时间、类型、数据引用
通知有所属用户、创建时间、类型、数据引用、已读状态
为了允许在用户和应用间创建 Star 关系、用户和用户之前创建跟随关系,还额外建立了
GeekApk 里,通知 作为一种对 用户 的提醒而存在,一般在 动作执行后 直接保存等待用户阅读,GeekApk 中有这些通知:
用户 的 评论 被 回复 的通知Timeline(时间线)
用户 被 @ 提到 的通知
用户 被 用户 跟随 的通知
类似 GitHub,GeekApk 也会记录每个 用户 的公开活动并允许所有人自由查询,这个特性被称为 Timeline(时间线),GeekApk 中有这些时间线记录:
用户 Follow 了某个 用户排序
用户 创建了 某个 评论
用户 更新了 某个 评论
用户 发布了 某个 应用
用户 发布了 某个 应用 的 更新
用户 删除了 某个 应用
用户 Star 了某个 应用
用户可按照跟随数目排序,这要在数据库表里增加
followers_num 字段应用按照 Star 数、Comment 数、更新时间排序,这要在表里增加
stars_num 和 comments_num 字段评论只能按照创建时间排序
权限
权限还是用户可写,全服只有一个管理帐号使用
DOGE_TOK 验证,只行使管理员权限而没有用户权限用户还是
uid 和 hash 两个 cookie、分发密码称为 metahash.计算密码的 Hash 值过程由客户端执行,所有官方客户端都自动取 Hash 值作为密码
简易模型
用户 |
user | users | uid | GeekApk 用户帐号用户可以跟随其他用户,用户有 metahash 和 hash,用户可以发布评论/应用/更新/星标
分类 |
category | categories | tid | GeekApk 应用分类管理员可以创建/删除分类、修改分类名
应用 |
app | apps | aid | GeekApk 应用应用可以被附加更新和评论,被用户星标
评论 |
comment | comments | cid | GeekApk 评论评论可以被附加子评论
具体
用户有简易名称、用户名和不可修改的 UID、头像链接、介绍、创建时间、小黑屋状态
分类有自己不可修改的 ID 和名称,一般以
/ 切分路径应用有不可修改的 ID(包名)、创建用户的 ID 引用、所属分类的 ID 引用、名称、图标链接、应用描述、预览图像、创建时间和更新时间
更新有所属应用的 ID 引用、版本名、reversion、安装链接、更新内容、最低和最高适配 SDK 版本
评论有不可修改的 ID、创建用户的 ID 引用、所属应用的 ID 引用、回复评论的 ID 引用、内容、创建时间和更新时间、被回复数
时间线有所属用户引用、创建时间、类型、数据引用
通知有所属用户、创建时间、类型、数据引用、已读状态
为了允许在用户和应用间创建 Star 关系、用户和用户之前创建跟随关系,还额外建立了
follow 和 star 表傲梦 OJ 相关的 API(貌似是自己写的,要不然不会连 Vue.js 开发模式都没关(这次我再找到有啥问题不会发邮件通知他们了,发了也没好脸色看)👎
GET https://all-dream.com/napi/cfxy/questions
获得试题组,返回一个 JSON 列表,每个试题看起来是这样的:
获得小类(题类)组,大类下面是小类,小类下面是题目,返回数组
获得大类列表,每个大类对象看起来像这样
GET/POST https://all-dream.com/napi/cfxy/runlog?userId=uid
返回 uid 的运行记录题目 ID JSON 列表
尝试运行代码
POST https://all-dream.com/napi/cfxy/runcode
参数 code、questionId、userId
GET https://all-dream.com/napi/cfxy/questions
获得试题组,返回一个 JSON 列表,每个试题看起来是这样的:
{
"id": 16,
"name": "造梯子",
"description": "见惯了生活中的木梯子、石梯子,你见过用*造的梯子吗?那么现在尝试去造一个*做的梯子吧!\r\n\r\n注:每两个相邻的\"*\"之间用一个空格隔开,且每行没有多余的空格。",
"chapter_id": "0636f9bc-aff3-4bed-b38d-ab1242d4a88d",
"reward": 1,
"create_time": "2016-04-29T11:05:01.000Z",
"intput": "无",
"output": "*\r\n**\r\n***",
"example_input": "无",
"example_output": "*\r\n**\r\n***",
"tips": "printf结合\\n的使用",
"attempt": 511,
"pass": 420,
"time_limit": 1000,
"test_time_limit": 1000,
"memory_limit": 50,
"in_file_path": "",
"out_file_path": "ONLINETEST/6da99376-3237-4b5a-b991-e6e1b8e08382/1.out,",
"sort_num": 1,
"oss": "6da99376-3237-4b5a-b991-e6e1b8e08382"
}
GET https://all-dream.com/napi/cfxy/chapters获得小类(题类)组,大类下面是小类,小类下面是题目,返回数组
{
"id": "0636f9bc-aff3-4bed-b38d-ab1242d4a88d",
"name": "C1. 输出",
"group_id": "7fbcb3aa-da34-455e-ac75-6fcee72ed2f3",
"description": "输出",
"create_time": "2016-04-29T10:31:55.000Z",
"attempt": 557,
"pass": 78,
"sort_num": 1
}
GET https://all-dream.com/napi/cfxy/group获得大类列表,每个大类对象看起来像这样
{
"id": "7fbcb3aa-da34-455e-ac75-6fcee72ed2f3",
"name": "C语言",
"description": "",
"sort_num": 1
}
获得运行记录GET/POST https://all-dream.com/napi/cfxy/runlog?userId=uid
返回 uid 的运行记录题目 ID JSON 列表
尝试运行代码
POST https://all-dream.com/napi/cfxy/runcode
参数 code、questionId、userId
响应 JSON 包含 id(qid)、code、ret JSON({"info": [{"cpu_time": 1, "exit_status": 0, "signal": 0, "real_time": 2, "flag": 0, "result": 6, "memory": 22884352, "output": "", "message": "\u5b9e\u9645\u8f93\u51fa\u548c\u671f\u671b\u8f93\u51fa\u4e0d\u4e00\u81f4"}], "result": 6})JavaScript 版本
function runlog(uid, fun) {
var req = new XMLHttpRequest();
req.addEventListener('load', fun);
req.open('POST', 'https://all-dream.com/napi/cfxy/runlog');
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
req.send('userId=' + uid);
return req;
}function runlog(uid, fun) {
var request = require("request");
return request({
uri: "https://all-dream.com/napi/cfxy/runlog",
method: "POST",
form: {
userId: uid
}
}, function(error, response, body) {
fun(JSON.parse(body));
});
}
runlog('d21ad8f718264854a4dee4dc4a11badd', console.log)function runcode(uid, qid, code, fun) {
var request = require("request");
return request({
uri: "https://all-dream.com/napi/cfxy/runcode",
method: "POST",
form: {
userId: uid, questionId: qid, code: code
}
}, function(error, response, body) {
fun(JSON.parse(body));
});
}
runcode('d21ad8f718264854a4dee4dc4a11badd', 18, '', console.log)function runlogPromise(uid) {
var request = require("request");
return new Promise((resolve, reject) => {
request({ uri: 'https://all-dream.com/napi/cfxy/runlog', method: 'POST', form: { userId: uid } },
(err, resp, body) => {
if (err) { reject(err) } else { resolve(JSON.parse(body)); }
});
});
}
runlogPromise('d21ad8f718264854a4dee4dc4a11badd').then(console.log)