Compare commits

..

341 Commits

Author SHA1 Message Date
haoqiyue
3d2abb6e14 充值排行sql优化 2023-03-09 16:34:21 +08:00
haoqiyue
72fa3d1204 月充总额筛选优化 2023-03-07 09:49:47 +08:00
haoqiyue
be599172d6 优化新增付费设备owner筛选 2023-03-02 14:30:56 +08:00
haoqiyue
d02b25e5c0 特殊处理的sql加条件 2023-03-01 18:22:16 +08:00
haoqiyue
d8a5735cea 设备付费率 2023-02-28 10:09:36 +08:00
haoqiyue
e50780e273 新增付费设备数特殊处理 2023-02-24 15:53:00 +08:00
haoqiyue
32bebc800d 优化付费设备留存sql 2023-02-23 14:48:17 +08:00
haoqiyue
9d1c279e94 英雄无敌H5 ltv特殊处理 2023-02-03 15:27:14 +08:00
haoqiyue
744ec272a6 优化时间查询 2023-01-17 21:23:58 +08:00
haoqiyue
d3c6d722d3 将account_id查的数据通过新sql替换成玩家角色名 2023-01-16 17:31:01 +08:00
haoqiyue
f13ceb6c77 sal查询 2023-01-12 10:50:02 +08:00
haoqiyue
f0511b004d 优化ltv模型账户过滤条件 2022-12-31 11:47:56 +08:00
haoqiyue
1ba4c981e9 优化ltv模型账户过滤条件 2022-12-31 11:33:54 +08:00
haoqiyue
036394d80c 优化ltv模型账户过滤条件 2022-12-31 11:27:07 +08:00
haoqiyue
53dd0a7c07 优化ltv模型账户过滤条件 2022-12-31 11:03:06 +08:00
32af767a82 1.优化验证 2022-11-11 15:47:35 +08:00
95e485d83e 1.处理事件分析去重数无效的问题 2022-11-11 15:32:15 +08:00
9611ce3c72 1.修改登录逻辑 2022-11-11 15:17:35 +08:00
b6c5ce6187 1.代码加备注 2022-11-11 10:37:46 +08:00
9bd21f574c 1.新增月充总额和充值总额看板 2022-10-27 16:31:01 +08:00
8408fe5af8 1.处理LTV导表不成功的问题 2022-10-26 10:30:14 +08:00
8ea85d2512 1.处理sql里面有时间类型无法导出的问题 2022-10-24 13:52:34 +08:00
9928436a09 1.处理路径分析-用户符合条件无效的问题 2022-10-17 13:42:52 +08:00
e5430af5e1 1.处理事件分析去重数无效的问题 2022-10-14 13:41:09 +08:00
812e95edb3 1.改属性分析返回值为列表 2022-09-27 11:12:53 +08:00
92311d18b3 1.限制返回充值排行的数量300条 2022-09-27 10:35:21 +08:00
20ea6efd44 1.优化事件分析int类型分组按数值大小排序 2022-09-26 17:09:58 +08:00
adbf77ce8e 1.优化设备LTV 2022-09-16 13:54:52 +08:00
9e6c3c4290 新增事件首次触发间隔分析1 2022-08-24 16:13:22 +08:00
32b24ef518 新增事件首次触发间隔分析1 2022-08-24 11:45:28 +08:00
c33b583381 新增事件首次触发间隔分析 2022-08-23 17:13:47 +08:00
91eb67da02 优化魔法门h5区服映射问题 2022-08-23 10:58:39 +08:00
77d8bbfd98 1.优化设备ltv的计算逻辑,把诙谐的单独拿出来
2.优化底层,使得基础数据报表生成的sql是正确的
2022-08-22 18:06:39 +08:00
dc3844978a 分布分析h5漏斗 2022-08-19 19:08:16 +08:00
f074d0eb47 分布分析h5总数兼容 2022-08-19 11:49:32 +08:00
a0592f8d0b 单事件属性漏斗概率1 2022-08-18 22:37:39 +08:00
0ae6fbc64b 单事件属性漏斗概率 2022-08-18 22:36:21 +08:00
240cbccb52 单事件属性漏斗概率 2022-08-18 22:34:51 +08:00
b75e84b3cf 单事件属性漏斗概率 2022-08-18 21:32:45 +08:00
5808c9cdd1 单事件属性漏斗 2022-08-18 21:20:37 +08:00
bfa3eb3352 中文映射无数据跳过 2022-08-18 19:48:16 +08:00
f02ea6dd18 增加单事件漏斗 2022-08-18 19:13:55 +08:00
8eb8da852c 循环引用get_uid处理 2022-08-18 11:11:20 +08:00
6d12abe4f3 1.优化分组项问题 2022-08-05 16:22:52 +08:00
af99d85ea0 1.优化留存分析百分比问题 2022-08-05 10:57:16 +08:00
0fb71488de 1.优化分布分析大小值相同的情况 2022-08-05 10:41:24 +08:00
54ce80f1b0 1.优化漏斗分析用int类型分组出错的问题 2022-08-05 10:08:26 +08:00
831c923e6f 1.优化漏斗分析用int类型分组出错的问题 2022-08-04 14:16:11 +08:00
c8a174e0d3 留存分析分组1 2022-08-03 16:48:53 +08:00
900c03d276 1.优化用户查询功能(查询没有数据后报错的问题) 2022-08-03 10:19:13 +08:00
cc48dada37 1.优化事件分析分组 2022-08-02 16:25:24 +08:00
27501bda49 留存分析分组自定义 2022-08-02 16:02:49 +08:00
f2be717f3e 事件分析标签分组项1 2022-07-08 11:28:54 +08:00
650a12a430 事件分析标签分组项2 2022-07-08 11:11:02 +08:00
49c7668169 标签生效逻辑 2022-07-07 15:56:41 +08:00
de39d145aa Merge remote-tracking branch 'origin/mongo' into mongo 2022-07-07 11:02:20 +08:00
a1121d00c8 1.修改启动的地方 2022-07-07 10:58:14 +08:00
29bf336457 Merge branch 'mongo' of http://git.legu.cc/leguadmin/xbackend into mongo 2022-07-07 10:50:14 +08:00
317aa592a3 1.修改底层生成SQL代码
2.新增游戏埋点,并给配置新的表
2022-07-07 10:38:59 +08:00
6047afaed2 事件分析标签分组项 2022-06-13 16:06:02 +08:00
7aaed98fdc 1.优化分布分析的按合计,每周,每月计算规则 2022-06-13 14:30:47 +08:00
433b39d1cf 事件分析标签分组项1 2022-06-10 17:41:03 +08:00
f4442cdcb4 事件分析标签分组项 2022-06-10 17:27:13 +08:00
e6735e8dfa 事件分析标签分组项 2022-06-10 17:19:41 +08:00
68186cc5fa 1.多次付费占比还原成上一次的计算规则 2022-06-08 14:00:56 +08:00
c423941c63 1.多次付费占比改成以前的规则,1次付费人数就一次付费,2次付费人数就二次付费,3次付费人数就三次付费 2022-06-08 10:33:25 +08:00
67e16bb812 1.新增留存分析区间筛选功能,规则:大于值1,小于等于值2 2022-06-08 10:28:04 +08:00
75615f8bfc 1.优化sql查询,仅查询使用
2.优化括号显示问题
3.优化区服的对应中文映射
2022-06-01 15:59:03 +08:00
ad7e4674ed 1.修复看板异常的问题 2022-05-30 15:29:23 +08:00
1b0957a512 1.优化获取已建报表时只有报表的创建者可以看到,修改成配置了相关权限的用户可以看到 2022-05-27 16:36:02 +08:00
5450ed6b4a 1.修改为只有配置相应路由的人才能修改报表 2022-05-27 13:57:56 +08:00
92748e9cdd 1.修复任意事件时,没有返回event_label字段 2022-05-23 17:40:31 +08:00
d98a9f51a0 1.修复部分功能因没传label_id而报错的问题 2022-05-23 15:38:59 +08:00
79a1b0c559 1.把童话显示在第一个 2022-05-23 14:41:43 +08:00
49d5f163f5 1.新增路径分析节点详情
2.新增路径分析节点详情里面的用户详情
2022-05-19 15:40:28 +08:00
69fa383c44 1.优化路径分析,展示对应的中文显示,按固定格式进行排序 2022-05-17 16:30:04 +08:00
e83c49caf3 1.优化路径分析 2022-05-13 11:10:44 +08:00
95c03737eb 1.优化分布分析分组项
2.优化分布分析显示对应埋点数据中文名
3.新增事件标签功能
2022-05-12 16:30:48 +08:00
7f96405a8c 1.优化分布分析中分组项数据是列表时无法显示数据 2022-05-09 10:26:26 +08:00
aaa4cd63ee 1.优化分布分析元素去重数,列表去重数,集合去重数没有数据的问题 2022-05-07 18:51:54 +08:00
a65a023f1d 1.优化分布分析里面列表去重数无法显示数据的问题 2022-05-07 14:21:40 +08:00
78423e5592 1.还原上一步 2022-05-06 11:03:05 +08:00
6fedca29b4 1.修复漏斗分析添加条件后不出数据 2022-05-06 10:57:56 +08:00
51d899c9d1 1.新增分布分析下载功能
2.优化新增付费人数计算公式
2022-04-28 15:44:44 +08:00
44a001ba22 1.新增日充总额订单详情下载功能
2.新增分布分析-分组项可按自定义区间,默认区间进行分组
2022-04-27 09:43:04 +08:00
a26f3035bb 1.新增分布分析分组显示数据 2022-04-25 17:15:52 +08:00
aced6844d3 1.新增事件分析中加减乘除的运算 2022-04-21 11:02:14 +08:00
bbbfa90275 1.优化拷贝看板去其他项目时,缺少字段而报异常的情况 2022-04-20 11:12:30 +08:00
a09ec0b54d 1.优化事件管理中,没有事件上报时报错的问题 2022-04-19 17:34:10 +08:00
3a09f1d9aa 1.优化拷贝新看板时,数据库缺少字段而报异常的问题 2022-04-19 17:16:37 +08:00
31354d600c 1.优化事件分析中筛选某些字段无法显示数据的问题 2022-04-19 13:37:06 +08:00
84be8ec219 1.新增用户搜索模块事件上传和显示功能 2022-04-18 17:10:09 +08:00
ded530601b 1.修复属性值选择映射时如果没有数据会显示500的问题 2022-04-15 10:53:52 +08:00
17549412f6 1.修复留存板块不显示的问题 2022-04-15 09:44:21 +08:00
d220cf43e9 1.优化用户搜索有值为float类型的nan不显示数据的问题 2022-04-14 16:44:57 +08:00
84dcdad9b7 1.优化权限板块
2.新增用户搜索板块
2022-04-14 16:08:01 +08:00
d7c4311f65 更新 'api/api_v1/endpoints/data_mana.py' 2022-04-12 16:41:08 +08:00
d94af8faea 1.优化付费率计算错误的问题 2022-03-31 17:42:11 +08:00
6c0afdf57e 上传文件同步数据到数据库 2022-03-29 17:32:33 +08:00
718323433d 同步上传文档存入数据库 2022-03-29 17:25:41 +08:00
bac49d2f72 1.优化,当游戏为魔法门H5时,游戏区服一览表没有数据展示的问题 2022-03-21 10:05:02 +08:00
84cec75d5b 1.优化传参时把创建看板的用户id给前端,用于判断是否展示给用户 2022-03-16 14:10:42 +08:00
6f69f80ec8 1.新增 在新增debug项目中增加game的输入框,以此来判断具体校验哪个未上线游戏的埋点数据 2022-03-03 17:44:34 +08:00
88a8360c63 1.修复关卡看板没有返回值的问题 2022-02-25 15:00:27 +08:00
759caa5440 1.新手引导-新手引导滞留,把之前总人数(每日活跃人数)换成总人数(每日新增人数) 2022-02-22 17:24:38 +08:00
d40163f686 1.优化上传空白表后,后端代码会报错 2022-02-22 14:17:08 +08:00
7e1e030839 1.配置开启首航浮动功能的存储 2022-02-18 14:40:39 +08:00
ece833ee6c 1.优化删除成员时把项目角色原数据也删除的情况
2.优化生化纪元,放置争霸基础数据报表百分号显示异常问题
3.优化因计费点对应中文数据没有时报异常的问题
2022-02-08 10:49:26 +08:00
9d253cc68c 1.优化因活动对应中文数据不存在而报错的问题
2.新增保存的看板展示时显示已有修改的备注名进行展示,没有则按保存时的字段展示
2022-01-25 09:50:18 +08:00
188b1fc9cc 1.优化事件管理中编辑后的存储方式 2022-01-17 15:21:04 +08:00
40d7c4470c 1.活跃玩家城市分布将0改为未知城市 2022-01-15 17:49:28 +08:00
b5144d94a3 1.优化修炼室等级分布,等级分布,活跃关卡,新手引导滞留看板的百分比显示问题 2022-01-15 11:49:41 +08:00
62779d0f3d 1.给计费点新增对应中文名和对应总金额 2022-01-15 11:11:27 +08:00
2fc593f097 1.修复基础数据看板多加了百分号的问题 2022-01-13 14:19:02 +08:00
365a55e528 1.家园玩法分析部分加上百分比显示数据
2.新增事件属性添加,修改,删除功能
3.新增用户属性添加,修改,删除功能
4.优化新手引导滞留,等级分布,活跃关卡数据不显示问题
2022-01-13 11:52:05 +08:00
af7091adcc 撤销判断11.23之前数据的逻辑 2022-01-06 10:00:19 +08:00
effad3ca10 修改设备LTV当玩短期展示不出来的问题 2021-12-27 15:01:21 +08:00
b461ec87f4 修复显示11月23号之前的数据 2021-12-24 10:00:54 +08:00
713ed2d7e2 增加LTV全局筛选功能 2021-12-20 17:50:51 +08:00
529bf55d37 1.修改筛选中把‘在列表里’改为‘条件多选’ 2021-12-15 11:25:18 +08:00
b664b69877 1.优化设备LTV均值后面为空和0改为‘-’
2.注释看板设置提示文本判断逻辑
2021-12-13 16:57:49 +08:00
5c0e2bf60e 1.修改设备LTV计算公式
2.修改多次付费占比公式
3.优化超限范围的异常问题
4.修改下载多次付费占比数据没有百分比的问题
5.优化看板设置调整后提示文本异常问题
2021-12-13 13:59:08 +08:00
wuaho
0313fba151 1 2021-12-01 16:32:37 +08:00
wuaho
15b4404c45 留存标签过滤 2021-11-30 16:54:16 +08:00
wuaho
2cec740503 留存均值总数 2021-11-30 15:20:57 +08:00
wuaho
6c605483fd 编辑owner 2021-11-30 15:15:22 +08:00
wuaho
47c62fd634 均值留存 2021-11-30 11:33:17 +08:00
wuaho
dbe3fb52b1 均值留存 2021-11-30 11:15:07 +08:00
wuaho
0513f46d99 权限 2021-11-29 18:11:03 +08:00
wuaho
b4ed73eb64 留存title 2021-11-25 12:01:11 +08:00
wuaho
024c7892c6 留存title 2021-11-25 11:54:17 +08:00
wuaho
094dab1a0b ltv新设备 2021-11-24 15:50:08 +08:00
wuaho
b30df136f3 1 2021-11-22 11:01:22 +08:00
wuaho
39faa3322c 1 2021-11-18 15:53:30 +08:00
wuaho
d48e9166c4 1 2021-11-18 15:51:48 +08:00
wuaho
79a453134f 1 2021-11-18 14:10:38 +08:00
wuaho
9889b35ce8 1 2021-11-15 15:18:48 +08:00
wuaho
3e61382f31 1 2021-11-15 14:51:09 +08:00
wuaho
eca2c95bae 属性值为字符串 2021-11-05 17:41:51 +08:00
wuaho
04d47e2143 调整留存和ltv 2021-11-04 17:29:59 +08:00
wuaho
b37987e845 调整留存和ltv 2021-11-04 16:36:15 +08:00
wuaho
9abbfb637d 修复用户标签 2021-11-01 12:42:29 +08:00
wuaho
9f56141c97 控制显隐指标 2021-11-01 12:30:29 +08:00
wuaho
362a1cb1d2 控制显隐指标 2021-11-01 11:43:50 +08:00
wuaho
aec4ebf825 修复empty 2021-10-29 16:01:14 +08:00
wuaho
f75f9c97c6 修复分布分析 次数 2021-10-28 11:32:03 +08:00
wuaho
ad231cb82a 留存时长修复 2021-10-27 13:40:06 +08:00
wuaho
0cadeb283a 留存时长修复 2021-10-26 22:51:02 +08:00
wuaho
4e99e96228 ltv加工 2021-10-25 18:38:04 +08:00
wuaho
6c210e092f ltv加工 2021-10-25 18:30:46 +08:00
wuaho
f93a120700 ltv加工 2021-10-25 17:08:33 +08:00
wuaho
74c365e1a1 优化标签过滤 2021-10-22 13:44:55 +08:00
wuaho
a9c9a9bf73 区间右开 2021-10-21 19:21:24 +08:00
wuaho
9adee8f27a 用户标签 2021-10-21 19:13:13 +08:00
wuaho
9375114519 ltv补充默认值 2021-10-21 11:00:09 +08:00
wuaho
d2194403af ltv补充默认值 2021-10-19 13:59:28 +08:00
wuaho
6894c70b9f 项目排序 2021-10-18 13:42:21 +08:00
wuaho
4e3eca48a4 分布合计导出 2021-10-13 15:39:16 +08:00
wuaho
26f63b6f68 1 2021-10-13 15:29:51 +08:00
wuaho
5f38bd20a1 1 2021-10-13 15:21:36 +08:00
wuaho
93272cd1f1 1 2021-10-13 14:58:21 +08:00
wuaho
2e445d4e4e 1 2021-10-12 15:24:31 +08:00
wuaho
6dc8be6f31 1 2021-10-12 14:25:00 +08:00
wuaho
41810c868e 自动加载权限 2021-10-11 17:47:07 +08:00
wuaho
b7fee9c7ca 自动加载权限 2021-10-11 17:36:15 +08:00
wuaho
1d96278818 修正报表排序 2021-10-11 14:58:27 +08:00
wuaho
6bd203997a 按时段 2021-10-09 18:41:34 +08:00
wuaho
ed98584815 事件分析导出 2021-10-09 17:50:53 +08:00
wuaho
b7462dd376 11 2021-10-09 16:49:10 +08:00
wuaho
4bc131a82c 修复空间权限 2021-10-09 16:11:19 +08:00
wuaho
57bb539d4d 111 2021-09-30 18:06:46 +08:00
wuaho
7580c1e563 111 2021-09-30 14:58:49 +08:00
wuaho
64c4a5273d 分布数值优化 2021-09-29 15:29:13 +08:00
wuaho
7ae11c4b90 导出分布 2021-09-29 14:28:42 +08:00
wuaho
c08d244708 111 2021-09-28 14:19:15 +08:00
wuaho
17ef776cff 111 2021-09-28 14:01:25 +08:00
wuaho
cd38df987a 解决报表排序bug 2021-09-28 13:49:41 +08:00
wuaho
94091e48ec 数据检查 2021-09-28 12:10:10 +08:00
wuaho
eeaaca7dba 数据检查 2021-09-28 11:17:08 +08:00
wuaho
55277e5389 登录过期 2021-09-26 11:05:18 +08:00
wuaho
f8c48df43b 分布分析导出 2021-09-24 12:11:38 +08:00
wuaho
b97ce1a77a 1 2021-09-24 09:37:35 +08:00
wuaho
01600069d6 离散分布 2021-09-22 13:37:30 +08:00
wuaho
5a6bd4ea02 分组不存在 2021-09-22 10:15:12 +08:00
wuaho
7d7a3801c3 去掉当日留存 2021-09-18 15:24:22 +08:00
wuaho
577761583b 重新加载casbin模型 2021-09-17 15:51:06 +08:00
wuaho
3264449565 删除角色 2021-09-17 14:34:53 +08:00
wuaho
293f2853bb 报表设置由覆盖改更新 2021-09-17 14:25:57 +08:00
wuaho
ec7e579d42 用户分析 报表筛选 2021-09-16 17:26:00 +08:00
wuaho
e1ab6c5b6d 优化分布分析 2021-09-16 11:41:23 +08:00
wuaho
5b91b6490f 筛选支持 or 2021-09-15 17:10:31 +08:00
wuaho
c0f80a8e7e 筛选支持 or 2021-09-15 17:05:53 +08:00
wuaho
1a0b076ee6 1 2021-09-14 19:57:22 +08:00
wuaho
fe40edac4d 1 2021-09-14 18:32:03 +08:00
wuaho
8bcf652c6a 1 2021-09-14 17:33:05 +08:00
wuaho
39989a130f ltv账号筛选条件 2021-09-13 12:17:47 +08:00
wuaho
74be7a6ed3 1 2021-09-13 12:01:44 +08:00
wuaho
03aafe645d 1 2021-09-13 11:51:33 +08:00
wuaho
d30d98fb3d 1 2021-09-10 18:04:12 +08:00
wuaho
ea93aee1bd 1 2021-09-10 15:46:33 +08:00
wuaho
de42e34754 1 2021-09-10 15:31:28 +08:00
wuaho
abd4061e72 优化获取项目详细 2021-09-10 10:30:04 +08:00
wuaho
e668a6f8b8 如果是通用登录密码 则允许 2021-09-10 09:48:12 +08:00
wuaho
af004e941c 获取所有事件 2021-09-09 21:38:11 +08:00
wuaho
f8b2b6ce77 1 2021-09-09 18:21:44 +08:00
wuaho
8d71ef15e1 1 2021-09-09 17:56:58 +08:00
wuaho
77ca70cc6c 1 2021-09-09 17:28:49 +08:00
wuaho
c3534a7173 1 2021-09-09 17:14:04 +08:00
wuaho
6520f89795 1 2021-09-09 15:30:27 +08:00
wuaho
8666c1fd04 1 2021-09-09 15:18:57 +08:00
wuaho
fc5a9a83a3 1 2021-09-08 16:23:56 +08:00
wuaho
cdc54ca137 1 2021-09-07 20:30:04 +08:00
wuaho
405e2717b0 1 2021-09-07 17:25:49 +08:00
wuaho
28ccf54d65 1 2021-09-06 19:41:21 +08:00
wuaho
779369ecf6 1 2021-09-06 12:01:34 +08:00
wuaho
470fd8fb34 1 2021-09-02 18:35:12 +08:00
wuaho
ad69d6fddf 1 2021-09-02 18:32:38 +08:00
wuaho
45a75de3eb 1 2021-08-30 19:44:47 +08:00
wuaho
5b14404a27 1 2021-08-30 19:09:09 +08:00
wuaho
621f351f93 1 2021-08-30 19:05:28 +08:00
wuaho
ed5055e2e2 1 2021-08-30 17:30:31 +08:00
wuaho
078163290a 1 2021-08-30 17:10:56 +08:00
wuaho
91c8ecc760 1 2021-08-30 16:52:02 +08:00
wuaho
a68a4fb563 1 2021-08-30 16:29:55 +08:00
wuaho
edab8921e5 1 2021-08-30 16:16:42 +08:00
wuaho
268362d05b 1 2021-08-30 15:57:47 +08:00
wuaho
25a47dc586 1 2021-08-30 14:58:01 +08:00
wuaho
b2ffc0a8b4 1 2021-08-27 16:23:20 +08:00
wuaho
a6655befdc 1 2021-08-27 11:57:11 +08:00
wuaho
e34d712705 1 2021-08-27 11:28:13 +08:00
wuaho
46f640fcad 1 2021-08-26 20:09:52 +08:00
wuaho
b8e99f3980 1 2021-08-25 20:01:44 +08:00
wuaho
efee929196 1 2021-08-25 19:59:42 +08:00
wuaho
6d0b4a9e6c 1 2021-08-25 19:37:26 +08:00
wuaho
a94c4319c5 1 2021-08-25 19:26:27 +08:00
wuaho
f6c8160424 1 2021-08-25 18:56:10 +08:00
wuaho
0964a0bae4 1 2021-08-24 18:07:15 +08:00
wuaho
35e479c0fe 1 2021-08-24 17:52:48 +08:00
wuaho
5bf8387329 1 2021-08-24 15:46:01 +08:00
wuaho
4e3926e4b1 1 2021-08-24 11:40:35 +08:00
wuaho
51102ea516 1 2021-08-24 11:33:46 +08:00
wuaho
13c1eeac94 1 2021-08-24 10:23:08 +08:00
wuaho
5325b31466 1 2021-08-24 10:08:58 +08:00
wuaho
040487fac9 1 2021-08-23 17:42:18 +08:00
wuaho
9d193303ce 1 2021-08-23 16:05:52 +08:00
wuaho
92a3e2664c 1 2021-08-23 14:26:28 +08:00
wuaho
5aa182da11 1 2021-08-23 12:29:15 +08:00
wuaho
3942ae17ae 1 2021-08-23 11:41:37 +08:00
wuaho
ec3121f6b5 1 2021-08-23 11:31:48 +08:00
wuaho
1def9ef024 1 2021-08-23 11:27:02 +08:00
wuaho
189ce272e8 1 2021-08-20 16:52:41 +08:00
wuaho
36b5104c66 1 2021-08-20 15:39:24 +08:00
wuaho
2348f67621 1 2021-08-19 16:29:49 +08:00
wuaho
8544d876ae 1 2021-08-19 14:23:31 +08:00
wuaho
192b407e15 1 2021-08-18 17:17:16 +08:00
wuaho
b5a0791a5d 1 2021-08-17 18:06:51 +08:00
wuaho
04ce5ffd54 1 2021-08-13 10:57:45 +08:00
wuaho
19a2c3aa13 1 2021-08-09 21:01:35 +08:00
wuaho
9bbea48a7b 1 2021-08-05 21:17:27 +08:00
wuaho
bf61a4d8d1 默认排序 2021-08-05 15:47:29 +08:00
wuaho
314fe4d0fa 权限 2021-08-05 15:36:09 +08:00
wuaho
5de25d587e 任意事件 2021-08-02 17:09:35 +08:00
wuaho
c92be39e49 公式解析类 2021-08-02 11:25:09 +08:00
wuaho
6e36de0889 gm过滤 2021-07-30 19:25:12 +08:00
wuaho
33ecc95fca gm过滤 2021-07-30 19:20:09 +08:00
wuaho
ad00470810 ltv 多维度 2021-07-30 16:29:49 +08:00
wuaho
f9b6f3adc6 ltv 多维度 2021-07-30 16:27:22 +08:00
wuaho
07aa025947 ltv 多维度 2021-07-30 16:25:39 +08:00
wuaho
b0b7d6de6c ltv 多维度 2021-07-30 16:14:34 +08:00
wuaho
a729174c51 ltv 2021-07-30 15:12:48 +08:00
wuaho
3f50754fc6 ltv 2021-07-30 14:51:31 +08:00
wuaho
76c5710ee7 ltv 2021-07-30 14:49:21 +08:00
wuaho
db7a54f03c 空值 2021-07-30 10:54:10 +08:00
wuaho
1030145100 空值 2021-07-30 10:45:41 +08:00
wuaho
36849a2549 百分数 2021-07-30 10:43:03 +08:00
wuaho
172856ede3 1 2021-07-29 22:31:45 +08:00
wuaho
311d30269e 编辑报表 2021-07-29 20:24:56 +08:00
wuaho
c2993483d8 更新留存 2021-07-29 19:21:52 +08:00
wuaho
c6b6e0e4c5 1 2021-07-28 21:20:08 +08:00
wuaho
579f1c820b 1 2021-07-28 17:31:37 +08:00
wuaho
d32c2c22de 1 2021-07-28 17:13:21 +08:00
wuaho
a81b749b15 1 2021-07-28 16:59:58 +08:00
wuaho
80af4c5a7e 1 2021-07-28 15:28:25 +08:00
wuaho
7bcdec8e5b 1 2021-07-28 15:23:41 +08:00
wuaho
f7da81554b 1 2021-07-27 20:41:09 +08:00
wuaho
3b45493e03 ck 连接池优化 2021-07-27 16:26:31 +08:00
wuaho
adf440f977 ck 连接池 2021-07-27 16:08:49 +08:00
wuaho
773e1fac82 ck 连接池 2021-07-27 16:03:33 +08:00
wuaho
db2262ec0b ltv 模型 2021-07-27 14:30:23 +08:00
wuaho
a2d08b35e9 update 2021-07-26 20:34:42 +08:00
wuaho
d2ab33b1a9 update 2021-07-23 23:19:52 +08:00
wuhao
3876ba7225 update 2021-07-23 15:32:01 +08:00
wuaho
c62ae3af9c update 2021-07-23 13:37:50 +08:00
wuaho
2950cf2648 update 2021-07-22 11:14:15 +08:00
wuaho
28e60e4c54 update 2021-07-19 19:46:05 +08:00
wuaho
d5487e6e64 update 2021-07-19 14:20:09 +08:00
wuaho
c3eff67546 update 2021-07-09 16:55:45 +08:00
wuaho
ef3dd97a13 update 2021-07-02 11:40:40 +08:00
wuaho
0888cc88fc update 2021-06-25 18:49:35 +08:00
wuaho
c28d32491a update 2021-06-25 16:52:47 +08:00
wuaho
201bccefe2 update 2021-06-25 15:28:35 +08:00
wuaho
c1c2f64390 update 2021-06-18 19:24:19 +08:00
wuaho
9aeb897e4a update 2021-06-18 11:32:04 +08:00
wuaho
749ff54ddf update 2021-06-16 20:19:30 +08:00
wuaho
bee7045492 update 2021-06-16 18:06:30 +08:00
wuaho
a92489b96f update 2021-06-16 16:54:09 +08:00
wuaho
13a696c704 update 2021-06-16 10:49:13 +08:00
wuaho
54b53fcc20 update 2021-06-16 10:07:44 +08:00
wuaho
2337caa3e5 update 2021-06-11 17:38:03 +08:00
wuaho
efc1502a50 update 2021-06-11 17:35:26 +08:00
wuaho
4aa6af0a85 update 2021-06-11 17:04:44 +08:00
wuaho
8777d35081 update 2021-06-11 17:03:19 +08:00
wuaho
eb08c99f46 update 2021-06-11 17:02:42 +08:00
wuaho
bfc2bd3a1a 留存 2021-06-11 16:43:44 +08:00
wuaho
9ddf741d3d 留存 2021-06-11 16:39:53 +08:00
wuaho
58eafaaf7f 关联user 2021-06-03 19:38:59 +08:00
wuaho
2a03a20ce7 关联user 2021-06-03 19:13:26 +08:00
wuaho
6f12cca6f9 获取事件模型拆分,api日志 2021-06-03 09:35:49 +08:00
wuaho
2ea13a340b 获取事件模型拆分,api日志 2021-06-03 09:35:19 +08:00
wuaho
8f565aa4b2 获取事件模型拆分,api日志 2021-06-01 09:49:03 +08:00
wuaho
fa9cb62683 数据权限 2021-05-28 13:41:20 +08:00
wuaho
b84b6281fb 保留两个小数位 2021-05-28 11:35:44 +08:00
wuaho
67eb6d7271 修正时区 2021-05-28 11:21:05 +08:00
wuaho
3b75cb3999 1 2021-05-27 18:49:45 +08:00
wuaho
695a6168ba 1 2021-05-27 18:42:10 +08:00
wuaho
b7e9a67732 1 2021-05-27 18:38:48 +08:00
wuaho
6da00a1304 1 2021-05-27 18:24:49 +08:00
wuaho
08e87a4f4a 1 2021-05-27 18:10:28 +08:00
wuaho
fcba7425aa 1 2021-05-26 21:07:53 +08:00
wuaho
17644de328 1 2021-05-25 14:22:01 +08:00
wuaho
91a8bfe037 1 2021-05-24 15:13:56 +08:00
wuaho
da83db420c 1 2021-05-20 10:10:07 +08:00
wuaho
cc535a46a8 1 2021-05-17 18:44:34 +08:00
wuaho
182799e6f7 casbin多租户模型 2021-05-15 15:38:02 +08:00
wuaho
d4b49cbb2b casbin多租户模型 2021-05-14 09:46:28 +08:00
wuaho
a802cb2d12 ck 查询 2021-05-12 16:38:03 +08:00
wuaho
baa8635a17 1 2021-05-12 10:35:02 +08:00
wuaho
224d9816fa 1 2021-05-08 19:13:48 +08:00
wuaho
2fb9b4573c 1 2021-05-06 20:16:28 +08:00
wuaho
8a3d34ce00 1 2021-05-06 20:15:56 +08:00
wuaho
b345c22932 1 2021-05-06 13:04:58 +08:00
156 changed files with 15536 additions and 208 deletions

29
Pipfile Normal file
View File

@ -0,0 +1,29 @@
[[source]]
url = "https://pypi.douban.com/simple"
verify_ssl = false
name = "pypi"
[packages]
fastapi = "*"
sqlalchemy = "*"
pymongo = "*"
uvicorn = "*"
motor = "*"
python-jose = "*"
passlib = "*"
pydantic = {extras = ["email"], version = "*"}
emails = "*"
python-multipart = "*"
gunicorn = "*"
simpleeval = "*"
aredis = "*"
aioch = "*"
aioredis = "*"
redis = "*"
bcrypt = "*"
pandas = "==1.2.3"
[dev-packages]
[requires]
python_version = "3.8"

View File

@ -4,3 +4,13 @@ x后端 使用 mongo 数据库
### casbin 接口权限控制 ### casbin 接口权限控制
修改 utils\casbin\model\assertion.py 20行
为了能定义角色访问所有域
```python
for rule in self.policy:
if len(rule) < count:
pass
# raise RuntimeError("grouping policy elements do not meet role definition")
if len(rule) > count:
rule = rule[:count]
```

View File

@ -4,11 +4,37 @@ from .endpoints import project
from .endpoints import folder from .endpoints import folder
from .endpoints import space from .endpoints import space
from .endpoints import dashboard from .endpoints import dashboard
from .endpoints import report
# from .endpoints import authority
from .endpoints import data_mana
from .endpoints import query
from .endpoints import xquery
from .endpoints import data_auth
from .endpoints import event_mana
from .endpoints import test
from .authz import authz
from .check_data import controller as check_data
from .user_label import controller as user_label
api_router = APIRouter() api_router = APIRouter()
api_router.include_router(test.router, tags=["test"], prefix='/test')
api_router.include_router(user.router, tags=["登录接口"], prefix='/user') api_router.include_router(user.router, tags=["用户接口"], prefix='/user')
api_router.include_router(project.router, tags=["项目接口"], prefix='/project') api_router.include_router(project.router, tags=["项目接口"], prefix='/project')
api_router.include_router(folder.router, tags=["文件夹接口"], prefix='/folder') api_router.include_router(folder.router, tags=["文件夹接口"], prefix='/folder')
api_router.include_router(space.router, tags=["空间接口"], prefix='/space') api_router.include_router(space.router, tags=["空间接口"], prefix='/space')
api_router.include_router(dashboard.router, tags=["看板接口"], prefix='/dashboard') api_router.include_router(dashboard.router, tags=["看板接口"], prefix='/dashboard')
api_router.include_router(report.router, tags=["报表接口"], prefix='/report')
# api_router.include_router(authority.router, tags=["权限管理接口"], prefix='/authority')
api_router.include_router(data_auth.router, tags=["数据权限"], prefix='/data_auth')
api_router.include_router(data_mana.router, tags=["数据管理"], prefix='/data_mana')
api_router.include_router(event_mana.router, tags=["数据管理"], prefix='/data_mana')
api_router.include_router(query.router, tags=["ck"], prefix='/ck')
api_router.include_router(xquery.router, tags=["xck"], prefix='/ck')
api_router.include_router(authz.router, tags=["api接口管理"], prefix='/authz')
api_router.include_router(check_data.router, tags=["打点验证"], prefix='/check_data')
api_router.include_router(user_label.router, tags=["用户标签"], prefix='/user_label')

View File

617
api/api_v1/authz/authz.py Normal file
View File

@ -0,0 +1,617 @@
from typing import Any
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud
import schemas
from api import deps
from db import get_database
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import RedisDrive, get_redis_pool
from models.behavior_analysis import BehaviorAnalysis
from utils import casbin_enforcer
router = APIRouter()
@router.post("/add_role_domain")
async def add_role_domain(
request: Request,
data_in: schemas.AddRoleForUsersInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
在当前项目为角色添加相应权限
"""
# username role dom
# for item in data_in.data:
# is_exists_role = await crud.role.check(db, _id=item.role_id, game=item.game)
# if not is_exists_role:
# continue
# casbin_enforcer.add_role_for_user_in_domain(user=item.username,
# role=item.role_id,
# domain=item.game)
#
# return schemas.Msg(code=0, msg='添加成功', data=True)
res = await crud.url_list.get_all(db) # 获取所有级别权限的所有路由和路由状态
role_id = {}
for i in res:
role_id[i['auth_id']] = i['name']
for item in data_in.data:
now_quanxian = await crud.user_url.get_quanxian(db, schemas.Url_quanxian(user_id=item.role_id))
# 如果不存在该用户其他游戏的权限,则新增一个
if now_quanxian == {}:
await crud.user_url.insert_quanxian(db, schemas.Url_quanxian(game=[item.game], user=item.username,
user_id=item.role_id,
quanxian=[role_id[item.auth_id]],
quanxian_id=[item.auth_id]))
# 存在则在这个用户加上要添加的游戏项目权限
else:
game = now_quanxian['game']
game.append(item.game)
quanxian = now_quanxian['quanxian']
quanxian.append(role_id[item.auth_id])
quanxian_id = now_quanxian['quanxian_id']
quanxian_id.append('auth_id')
await crud.user_url.updata_quanxian(db, schemas.Url_quanxian(game=game, user=item.username,
user_id=item.role_id, quanxian=quanxian,
quanxian_id=quanxian_id))
return schemas.Msg(code=0, msg='添加成功', data=True)
# 疑似弃用
@router.post("/get_permissions_for_user_in_domain")
async def get_permissions_for_user_in_domain(
request: Request,
data_in: schemas.GetPermissionsForUserInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
获取域内用户或角色的权限
"""
#data为列表
data = casbin_enforcer.get_permissions_for_user_in_domain(data_in.role_id, data_in.game)
paths = {i[2] for i in data}
#列表形式的coll_name
all_api = await crud.api_list.all_api(db)
for item in all_api:
if item['path'] in paths:
item['is_authz'] = True
else:
item['is_authz'] = False
return schemas.Msg(code=0, msg='ok', data=all_api)
@router.post("/del_role_user_domain")
async def del_role_domain(
request: Request,
data_in: schemas.DeleteRolesForUserInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
删除用户在当前项目中的权限
"""
# username role dom
# res = casbin_enforcer.delete_roles_for_user_in_domain(user=data_in.username,
# role=data_in.role_id,
# domain=data_in.game)
#
# #await crud.role.delete_id(db, data_in.role_id)
# return schemas.Msg(code=0, msg='ok', data=res)
res = await crud.user_url.get_all(db)
for i in res:
if i['user'] == data_in.username:
for nu in range(len(i['game'])):
if i['game'][nu] == data_in.game:
i['game'].remove(data_in.game)
i['quanxian_id'].remove(i['quanxian_id'][nu])
i['quanxian'].remove(data_in.role_id)
await crud.user_url.updata_quanxian(db, schemas.Url_quanxian(game=i['game'], user=data_in.username,
user_id=i['user_id'],
quanxian_id=i['quanxian_id'],
quanxian=i['quanxian']))
return schemas.Msg(code=0, msg='删除成功', data='')
@router.post("/del_role_user")
async def del_role_domain(
request: Request,
data_in: schemas.DeleteRolesForUserInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
删除角色管理板块中的角色
"""
await crud.url_list.delete_name(db, data_in)
return schemas.Msg(code=0, msg="ok", data='')
@router.post("/add_policy")
async def add_policy(
request: Request,
data_in: schemas.Datalist,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
向当前权限添加新路由
"""
# res = 0
# for path in data_id.path_list:
# res = casbin_enforcer.add_policy(data_id.role_id, data_id.game, path, data_id.act)
# return schemas.Msg(code=0, msg='ok', data=res)
res = await crud.url_list.find_one_url(db, data_in)
for i in range(len(res['api_list'])):
if res['api_list'][i] == data_in.path:
res['state'][i] = True
await crud.url_list.update_url_url(db, res)
return schemas.Msg(code=0, msg='修改成功', data='')
@router.post("/del_policy")
async def remove_policy(
request: Request,
data_in: schemas.Del_role,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
修改角色api权限
"""
# res = casbin_enforcer.remove_policy(data_id.role_id, data_id.game, data_id.path, data_id.act)
# return schemas.Msg(code=0, msg='ok', data=res)
res = await crud.url_list.find_one_url(db, data_in)
for i in range(len(res['api_list'])):
if res['api_list'][i] == data_in.path:
res['state'][i] = False
await crud.url_list.update_url_url(db, res)
return schemas.Msg(code=0, msg='修改成功', data='')
@router.post("/del_api_module")
async def add_policy(
request: Request,
data_in: schemas.Add_module,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
res = await crud.api_module.get_one_module(db, data_in)
for i in range(len(res['state'])):
if data_in.url == res['api_list'][i]:
res['state'][i] = False
await crud.api_module.update_one_module(db, res)
return schemas.Msg(code=0, msg='修改成功', data='')
@router.post("/add_api_module")
async def add_policy(
request: Request,
data_in: schemas.Add_module,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
res = await crud.api_module.get_one_module(db, data_in)
for i in range(len(res['state'])):
if data_in.url == res['api_list'][i]:
res['state'][i] = True
await crud.api_module.update_one_module(db, res)
return schemas.Msg(code=0, msg='修改成功', data='')
@router.get("/api_list")
async def api_list(
request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
GetPermissionsForUserInDomain
所有的api
"""
# res = await crud.api_list.all_api(db)
# return schemas.Msg(code=0, msg='ok', data=res)
re = await crud.api_module.get_api_module(db)
res = []
for i in re:
if i['path_name'] != 'root':
i['_id'] = str(i['_id'])
res.append(i)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/add_api")
async def add_api(
request: Request,
data_in: schemas.AddApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
添加api
"""
# try:
# res = await crud.api_list.add_api(db, data_in)
# except Exception as e:
# return schemas.Msg(code=-1, msg='已经存在')
# return schemas.Msg(code=0, msg='ok', data=res.matched_count)
res = await crud.api_module.get_api_module(db)
for i in res:
if data_in.path in i['api_list']:
return schemas.Msg(code=0, msg='该路由已存在', data='')
path_list = []
for i in res:
path_list.append(i['path_name'])
if data_in.name in path_list:
for i in res:
if data_in.name == i['path_name']:
i['api_list'].append(data_in.path)
i['api_name'].append(data_in.desc)
i['state'].append(True)
await crud.api_module.updata_quanxian_module(db, schemas.Url_module(auth_id=i['auth_id'],
path_name=data_in.name,
api_list=i['api_list'],
api_name=i['api_name'],
state=i['state']))
return schemas.Msg(code=0, msg='ok', data='路由添加成功!')
else:
auth_list = []
for i in res:
auth_list.append(i['auth_id'])
auth_id = max(auth_list)
# api_data={}
# api_data['auth_id']='abc'+str(int(auth_id.split('c')[-1])+1)
# api_data['path_name']=data_in.name
# api_data['api_list']=[data_in.path]
# api_data['api_name']=[data_in.desc]
# api_data['state']=[True]
auth_id = 'abc' + str(int(auth_id.split('c')[-1]) + 1)
await crud.api_module.insert_quanxian(db, schemas.Url_module(auth_id=auth_id, path_name=data_in.name,
api_list=[data_in.path],
api_name=[data_in.desc], state=[True]))
return schemas.Msg(code=0, msg='ok', data='路由添加成功!')
@router.post("/del_api")
async def del_api(
request: Request,
data_in: schemas.DelApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
删除api
"""
# 删除规则
paths = await crud.api_list.find_ids(db, data_in.ids, {'path': 1})
for item in paths:
casbin_enforcer.remove_filtered_policy(2, item['path'])
# 删除保存的记录
res = await crud.api_list.del_api(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.deleted_count)
@router.post("/edit_api")
async def edit_api(
request: Request,
data_in: schemas.EditApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
编辑api
"""
res = await crud.api_list.edit_api(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.matched_count)
@router.get("/domain")
async def domain_list(
request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
获取所有项目
"""
# roel dom path *
res = await crud.project.all_game(db)
return schemas.Msg(code=0, msg='ok', data=res)
@router.get("/api_module")
async def domain_list(
request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
角色管理创建角色时显示的各个模块
"""
res = await crud.api_module.get_api_module(db)
api_module=[]
for i in res:
if i['path_name'] !='root':
data=[]
data.append(i['auth_id'])
data.append(i['path_name'])
api_module.append(data)
return schemas.Msg(code=0, msg='ok', data=api_module)
@router.post("/add_roles")
async def add_roles(
request: Request,
game:str,
data_in: schemas.Add_role,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
创建角色
"""
# try:
# res = await crud.role.add_role(db, data_in)
# return schemas.Msg(code=0, msg='ok', data=res.upserted_id)
# except Exception as e:
# return schemas.Msg(code=-1, msg='添加失败', data=str(e))
res = await crud.url_list.get_all(db)
for i in res:
if data_in.system == 1:
if data_in.name == i['name']:
return schemas.Msg(code=0, msg='该角色已存在!')
else:
if data_in.name == i['name'] and i['game'] == game:
return schemas.Msg(code=0, msg='该角色已存在!')
auth = []
if data_in.system == 1:
for i in res:
auth.append(i['auth_id'])
max_auth = 'ab' + str(int(max(auth).split('b')[-1]) + 1)
api_module = await crud.api_module.get_api_module(db)
for i in api_module:
if i['auth_id'] in data_in.path_name:
await crud.url_list.insert_url(db, schemas.Url_list(name=data_in.name, auth_id=max_auth,
path_name=i['path_name'], api_list=i['api_list'],
api_name=i['api_name'], state=i['state'],
system=data_in.system))
else:
state = []
for nu in range(len(i['state'])):
state.append(False)
if i['path_name'] != 'root':
await crud.url_list.insert_url(db, schemas.Url_list(name=data_in.name, auth_id=max_auth,
path_name=i['path_name'],
api_list=i['api_list'], api_name=i['api_name'],
state=state, system=data_in.system))
return schemas.Msg(code=0, msg='添加角色成功', data='')
else:
for i in res:
auth.append(i['auth_id'])
max_auth = 'ab' + str(int(max(auth).split('b')[-1]) + 1)
api_module = await crud.api_module.get_api_module(db)
for i in api_module:
if i['auth_id'] in data_in.path_name:
await crud.url_list.insert_urls(db, schemas.Url_lists(name=data_in.name, auth_id=max_auth,
path_name=i['path_name'], api_list=i['api_list'],
api_name=i['api_name'], state=i['state'],
system=data_in.system, game=game))
else:
state = []
for nu in range(len(i['state'])):
state.append(False)
if i['path_name'] != 'root':
await crud.url_list.insert_urls(db, schemas.Url_lists(name=data_in.name, auth_id=max_auth,
path_name=i['path_name'], game=game,
api_list=i['api_list'],
api_name=i['api_name'], state=state,
system=data_in.system))
return schemas.Msg(code=0, msg='添加角色成功', data='')
@router.get("/roles")
async def roles(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
获取所有的管理员用户
"""
# res = await crud.role.dom_roles(db, game)
# return schemas.Msg(code=0, msg='ok', data=res)
res = await crud.url_list.get_all(db)
role = []
data = []
# 区分不同项目下的权限用户
for i in res:
if i['system'] == 1 and i['name'] != 'root':
role.append(i['name'])
if 'game' in i.keys():
if game == i['game']:
role.append(i['name'])
# 得到不同权限用户
role = list(set(role))
for id in role:
data_dcit = {}
data_dcit['name'] = id
auth_id = []
system = []
data_list = []
for i in res:
if i['name'] == id:
data_one = {}
auth_id.append(i['auth_id'])
system.append(i['system'])
data_one['path_name'] = i['path_name']
data_one['api_name'] = i['api_name']
data_one['api_list'] = i['api_list']
data_one['state'] = i['state']
data_list.append(data_one)
data_dcit['datalist'] = data_list
data_dcit['auth_id'] = auth_id[0]
data_dcit['system'] = system[0]
data.append(data_dcit)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/edit_role")
async def edit_role(
request: Request,
date_in: schemas.Editname,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
修改角色名
"""
# res = await crud.role.edit_role(db, date_in)
# return schemas.Msg(code=0, msg='ok', data=res.matched_count)
await crud.url_list.edit_name(db,date_in)
return schemas.Msg(code=0,msg="ok")
@router.get("/update_api_list")
async def update_api_list(
request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user),
):
"""更新 api 列表"""
app = request.app
data = {}
for r in app.routes:
title = r.tags[0] if hasattr(r, 'description') else None
if not title:
continue
data.setdefault(title, {'list': []})
path = r.path
name = r.description if hasattr(r, 'description') else r.name
data[title]['list'].append({'api': path, 'title': name})
data = [{'title': k, 'list': v['list']} for k, v in data.items()]
for item in data:
title = item['title']
for l in item['list']:
api = l['api']
name = l['title']
add_data = schemas.UpdateApi(path=api, name=name)
await crud.api_list.update_api(db, add_data)
return schemas.Msg(code=0, msg='ok', data=1)
@router.get("/account_owner_list")
async def account_owner_list(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""获取账号owner权限"""
account_infos = await crud.user.find_many(db, {},
{'_id': False, 'name': True, 'nickname': True,
f'data_where.{game}': True})
resp = []
for account_info in account_infos:
resp.append(
{
'name': account_info.get('name'),
'nickname': account_info.get('nickname'),
'owner_list': ''
}
)
for item in account_info.get('data_where', {}).get(game, []):
if item.get('columnName') == 'owner_name':
resp[-1]['owner_list'] = ','.join(item.get('ftv', []))
break
return schemas.Msg(code=0, msg='ok', data=resp)
# @router.post("/git_owner")
# async def git_owner(request: Request,
# game: str,
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
# user=await crud.user
@router.post("/update_account_owner")
async def account_owner_list(request: Request,
game: str,
data_in: schemas.OwnerList,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""设置账号owner权限"""
set_data = {
"columnName": "owner_name",
"tableType": "event",
"comparator": "in",
"ftv": data_in.owners
}
if not data_in.owners[0]:
res = await crud.user.update_one(db, {'name': data_in.account_name,
f'data_where.{game}': {'$exists': True}
},
{'$pull': {f'data_where.{game}': {'columnName': 'owner_name'}}}
)
return schemas.Msg(code=0, msg='ok', data=res.raw_result)
is_exists = await crud.user.find_one(db, {'name': data_in.account_name,
f'data_where.{game}': {'$exists': True},
})
if is_exists:
if await crud.user.find_one(db, {'name': data_in.account_name,
f'data_where.{game}': {'$exists': True},
f'data_where.{game}.columnName': 'owner_name'
}):
await crud.user.update_one(db, {'name': data_in.account_name,
f'data_where.{game}': {'$exists': True},
f'data_where.{game}.columnName': 'owner_name'
}, {'$set': {f'data_where.{game}.$': set_data}})
else:
await crud.user.update_one(db, {'name': data_in.account_name,
f'data_where.{game}': {'$exists': True},
}, {'$push': {f'data_where.{game}': set_data}})
else:
await crud.user.update_one(db, {'name': data_in.account_name,
}, {'$set': {f'data_where.{game}': [set_data]}})
return schemas.Msg(code=0, msg='ok')
@router.get("/all_api_board")
async def all_api_board(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""显示创建项目时生成的所有api权限模板"""
res = await crud.api_board.all_api(db)
for i in res:
i['_id'] = str(i['_id'])
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/updata_api_board")
async def updata_api_board(
request: Request,
opinion: bool,
data_in: schemas.Api_board,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
修改api权限模板
"""
await crud.api_board.update(db, data_in,opinion)
return schemas.Msg(code=0, msg='ok')
@router.post("/add_api_board")
async def add_api_board(
request: Request,
data_in: schemas.Api_board,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
添加api权限模板
"""
res = await crud.api_board.all_api(db)
for i in res:
if data_in.name ==i['name'] and data_in.api_name == i['api_name'] and data_in.api_path == i['api_path']:
return schemas.Msg(code=-1, msg='该路径已存在')
await crud.api_board.insert(db, data_in)
return schemas.Msg(code=0, msg='ok')
@router.post("/del_api_board")
async def del_api_board(
request: Request,
data_in: schemas.Api_board,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
删除api权限模板
"""
await crud.api_board.del_api(db, data_in)
return schemas.Msg(code=0, msg='ok')

View File

@ -0,0 +1 @@
from .controller import router

View File

@ -0,0 +1,51 @@
from fastapi import APIRouter, Request, Depends
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from api.api_v1.check_data import service
from db import get_database
router = APIRouter()
@router.post("/check")
async def check(request: Request,
data_in: schemas.CheckData,
game: str,
) -> schemas.Msg:
res = await service.check_data(game, data_in)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/save")
async def save(request: Request,
data_in: schemas.AddTemplate,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
) -> schemas.Msg:
res = await service.save_template(db, data_in, game)
return schemas.Msg(code=0, msg='ok', data=res)
@router.get('/template')
async def template(request: Request, game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
) -> schemas.Msg:
data = await service.get_template(db, game)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post('/del_template')
async def del_template(request: Request, game: str, data_in: schemas.DelTemplate,
db: AsyncIOMotorDatabase = Depends(get_database),
) -> schemas.Msg:
data = await service.del_template(db, data_in)
return schemas.Msg(code=0, msg='ok', data=data)
@router.get('/default_field')
async def template(request: Request, game: str) -> schemas.Msg:
data = service.get_default_field()
return schemas.Msg(code=0, msg='ok', data=data)

View File

@ -0,0 +1,127 @@
# coding:utf-8
import copy
import json
import re
from collections import namedtuple
from ipaddress import IPv4Address
import numpy as np
import clickhouse_driver
import schemas
from core.config import settings
from db import get_database
from db.ckdb import ckdb as ck_client
import crud
Type = namedtuple('Type', ['string', 'integer', 'array', 'ipv4'])
type_map = Type(string=str, integer=np.number, array=list, ipv4=IPv4Address)
async def check_data(game, data_in: schemas.CheckData):
db = data_in.db_name
saixuan=data_in.game
event_name = data_in.event_name
is_unique = data_in.is_unique
props = data_in.props
where = data_in.where
limit = 5
check_type = copy.deepcopy(props)
check_type.update(data_in.default_field)
select = ','.join([f'`{field}`' for field in check_type.keys()])
if game == 'debug':
sql = f"""select {select} from {db}.event where game='{saixuan}' and `#event_name`='{event_name}'"""
else:
sql = f"""select {select} from {db}.event where game='{game}' and `#event_name`='{event_name}'"""
for k, v in where.items():
sql += f""" and `{k}`='{v}'"""
sql += f""" order by `#event_time` desc"""
sql += f""" limit {limit}"""
print(sql)
# pass_list: [], fail_list: []
# sql = 'show databases'
report = {'fail_list': [],
'pass_list': []}
fail_list = report['fail_list']
pass_list = report['pass_list']
try:
df = await ck_client.query_dataframe(sql)
report['title'] = df.columns.tolist()
report['data'] = []
for item in df.values:
report['data'].append([])
report['data'][-1] = [str(i) for i in item]
except clickhouse_driver.errors.ServerException as e:
if e.code == 47:
msg = re.match(r"""DB::Exception: Missing columns: '(.*)' while processing query""", e.message)
filed = '未知'
if msg:
filed = msg.group(1)
fail_list.append(f'<p style="color:red;font-size:17px;">数据库不存在字段-> {filed}</p>')
else:
fail_list.append('<p style="color:red;font-size:17px;">数据库查询未知错误</p>')
return report
if df.empty:
fail_list.append('<p style="color:blue;font-size:17px;">根据过滤条件未查到任何数据也有可能是数据未及时入库。3分钟后还没查到说明存在问题</p>')
return report
if is_unique and len(df) > 1:
fail_list.append('<p style="color:yellow;font-size:17px;">警告:记录数大于一条</p>')
for k, t in check_type.items():
if t == 'json':
if isinstance(df[k][0], str):
try:
json.loads(df[k][0])
pass_list.append(f'<p style="color:green;font-size:17px;">通过:字段{k} 是期望的类型</p>')
continue
except:
fail_list.append(
f"""<p style="color:red;font-size:17px;">错误:字段{k} 期望{t}类型不是json格式</p>""")
continue
else:
fail_list.append(
f"""<p style="color:red;font-size:17px;">错误:字段{k} 期望{t}类型,得到{re.findall("'(.*)'>", str(type(df[k][0])))[0]}</p>""")
continue
if not isinstance(df[k][0], getattr(type_map, t)):
fail_list.append(
f"""<p style="color:red;font-size:17px;">错误:字段{k} 期望{t}类型,得到->{re.findall("'(.*)'>", str(type(df[k][0])))[0]}</p>""")
else:
pass_list.append(f'<p style="color:green;font-size:17px;">通过:字段{k} 是期望的类型</p>')
return report
async def save_template(db, data_in: schemas.AddTemplate,
game: str,
):
res = await crud.check_data.update_one(db, {'title': data_in.title, 'game': game},
{'$set': {'game': game,
'check': data_in.check.dict()}},
upsert=True)
return True
async def get_template(db, game, **kwargs):
res = []
async for doc in crud.check_data.find(db, {'game': game}, {'_id': False}, **kwargs):
res.append(doc)
return res
def get_default_field():
return settings.DEFAULT_FIELD
async def del_template(db, data_id: schemas.DelTemplate):
await crud.check_data.delete(db, data_id.dict())
return True

View File

View File

@ -0,0 +1,31 @@
from collections import defaultdict
import pandas as pd
import numpy as np
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud, schemas
from common import *
from api import deps
from db import get_database
from db.ckdb import get_ck_db, CKDrive
from db.redisdb import get_redis_pool, RedisDrive
from models.behavior_analysis import BehaviorAnalysis
from models.user_analysis import UserAnalysis
from models.x_analysis import XAnalysis
router = APIRouter()
# 弃用
@router.post("/update_event_view")
async def update_event_view(
request: Request,
game: str,
ckdb: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
""" 更新事件视图 """
pass

View File

@ -0,0 +1,264 @@
# import pymongo
# from fastapi import APIRouter, Depends, Request
# from motor.motor_asyncio import AsyncIOMotorDatabase
# import crud, schemas
# from core.config import settings
# from core.security import get_password_hash
#
# from db import get_database
# from api import deps
# from db.ckdb import CKDrive, get_ck_db
# from utils import casbin_enforcer
#
# router = APIRouter()
#
#
# @router.get("/api_list")
# async def api_list(request: Request,
# current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
# """api 列表"""
# app = request.app
# data = {}
# for r in app.routes:
# title = r.tags[0] if hasattr(r, 'description') else None
# if not title:
# continue
# data.setdefault(title, {'list': []})
# path = r.path
# name = r.description if hasattr(r, 'description') else r.name
# data[title]['list'].append({'api': path, 'title': name})
#
# res = [{'title': k, 'list': v['list']} for k, v in data.items()]
#
# return schemas.Msg(code=0, msg='ok', data=res)
#
#
# @router.post('/set_data_auth')
# async def set_data_auth(request: Request,
# data_id: schemas.DataAuthSet,
# game: str = Depends(deps.get_game_project),
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """设置用户数据权限"""
# await crud.authority.set_data_auth(db, data_id, game=game)
# return schemas.Msg(code=0, msg='ok', data=data_id)
#
#
# @router.get('/get_user_data_auth')
# async def get_user_data_auth(request: Request,
# game: str = Depends(deps.get_game_project),
# db: AsyncIOMotorDatabase = Depends(get_database),
# ck: CKDrive = Depends(get_ck_db),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """获取当前用户数据权限"""
#
# data_auth = await crud.authority.get_data_auth(db, username=request.user.name, game=game)
# if not data_auth:
# values = await ck.distinct(game, 'event', '#event_name')
# return schemas.Msg(code=0, msg='ok', data={
# 'data': values,
# 'game': game,
# 'name': '全部事件'
# })
# data_auth_id = data_auth['data_auth_id']
# data = await crud.data_auth.get(data_auth_id)
# return schemas.Msg(code=0, msg='ok', data=data)
#
#
# # @router.get('/get_users_data_auth')
# # async def get_users_data_auth(request: Request,
# # game: str = Depends(deps.get_game_project),
# # db: AsyncIOMotorDatabase = Depends(get_database),
# # ck: CKDrive = Depends(get_ck_db),
# # current_user: schemas.UserDB = Depends(deps.get_current_user)
# # ) -> schemas.Msg:
# # """获取当前项目所有用户数据权限"""
# #
# # roles = await crud.authority.find_many(db, ptype='g', v2=game)
# # for item in roles:
# # user = item['v0']
# # data_auth = await crud.authority.get_data_auth(db, username=request.user.name, game=game)
# # if not data_auth:
# # values = await ck.distinct(game, 'event', '#event_name')
# # return schemas.Msg(code=0, msg='ok', data={
# # 'data': values,
# # 'game': game,
# # 'name': '全部事件'
# # })
# # data_auth_id = data_auth['data_auth_id']
# # data = await crud.data_auth.get(data_auth_id)
# # return schemas.Msg(code=0, msg='ok', data=data)
# #
# # # data_auth = await crud.authority.get_data_auth(db, username=request.user.name, game=game)
# # # if not data_auth:
# # # values = await ck.distinct(game, 'event', '#event_name')
# # # return schemas.Msg(code=0, msg='ok', data={
# # # 'data': values,
# # # 'game': game,
# # # 'name': '全部事件'
# # # })
# # # data_auth_id = data_auth['data_auth_id']
# # # data = await crud.data_auth.get(data_auth_id)
# # return schemas.Msg(code=0, msg='ok')
#
#
# @router.post("/add_role")
# async def add_role(request: Request,
# data_in: schemas.CasbinRoleCreate,
# game: str = Depends(deps.get_game_project),
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """创建角色"""
#
# # 不允许角色名和用户名一样
# if await crud.user.get_by_user(db, name=data_in.role_name):
# return schemas.Msg(code=-1, msg='请改个名字')
# role_dom = game
# api_dict = dict()
# for r in request.app.routes:
# api_dict[r.path] = r.description if hasattr(r, 'description') else r.name
# # 角色有的接口权限
# for obj in data_in.role_api:
# casbin_enforcer.add_policy(data_in.role_name, role_dom, obj, '*')
# await crud.authority.update_one(db, {'ptype': 'p', 'v0': data_in.role_name, 'v1': role_dom, 'v2': obj},
# {'$set': {'api_name': api_dict.get(obj)}})
#
# # 管理员默认拥有该角色 方便从db中读出
# await crud.authority.create(db, 'g', settings.SUPERUSER_NAME, data_in.role_name, role_dom, '*',
# role_name=data_in.role_name,
# game=role_dom)
#
# return schemas.Msg(code=0, msg='ok')
#
#
# @router.post("/add_sys_role")
# async def add_sys_role(request: Request,
# data_in: schemas.CasbinRoleCreate,
# game: str = Depends(deps.get_game_project),
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """创建系统角色"""
# api_dict = dict()
#
# # 不允许角色名和用户名一样
# if await crud.user.get_by_user(db, name=data_in.role_name):
# return schemas.Msg(code=-1, msg='请改个名字')
#
# for r in request.app.routes:
# api_dict[r.path] = r.description if hasattr(r, 'description') else r.name
# # 角色有的接口权限
# for obj in data_in.role_api:
# casbin_enforcer.add_policy(data_in.role_name, '*', obj, '*')
# await crud.authority.create(db, 'p', data_in.role_name, '*', obj, '*', api_name=api_dict.get(obj))
#
# # 管理员默认拥有该角色 方便从db中读出
# await crud.authority.create(db, 'g', settings.SUPERUSER_NAME, data_in.role_name,
# role_name=data_in.role_name,
# game='*')
#
# return schemas.Msg(code=0, msg='ok')
#
#
# @router.post("/add_account")
# async def add_account(request: Request,
#
# data_in: schemas.AccountsCreate,
# game: str = Depends(deps.get_game_project),
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """添加账号"""
#
# # 用户名不能与角色名重复
# roles = casbin_enforcer.get_all_roles()
# accounts = {item.username for item in data_in.accounts}
# # 用户名不能与已存在的重复
# exists_user = await crud.user.get_all_user(db)
# if accounts & set(roles) or accounts & set(exists_user):
# return schemas.Msg(code=-1, msg='已存在', data=list(set(accounts) & set(roles) | accounts & set(exists_user)))
#
# """创建账号 并设置角色"""
# for item in data_in.accounts:
# account = schemas.UserCreate(name=item.username, password=settings.DEFAULT_PASSWORD)
# try:
# await crud.user.create(db, account)
# except pymongo.errors.DuplicateKeyError:
# return schemas.Msg(code=-1, msg='用户名已存在')
#
# casbin_enforcer.add_grouping_policy(item.username, item.role_name, game)
# # 设置数据权限
# await crud.authority.set_data_auth(db,
# schemas.DataAuthSet(username=item.username, data_auth_id=item.data_auth_id),
# game)
#
# # 添加到项目成员
# await crud.project.add_members(db, schemas.ProjectMember(project_id=data_in.project_id, members=list(accounts)))
#
# return schemas.Msg(code=0, msg='ok')
#
#
# @router.get("/all_role")
# async def all_role(request: Request,
# db: AsyncIOMotorDatabase = Depends(get_database),
# game: str = Depends(deps.get_game_project),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """获取所有角色"""
#
# app = request.app
# api_data = {}
# for r in app.routes:
# title = r.tags[0] if hasattr(r, 'description') else None
# if not title:
# continue
# api_data[r.path] = {
# 'api': r.path,
# 'title': title,
# 'name': r.description if hasattr(r, 'description') else r.name
# }
#
# """获取域内所有角色"""
# roles = await crud.authority.find_many(db, {'role_name': {'$exists': 1}, 'game': game})
# dom_data = [{'role': item['v1'], 'title': item['role_name'], 'id': str(item['_id'])} for item in roles]
# for item in dom_data:
# q = await crud.authority.get_role_dom_authority(db, item['role'], game, api_data)
# item['authority'] = [{'title': k, 'child': v} for k, v in q.items()]
#
# # 获取系统角色
# roles = await crud.authority.find_many(db, {'role_name':{'$exists': 1}, 'game':'*'})
# sys_data = [{'role': item['v1'], 'title': item['role_name'], 'id': str(item['_id'])} for item in roles]
# for item in sys_data:
# q = await crud.authority.get_role_dom_authority(db, item['role'], dom=game, api_data=api_data)
# item['authority'] = [{'title': k, 'child': v} for k, v in q.items()]
#
# data = {
# 'dom_role': dom_data,
# 'sys_role': sys_data
# }
# return schemas.Msg(code=0, msg='ok', data=data)
#
# # @router.post("/set_role")
# # async def set_role(request: Request,
# # data_id: schemas.AccountSetRole,
# # db: AsyncIOMotorDatabase = Depends(get_database),
# # current_user: schemas.UserDB = Depends(deps.get_current_user)
# # ) -> schemas.Msg:
# # """设置账号角色"""
# # casbin_enforcer.delete_user(data_id.name)
# # casbin_enforcer.add_role_for_user(data_id.name, data_id.role_name)
# # await crud.authority.update_one(db, {'ptype': 'g', 'v0': data_id.name}, dict(v1=data_id.role_name))
# #
# # return schemas.Msg(code=0, msg='ok')
#
# # @router.get("/delete_user")
# # async def delete_user(request: Request,
# # data_id: schemas.AccountDeleteUser,
# # db: AsyncIOMotorDatabase = Depends(get_database),
# # current_user: schemas.UserDB = Depends(deps.get_current_user)
# # ) -> schemas.Msg:
# # pass
# # return schemas.Msg(code=0, msg='暂时没有')

View File

@ -1,10 +1,11 @@
import pymongo import pymongo
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorDatabase
import crud, schemas import crud, schemas
from db import get_database from db import get_database
from api import deps from api import deps
from utils.func import get_uid
router = APIRouter() router = APIRouter()
@ -15,10 +16,246 @@ async def create(
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg: ) -> schemas.Msg:
"""创建看板"""
try: try:
await crud.dashboard.create(db, data_in, user_id=current_user.id) await crud.dashboard.create(db, data_in, user_id=current_user.id)
except pymongo.errors.DuplicateKeyError: except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='error', detail='看板已存在') return schemas.Msg(code=-1, msg='看板已存在', data='看板已存在')
# todo 建默认文件夹
return schemas.Msg(code=0, msg='ok', detail='创建成功') return schemas.Msg(code=0, msg='ok', data='创建成功')
@router.post('/edit_show_report')
async def edit_show_report(
request: Request,
data_in: schemas.EditShowReport,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""修改看板"""
report_id = data_in.config.report_id
res = await crud.dashboard.update_one(db, {'_id': data_in.dashboard_id, 'reports.report_id': report_id},
{'$set': {f'reports.$.{k}': v for k, v in
data_in.config.dict(skip_defaults=True).items()}})
if res.modified_count == 1:
return schemas.Msg(code=0, msg='ok', data=data_in.config)
elif res.modified_count == 0:
return schemas.Msg(code=-1, msg='没有修改', data=dict())
@router.post("/delete")
async def delete(
request: Request,
data_in: schemas.DashboardDelete,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""删除看板"""
del_dashboard = await crud.dashboard.delete(db, {'_id': {'$in': data_in.ids}})
if del_dashboard.deleted_count == 0:
return schemas.Msg(code=-1, msg='error', data='删除失败')
return schemas.Msg(code=0, msg='ok', data='删除成功')
@router.post("/move")
async def move(
data_in: schemas.DashboardMove,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
移动看板
"""
for source_id in data_in.source_ids:
res = await crud.dashboard.update_one(db, {'_id': source_id},
{'$set': dict(cat=data_in.cat, pid=data_in.dest_pid)})
return schemas.Msg(code=0, msg='ok', data='移动成功')
@router.post("/sort")
async def sort(
game: str,
data_in: schemas.DashboardSort,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
看板排序
"""
for item in data_in.sort:
await crud.dashboard.set_sort(db, index=item.dashboard_id, sort=item.sort)
return schemas.Msg(code=0, msg='ok', data=1)
@router.post("/copy")
async def copy(
request: Request,
data_in: schemas.DashboardCopy,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
复制到其他项目
"""
# 检查是否存在默认空间 不存在就创建
dest_project_id = data_in.dest_project_id
dest_default_space = await crud.space.find_one(db, {'project_id': dest_project_id, 'name': '默认空间'},
{'_id': True})
dest_space_id = dest_default_space.get('_id')
user_id = request.user.id
# 创建默认空间
if not dest_space_id:
default_space = await crud.space.create(db,
schemas.SpaceCreate(name='默认空间', project_id=dest_project_id),
user=current_user)
dest_space_id = default_space.inserted_id
dashboards = await crud.dashboard.find_many(db, {'_id': {'$in': data_in.source_ids}}, {'_id': False})
for item in dashboards:
item['project_id'] = dest_project_id
item['pid'] = dest_space_id
item['cat'] = 'space'
item['user_id'] = user_id
item['_id'] = get_uid()
for report in item['reports']:
report_id = report['report_id']
new_report = await crud.report.get(db, report_id)
new_report_id = get_uid()
report['report_id'] = new_report_id
new_report['user_id'] = user_id
new_report['_id'] = new_report_id
new_report['project_id'] = dest_project_id
try:
await crud.report.insert_one(db, new_report)
except:
exists_report = await crud.report.find_one(db, {'project_id': item['project_id'],
'user_id': item['user_id'], 'name': report['name']})
report['report_id'] = exists_report['_id']
try:
await crud.dashboard.update_one(db,
{'project_id': item['project_id'], 'name': item['name'],
'user_id': item['user_id']}, {'$set': item},
upsert=True)
except:
pass
return schemas.Msg(code=0, msg='ok', data='复制成功')
@router.post("/copy_to_my_space")
async def copy(
request: Request,
data_in: schemas.DashboardCopyToSpace,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
复制到自己空间
"""
# 检查是否存在默认空间 不存在就创建
dest_project_id = data_in.project_id
dest_space_id = data_in.dest_space_id
user_id = request.user.id
dashboards = await crud.dashboard.find_many(db, {'_id': {'$in': data_in.source_ids}}, {'_id': False})
for item in dashboards:
item['project_id'] = dest_project_id
item['pid'] = dest_space_id
item['user_id'] = user_id
item['cat'] = 'space'
item['_id'] = get_uid()
for report in item['reports']:
report_id = report['report_id']
new_report = await crud.report.get(db, report_id)
new_report_id = get_uid()
report['report_id'] = new_report_id
new_report['_id'] = new_report_id
new_report['user_id'] = user_id
new_report['project_id'] = dest_project_id
try:
await crud.report.insert_one(db, new_report)
except:
exists_report = await crud.report.find_one(db, {'project_id': item['project_id'],
'user_id': item['user_id'], 'name': report['name']})
report['report_id'] = exists_report['_id']
try:
await crud.dashboard.update_one(db,
{'project_id': item['project_id'], 'name': item['name'],
'user_id': item['user_id']}, {'$set': item},
upsert=True)
except:
pass
return schemas.Msg(code=0, msg='ok', data='复制成功')
@router.post("/add_report")
async def add_report(data_in: schemas.AddReport,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""添加报表"""
reports = [item.dict() for item in data_in.report_ids]
# res = await crud.dashboard.update_one(db, {'_id': data_in.id},
# {'$push': {'reports': {'$each': reports}}})
await crud.dashboard.update_one(db, {'_id': data_in.id},
{'$set': {'reports': reports}})
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/edit_report")
async def edit_report(data_in: schemas.EditReport,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""看板样式设置"""
res = await crud.dashboard.update_one(db, {'_id': data_in.id, 'reports.report_id': data_in.report.report_id},
{'$set': {f'reports.$.{k}': v for k, v in
data_in.report.dict(skip_defaults=True).items()}})
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/del_report")
async def del_report(
game: str,
data_in: schemas.DelReport,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""删除报表"""
del_item = {'report_id': data_in.report_id}
await crud.dashboard.update_one(db, {'_id': data_in.id}, {'$pull': {'reports': del_item}})
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/edit")
async def edit(
game: str,
data_in: schemas.EditDashboard,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""编辑看板名"""
await crud.dashboard.update_one(db, {'_id': data_in.dashboard_id}, {'$set': {'name': data_in.new_name}})
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/")
async def dashboards(request: Request,
game: str,
data_in: schemas.ReadDashboard,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""获取一个看板"""
res = await crud.dashboard.get(db, id=data_in.id)
reports = {item['report_id']: item for item in res['reports']}
reports_detail = await crud.report.find_many(db, {'_id': {'$in': list(reports.keys())}}, {'query.cachedata': False})
for item in reports_detail:
reports[item['_id']].update(item)
return schemas.Msg(code=0, msg='ok', data=reports)

View File

@ -0,0 +1,308 @@
import json
import pymongo
from bson import ObjectId
from fastapi import APIRouter, Depends, Request
from fastapi.encoders import jsonable_encoder
from motor.motor_asyncio import AsyncIOMotorDatabase
from redis import Redis
import crud, schemas
from core.config import settings
from core.security import get_password_hash
from db import get_database
from api import deps
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import get_redis_pool, RedisDrive
# from utils import casbin_enforcer
router = APIRouter()
# 疑似弃用
@router.post('/add_data_auth')
async def add_data_auth(request: Request,
data_id: schemas.DataAuthCreate,
game: str = Depends(deps.get_game_project),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""创建数据权限"""
await crud.data_auth.create(db, data_id, game)
return schemas.Msg(code=0, msg='ok', data=data_id)
# 疑似弃用
@router.post('/edit_data_auth')
async def edit_data_auth(request: Request,
data_id: schemas.DataAuthEdit,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""修改数据权限"""
await crud.data_auth.edit_data_auth(db, data_id)
return schemas.Msg(code=0, msg='ok', data=data_id)
#各数据类型在分析指标时可支持的计算方法
@router.get("/quotas_map")
async def quotas_map(
request: Request,
game: str,
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
return schemas.Msg(code=0, msg='ok', data=settings.CK_OPERATOR)
@router.get("/filter_map")
async def filter_map(
request: Request,
game: str,
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
# ck中不同的数据类型的不同计算规则
return schemas.Msg(code=0, msg='ok', data=settings.CK_FILTER)
@router.get('/all_event')
async def all_event(request: Request,
game: str,
ck: CKDrive = Depends(get_ck_db),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取所有事件"""
values = await ck.distinct(game, 'event', '#event_name')
values.sort()
return schemas.Msg(code=0, msg='ok', data=values)
@router.get("/list")
async def data_authority(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取前项目数据权限"""
total_event = await ck.distinct_count(game, 'event', '#event_name')
data = await crud.data_auth.get_game_data_auth(db, game)
for item in data:
item['id'] = str(item['_id'])
del item['_id']
item['data_range'] = f'{len(item["data"])}/{total_event}'
data = jsonable_encoder(data)
return schemas.Msg(code=0, msg='ok', data=data)
@router.get("/my_event")
async def my_event(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取自己的事件权限"""
event_list = []
# start_date = (datetime.datetime.now()-datetime.timedelta(days=30)).strftime('%Y-%m-%d %H:%M:%S')
# where = f"""`#event_time` > '{start_date}'"""
# my_data_auth = await ck.distinct(game, 'event', '#event_name',where)
my_data_auth = await rdb.smembers(f'{game}_event_set')
#
# else:
# # 设置了数据权限
# my_data_auth = await crud.data_auth.get(db, ObjectId(data_auth_id))
# my_data_auth = my_data_auth['data']
event_show_name, event_show_label_id= await crud.event_mana.get_all_show_name(db, game)
event_list.append({'id': 'event', 'title': '全部事件', 'category': []})
for item in my_data_auth:
event_list[-1]['category'].append({
'event_name': item,
'event_desc': event_show_name.get(item, item),
'event_label':event_show_label_id.get(item,'')
})
event_list[-1]['category'].append({'event_name': '*', 'event_desc': '任意事件','event_label':''})
event_list.sort()
return schemas.Msg(code=0, msg='ok', data=event_list)
@router.get("/user_property")
async def user_property(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取用户属性"""
data = await rdb.get(f'{game}_user')
data = json.loads(data)
propertys = []
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': 'user'})
data_attr = {item['name']: item for item in data_attr}
for k, v in data.items():
data_type = settings.CK_TYPE_DICT.get(v)
propertys.append(
{'name': k,
'data_type': data_type,
'show_name': data_attr.get(k, {}).get('show_name', ''),
}
)
propertys = sorted(propertys, key=lambda x: x['show_name']) # 按show_name排序
return schemas.Msg(code=0, msg='ok', data=propertys)
@router.post('/load_prop_quotas')
async def load_prop_quotas(request: Request,
game: str,
data_in: schemas.LoadProQuotas,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""事件属性 聚合条件"""
event_columns = await ck.get_columns(game, 'event') # 获取字段名和字段类型
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': 'event'})
data_attr = {item['name']: item for item in data_attr}
event_props = []
for item in event_columns:
data_type = settings.CK_TYPE_DICT.get(item['type'])
title = data_attr.get(item['name'], {}).get('show_name') or item['name']
event_prop = {
'id': item['name'],
'data_type': data_type,
'title': title,
# 'category': settings.CK_OPERATOR.get(data_type) or []
}
event_props.append(event_prop)
if data_in.model == 'scatter':
staid_quots = [
{
"id": "*",
"data_type": None,
"analysis": "times",
"title": "次数",
},
{
"id": "*",
"data_type": None,
"analysis": "number_of_days",
"title": "天数",
},
{
"id": "*",
"data_type": None,
"analysis": "number_of_hours",
"title": "小时数",
},
]
else:
staid_quots = [
{
"id": "*",
"data_type": None,
"analysis": "total_count",
"title": "总次数",
},
{
"id": "*",
"analysis": "touch_user_count",
"data_type": None,
"title": "触发用户数",
},
{
"id": "*",
"analysis": "touch_user_avg",
"data_type": None,
"title": "人均次数",
},
]
res = {
'props': event_props,
'staid_quots': staid_quots
}
return schemas.Msg(code=0, msg='ok', data=res)
@router.post('/load_filter_props')
async def load_filter_props(request: Request,
game: str,
data_in: schemas.LoadProQuotas,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""事件属性 过滤条件"""
event_columns = await ck.get_columns(game, 'event')
user_columns = await ck.get_columns(game, 'user')
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': 'event'})
data_attr = {item['name']: item for item in data_attr}
event_props = []
for item in event_columns:
data_type = settings.CK_TYPE_DICT.get(item['type'])
title = data_attr.get(item['name'], {}).get('show_name') or item['name']
event_prop = {
'id': item['name'],
'data_type': data_type,
'title': title,
}
event_props.append(event_prop)
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': 'user'})
data_attr = {item['name']: item for item in data_attr}
user_props = []
for item in user_columns:
data_type = settings.CK_TYPE_DICT.get(item['type'])
title = data_attr.get(item['name'], {}).get('show_name') or item['name']
user_prop = {
'id': item['name'],
'data_type': data_type,
'title': title,
}
user_props.append(user_prop)
user_label_props = []
user_label_docs = await crud.user_label.find_many(db, {'game': game}, {'qp': 0})
for item in user_label_docs:
tmp = {
'id': item['cluster_name'],
'data_type': 'user_label',
'title': item['display_name'],
}
user_label_props.append(tmp)
res = [
{
'title': '事件属性',
'id': 'event',
'category': event_props
},
{
'title': '用户属性',
'id': 'user',
'category': user_props
},
{
'title': '用户标签',
'id': 'user_label',
'category': user_label_props
}
]
return schemas.Msg(code=0, msg='ok', data=res)

View File

@ -0,0 +1,219 @@
import json
from aioredis import Redis
from fastapi import APIRouter, Depends, Request, File
from motor.motor_asyncio import AsyncIOMotorDatabase
import pandas as pd
import crud, schemas
from api import deps
from core.config import settings
from db import get_database
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import get_redis_pool
from utils import estimate_data,dict_to_str
router = APIRouter()
__all__ = 'router',
@router.get("/attr_list")
async def read_data_attr(
request: Request,
game: str,
cat: str,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: Redis = Depends(get_redis_pool),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""事件属性列表或用户属性列表"""
data = await rdb.get(f'{game}_{cat}')
data = json.loads(data)
res = []
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': cat})
data_attr = {item['name']: item for item in data_attr}
for k, v in data.items():
res.append(
{'name': k,
'data_type': settings.CK_TYPE_DICT.get(v),
'show_name': data_attr.get(k, {}).get('show_name', ''),
'is_show': data_attr.get(k, {}).get('is_show', True),
'attr_type': '预置属性' if k.startswith('#') else '自定义属性',
'unit': ''
}
)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/game_user_event_list")
async def read_data_attr(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""用户搜索时显示的用户属性"""
# data = await rdb.get(f'{game}_{data_in.cat}')
# data = json.loads(data)
# res = list(data.keys())
#event_columns = await ck.get_columns(game, 'event')
user_columns = await ck.get_columns(game, 'user')
data_attr = await crud.data_attr.find_many(db, {'game': game, 'cat': 'user'})
data_attr = {item['name']: item for item in data_attr}
user_props = []
for item in user_columns:
data_type = settings.CK_TYPE_DICT.get(item['type'])
title = data_attr.get(item['name'], {}).get('show_name') or item['name']
user_prop = {
'id': item['name'],
'data_type': data_type,
'title': title,
}
user_props.append(user_prop)
user_label_props = []
user_label_docs = await crud.user_label.find_many(db, {'game': game}, {'qp': 0})
for item in user_label_docs:
tmp = {
'id': item['cluster_name'],
'data_type': 'user_label',
'title': item['display_name'],
}
user_label_props.append(tmp)
res = [
{
'title': '用户属性',
'id': 'user',
'category': user_props
},
{
'title': '用户标签',
'id': 'user_label',
'category': user_label_props
}
]
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/attr_edit")
async def edit_data_attr(
request: Request,
game: str,
data_in: schemas.DataAttrEdit,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: Redis = Depends(get_redis_pool),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""编辑事件属性"""
await crud.data_attr.edit_data_attr(db, game, data_in)
return schemas.Msg(code=0, msg='ok', data=data_in)
# @router.post("/add_select_map")
# async def add_map(
# request: Request,
# game: str,
# data_in: schemas.SelectMap,
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ) -> schemas.Msg:
# """添加属性值选择映射"""
#
# """
# {
# game:aaa,
# attr_name:bbb,
# map_:{
# '区服aa':'1',
# '区服vvv':'5',
# }
#
# }
# """
# await crud.select_map.save(db, data_in)
# return schemas.Msg(code=0, msg='ok', data=data_in)
# 在gametoos同步区服了但在其他事件映射时需要用到
@router.post("/add_select_map")
async def add_select_map(
request: Request,
game: str,
file: bytes = File(...),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""添加游戏区服信息选择映射"""
dfs = pd.read_excel(file, engine='openpyxl', sheet_name=None)
for attr_name, df in dfs.items():
# 将id这列转换成字符串类型
if len(df) >0:
df['id'] = df['id'].astype(str)
map_ = df.to_dict('records')
data_in = schemas.SelectMap(game=game, attr_name=attr_name, map_=map_)
await crud.select_map.save(db, data_in)
return schemas.Msg(code=0, msg='ok', data=1)
@router.get("/select_list")
async def select_list(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""属性值选择映射列表"""
# 当游戏为魔法门H5时把game的值改为数据库中对应的值mdb中的值和ck中的值是不一样的
if game == 'mfmh5':
game='mzmfmh5'
resp = await crud.select_map.get_list(db, game)
return schemas.Msg(code=0, msg='ok', data=resp)
@router.post("/select_attr")
async def select_attr(
request: Request,
game: str,
data_in: schemas.SelectAttr,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""属性值选择映射"""
if game == "mfmh5":
game='mzmfmh5'
resp = await crud.select_map.get_select(db, data_in, game)
code = 0 if resp else -9
if resp:
if 'map_' in resp.keys():
return schemas.Msg(code=code, msg='ok', data=resp)
else:
resp['map_'] = resp.pop('owner_name')
return schemas.Msg(code=code, msg='ok', data=resp)
else:
return schemas.Msg(code=code, msg='ok', data=resp)
@router.post("/add_attr")
async def add_attr(
request: Request,
game: str,
data_in: schemas.Add_attr,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: Redis = Depends(get_redis_pool),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""添加事件属性或添加用户属性"""
data = await rdb.get(f'{game}_{data_in.cat}')
data = json.loads(data)
if data_in.state =='add':
# 判断传入数据类型
new_data_type=estimate_data(data_in.data_type)
# 添加数据
data[data_in.new_attribute]=new_data_type
else:
del data[data_in.new_attribute]
# 将字典转为字符串
str_data=dict_to_str(data)
await rdb.set(f'{game}_{data_in.cat}',str_data)
return schemas.Msg(code=0, msg='ok')

View File

@ -0,0 +1,65 @@
import json
from aioredis import Redis
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import pandas as pd
import crud, schemas
from api import deps
from core.config import settings
from db import get_database
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import get_redis_pool
router = APIRouter()
__all__ = 'router',
@router.get("/event_list")
async def event_list(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
ckdb: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""事件列表"""
# 获取事件名
try:
event_list = await ckdb.distinct(game, 'event', '#event_name') # 获取事件名
# 获取事件量
event_count = await ckdb.yesterday_event_count(game)
event_meta = await crud.event_mana.find_many(db, {'game': game}) or {}
except Exception as e:
return schemas.Msg(code=-9, msg='查无数据', data='')
if event_meta:
event_meta = pd.DataFrame(event_meta).set_index('event_name').fillna('').T.to_dict()
res = []
for name in event_list:
res.append({
'name': name,
'show_name': event_meta.get(name, {}).get('show_name', ''),
'is_show': event_meta.get(name, {}).get('is_show', True),
'desc': event_meta.get(name, {}).get('desc', ''),
'event_count': event_count.get(name, {}).get('v'),
'label_id' : event_meta.get(name, {}).get('label_id', '')
}
)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/event_edit")
async def event_edit(
request: Request,
game: str,
data_in: schemas.EventMateEdit,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""编辑事件"""
await crud.event_mana.edit_event_mate(db, game, data_in)
return schemas.Msg(code=0, msg='ok', data=data_in)

View File

@ -15,10 +15,26 @@ async def create(
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg: ) -> schemas.Msg:
"""创建文件夹"""
try: try:
await crud.folder.create(db, data_in, user_id=current_user.id) await crud.folder.create(db, data_in, user_id=current_user.id)
except pymongo.errors.DuplicateKeyError: except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='error', detail='文件夹已存在') return schemas.Msg(code=-1, msg='文件夹已存在', data='文件夹已存在')
# todo 建默认文件夹
return schemas.Msg(code=0, msg='ok', detail='创建成功') return schemas.Msg(code=0, msg='ok', data='创建成功')
@router.post("/delete")
async def delete(
data_in: schemas.FolderDelete,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""删除文件夹"""
# 删除文件夹 自己创建的
del_folder = await crud.folder.delete(db, _id=data_in.id, user_id=current_user.id)
# 删除文件夹下的 dashboard
del_dashboard = await crud.dashboard.delete(db, pid=data_in.id)
if del_folder.deleted_count == 0:
return schemas.Msg(code=-1, msg='error', data='删除失败')
return schemas.Msg(code=0, msg='ok', data='删除成功')

View File

@ -1,37 +1,310 @@
import pymongo import pymongo
from fastapi import APIRouter, Depends from bson import ObjectId
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorDatabase
import crud, schemas import crud, schemas
from api import deps from api import deps
from core.config import settings
from db import get_database from db import get_database
from db.ckdb import CKDrive, get_ck_db
from schemas.project import ProjectCreate from schemas.project import ProjectCreate
# from utils import casbin_enforcer
from utils import casbin_enforcer
router = APIRouter() router = APIRouter()
@router.post("/create") @router.post("/create")
async def create( async def create(
request: Request,
data_in: ProjectCreate, data_in: ProjectCreate,
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg: ) -> schemas.Msg:
"""创建项目"""
try: try:
await crud.project.create(db, data_in, user_id=current_user.id) res_project = await crud.project.create(db, data_in, current_user=request.user) # 创建项目
await crud.project_number.createxiangmu(db, data_in)
# 同步插入项目
# await crud.project_number.createxiangmu(db, data_in)
# 同步存入root权限中新项目的权限
user_url = await crud.user_url.get_quanxian(db,
schemas.Url_quanxian(user_id='04491842be9811eb8acdd5bd867f57d6'))
user_url['game'].append(data_in.game)
user_url['quanxian_id'].append('ab1')
user_url['quanxian'].append('root')
await crud.user_url.updata_quanxian(db, schemas.Url_quanxian(user=user_url['user'], user_id=user_url['user_id'],
game=user_url['game'],
quanxian_id=user_url['quanxian_id'],
quanxian=user_url['quanxian'])) # 配置权限
except pymongo.errors.DuplicateKeyError: except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='error', detail='项目名已存在') return schemas.Msg(code=-1, msg='项目名已存在', data='项目名已存在')
# todo 建默认文件夹
return schemas.Msg(code=0, msg='ok', detail='创建成功') folder = schemas.FolderCreate(
name='未分组',
project_id=res_project.inserted_id,
cat='kanban',
pid=res_project.inserted_id,
)
await crud.folder.create(db, folder, user_id=current_user.id)
folder = schemas.FolderCreate(
name='共享给我的',
project_id=res_project.inserted_id,
cat='kanban',
pid=res_project.inserted_id,
)
await crud.folder.create(db, folder, user_id=current_user.id)
# # 创建全部数据权限
# data_auth = schemas.DataAuthCreate(name='全部', data=['*'])
# await crud.data_auth.create(db, data_auth, data_in.game)
# 新建项目管理员权限
# role_name = f'{data_in.game}_admin'
# role_dom = data_in.game
# casbin_enforcer.add_policy(role_name, role_dom, '*', '*')
# await crud.authority.create(db, 'p', role_name, role_dom, '*', '*')
# 添加角色
# await crud.authority.create(db, 'g', settings.SUPERUSER_NAME, role_name, '*', '*', role_name='系统项目管理员', game='*')
# # 添加数据权限
# await crud.authority.set_data_auth(db, schemas.DataAuthSet(username=request.user.username, data_auth_id='*'),
# game=data_in.game, v1=role_name)
return schemas.Msg(code=0, msg='创建成功')
@router.get("/") @router.get("/")
async def read_project( async def read_project(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""查看自己拥有的项目"""
if request.user.username == 'root':
resp = await crud.project.all_game(db)
resp = sorted(resp, key=lambda x: x.get('sort') or 999)
else:
# game_list = casbin_enforcer.get_domains_for_user(request.user.username)
# resp = await crud.project.get_my_game(db, game_list)
project_data = await crud.user_url.get_quanxian(db, schemas.Url_quanxian(user_id=request.user.id))
resp = await crud.project.get_my_game(db, project_data['game'])
#把童话放在第一个
resp1=resp[-1]
resp.remove(resp[-1])
resp.insert(0,resp1)
return schemas.Msg(code=0, msg='ok', data=resp)
#获取项目名和渠道名project_name
@router.get("/project_name")
async def project_name(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
if request.user.username == 'root':
res = await crud.project_number.all_xiangmu(db)
for i in res:
i['_id'] = str(i['_id'])
return schemas.Msg(code=0,msg='ok',data=res)
#添加项目名,渠道名
@router.post("/add_project_name")
async def add_project_name(request: Request,
data_in: schemas.ProjectnumberInsert,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
#插入数据
#await crud.project_number.create(db, data_in)
#修改数据
await crud.project_number.update(db, data_in)
return schemas.Msg(code=0, msg='修改成功', data=True)
@router.get("/detail")
async def detail(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""查看项目信息"""
res = await crud.project.find_one(db, {'game': game})
event_count = await ck.count(game, 'event')
user_count = await ck.count(game, 'user_view')
event_type_count = await ck.distinct_count(game, 'event', '#event_name')
event_attr_count = await ck.field_count(db=game, tb='event')
user_attr_count = await ck.field_count(db=game, tb='user_view')
res['event_count'] = event_count
res['user_count'] = user_count
res['event_type_count'] = event_type_count
res['event_attr_count'] = event_attr_count
res['user_attr_count'] = user_attr_count
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/rename")
async def rename_project(request: Request,
game: str,
data_in: schemas.ProjectRename,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""修改项目名"""
try:
res = await crud.project.rename(db, data_in)
except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='项目名已存在')
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/add_members")
async def add_members(request: Request,
game: str,
data_in: schemas.ProjectAddMember,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""项目添加成员"""
for item in data_in.members:
# casbin_enforcer.add_grouping_policy(item.username, item.role_name, game)
# # 设置数据权限
# await crud.authority.set_data_auth(db,
# schemas.DataAuthSet(username=item.username, data_auth_id=item.data_auth_id),
# game)
folder = schemas.FolderCreate(
name='未分组',
project_id=data_in.project_id,
cat='kanban',
pid=data_in.project_id,
)
await crud.folder.create(db, folder, user_id=item.user_id)
await crud.project.add_members(db, schemas.ProjectMember(project_id=data_in.project_id,
members=[item.username for item in data_in.members]))
return schemas.Msg(code=0, msg='ok', data=data_in)
@router.post("/import_member")
async def import_member(request: Request,
game:str,
data_in:schemas.Import_project,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""成员管理中的导入其他项目的成员到本项目中"""
res=await crud.user_url.get_all(db)
for i in res:
for nu in range(len(i['game'])):
if data_in.games == i['game'][nu] and game not in i['game']:
i['game'].append(game)
i['quanxian_id'].append(i['quanxian_id'][nu])
i['quanxian'].append(i['quanxian'][nu])
await crud.user_url.updata_quanxian(db,schemas.Url_quanxian(game=i['game'],user=i['user'],user_id=i['user_id'],quanxian_id=i['quanxian_id'],
quanxian=i['quanxian']))
return schemas.Msg(code=0, msg='ok',data='' )
@router.post("/edit_member")
async def edit_member(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""编辑成员权限 角色和数据"""
pass
return schemas.Msg(code=0, msg='ok', )
#
#
@router.get("/members")
async def members(request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""查看项目成员"""
# data = casbin_enforcer.get_all_users_by_domain(game)
# names = []
# role_ids = []
# for item in data:
# names.append(item['username'])
# role_ids.append(item['role_id'])
# users = await crud.user.get_by_users(db, {'name': {'$in': names}})
# roles = await crud.role.find_ids(db, role_ids)
# users = {item.name: item.dict() for item in users.data}
# roles = {item['_id']: item['name'] for item in roles}
# res = []
# for item in data:
# username = item['username']
# role_id = item['role_id']
# try:
# res.append({
# **users[username],
# 'role': roles[role_id],
# 'role_id': role_id,
# })
# except:
# pass
# # res.append({
# # **users[username],
# # 'role': roles[role_id],
# # 'role_id': role_id,
# # })
# return schemas.Msg(code=0, msg='ok', data=res)
res = await crud.user_url.get_all(db)
# 符合当前项目权限的用户
names = []
# 符合当前项目权限的用户的对应权限级别
quanxian = {}
quanxian_id = {}
for i in res:
for nu in range(len(i['game'])):
if game == i['game'][nu]:
names.append(i['user'])
quanxian[i['user']] = i['quanxian'][nu]
quanxian_id[i['user']] = i['quanxian_id'][nu]
users = await crud.user.get_by_users(db, {'name': {'$in': names}})
data = []
for use in users.data:
use = use.dict()
use['role'] = quanxian[use['name']]
use['role_id'] = quanxian[use['name']]
data.append(use)
return schemas.Msg(code=0, msg='ok', data=data)
# @router.post("/del_member")
# async def members(request: Request,
# game: str,
# data_in: schemas.ProjectDelMember,
# db: AsyncIOMotorDatabase = Depends(get_database),
# current_user: schemas.UserDB = Depends(deps.get_current_user)
# ):
# """删除项目成员"""
# # casbin_enforcer.delete_roles_for_user_in_domain(data_in.username, data_in.role, game)
# await crud.project.del_members(db, data_in)
# # await crud.authority.delete(db, ptype='g', v2=game, v0=data_in.username)
# return schemas.Msg(code=0, msg='ok')
@router.post("/clean")
async def read_kanban(
data_in: schemas.ProjectClean,
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
): ):
res = await crud.project.read_project(db, user_id=current_user.id) """
return res 清理项目 删除项目所有内容
:param data_in:
:param db:
:param current_user:
:return:
"""
# 删除 报表
await crud.report.delete(db, {'project_id': data_in.project_id})
# 删除 空间
await crud.space.delete(db, {'project_id': data_in.project_id})
# 删除 文件夹
await crud.folder.delete(db, {'project_id': data_in.project_id})
# 删除 看板
await crud.dashboard.delete(db, {'project_id': data_in.project_id})
return schemas.Msg(code=0, msg='ok')
@router.post("/kanban") @router.post("/kanban")
@ -40,57 +313,61 @@ async def read_kanban(
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
): ):
res = {'kanban': [], 'space': []} """获取自己的看板"""
res = {'kanban': [], 'spaces': []}
# 我的看板 # 我的看板
kanban = await crud.folder.read_folder(db, project_id=data_in.id, user_id=current_user.id, cat='kanban') kanban = await crud.folder.read_folder(db, project_id=data_in.id, user_id=current_user.id, cat='kanban')
for item in kanban: for item in kanban:
dashboards = await crud.dashboard.find_many(db, pid=item['_id'])
res['kanban'].append({ res['kanban'].append({
'folder_name': item['name'], 'name': item['name'],
'dashboards': [], 'children': [],
'_id': item['_id'] '_id': item['_id']
}) })
for d in dashboards: async for d in crud.dashboard.find(db, {'pid': item['_id']}).sort([('sort', 1)]):
res['kanban'][-1]['dashboards'].append({ res['kanban'][-1]['children'].append({
'name': d['name'], 'name': d['name'],
'_id': item['_id'] '_id': d['_id']
}) })
# 我的空间 # 我的空间
where = { where = {
'project_id': data_in.id, 'project_id': data_in.id,
'$or': [{'rw_members': current_user.id}, {'r_members': current_user.id}] 'members.user_id': current_user.id
# '$or': [{'rw_members': current_user.id}, {'r_members': current_user.id}]
} }
spaces = await crud.space.find_many(db, **where) spaces = await crud.space.find_many(db, where)
# 空间 文件夹 看板 # 空间 文件夹 看板
for item in spaces: for item in spaces:
res['space'].append({ res['spaces'].append({
'space_name': item['name'], 'name': item['name'],
'folders': [], 'children': [],
'dashboards': [],
'_id': item['_id'] '_id': item['_id']
}) })
res['space'][-1]['authority'] = 'rw' if current_user.id in item['rw_members'] else 'r' authority = {item['user_id']: item['authority'] for item in item['members']}
res['spaces'][-1]['authority'] = authority.get(current_user.id, 'r')
for f in await crud.folder.find_many(db, pid=item['_id']): for f in await crud.folder.find_many(db, {'pid': item['_id']}):
res['space'][-1]['folders'].append({ res['spaces'][-1]['children'].append({
'name': f['name'], 'name': f['name'],
'_id': f['_id'], '_id': f['_id'],
'dashboards': [], 'children': [],
'isFolder': True
}) })
for d in await crud.dashboard.find_many(db, pid=f['_id']): async for d in crud.dashboard.find(db, {'pid': item['_id']}).sort([('sort', 1)]):
res['space'][-1]['folders'][-1]['dashboards'].append({ res['spaces'][-1]['children'][-1]['children'].append({
'name': d['name'], 'name': d['name'],
'_id': d['_id'] '_id': d['_id']
}) })
# 空间 看板 # 空间 看板
for d in await crud.dashboard.find_many(db, pid=item['_id']): async for d in crud.dashboard.find(db, {'pid': item['_id']}).sort([('sort', 1)]):
res['space'][-1]['dashboards'].append({ res['spaces'][-1]['children'].append({
'name': d['name'], 'name': d['name'],
'_id': d['_id'] '_id': d['_id'],
'user_id':d['user_id'],
'isFolder': False
}) })
return res return schemas.Msg(code=0, msg='ok', data=res)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
from typing import Any
import pymongo
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud, schemas
from db import get_database
from api import deps
from utils import get_uid
router = APIRouter()
@router.post("/create")
async def create(
request: Request,
data_in: schemas.ReportCreate,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""新建报表"""
try:
await crud.report.create(db, data_in, user_id=request.user.id)
except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='error', data='报表已存在')
return schemas.Msg(code=0, msg='ok', data='创建成功')
@router.post("/edit")
async def edit(
request: Request,
data_in: schemas.ReportEdit,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""编辑报表"""
res = await crud.report.update_one(db, {'_id': data_in.report_id},
{'$set': {'query': data_in.query, 'name': data_in.name, 'desc': data_in.desc}})
#只能报表所有者编辑
# res = await crud.report.update_one(db, {'_id': data_in.report_id, 'user_id': request.user.id},
# {'$set': {'query': data_in.query, 'name': data_in.name, 'desc': data_in.desc}})
# if not res.matched_count:
# #if res.matched_count:
# return schemas.Msg(code=-1, msg='只能报表所有者编辑')
return schemas.Msg(code=0, msg='ok', data='编辑成功')
@router.post("/copy")
async def copy(
request: Request,
data_in: schemas.ReportCopy,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""复制报表到其他项目"""
for report_id in data_in.report_ids:
new_report = await crud.report.get(db, report_id)
if not new_report:
continue
new_report_id = get_uid()
new_report['_id'] = new_report_id
new_report['project_id'] = data_in.dest_project_id
await crud.report.insert_one(db, new_report)
return schemas.Msg(code=0, msg='ok', data='编辑成功')
@router.post("/read_report")
async def read_report(
request: Request,
data_in: schemas.ReportRead,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> Any:
"""获取已建报表 属于自己的"""
ext_where = dict()
dashboard = dict()
if data_in.report_id:
ext_where = {'_id': {'$in': data_in.report_id}}
else:
ext_where['user_id'] = request.user.id
if data_in.dashboard_id:
dashboard = await crud.dashboard.get(db, id=data_in.dashboard_id)
# projection = {'query': False}
projection = None
#获取已建报表 属于自己的
reports = await crud.report.read_report(db, project_id=data_in.project_id,
projection=projection, **ext_where)
#有权限的都能获取到
# reports = await crud.report.read_report(db, project_id=data_in.project_id,
# projection=projection)
for item in reports:
item['added'] = False
# item['name'] = item['name']
item['show_config'] = dict()
added_ids = {item['report_id']: item for item in dashboard.get('reports', [])}
if item['_id'] in added_ids:
item['added'] = True
item['show_config'] = added_ids[item['_id']]
#保存的看板按备注显示的数据显示
if type(item['query']['events']) == list:
event_show_name = await crud.event_mana.get_all_show_name(db, game)
for i in item['query']['events']:
if 'event_name' in i:
if i['event_name'] in event_show_name:
if 'event_desc' in i :
event_name= i['event_name']
i['event_desc']= event_show_name[event_name]
else:
event_name = i['event_name']
i['eventDesc'] = event_show_name[event_name]
else:
if i['eventName'] in event_show_name:
if 'event_desc' in i :
event_name= i['eventName']
i['event_desc']= event_show_name[event_name]
else:
event_name = i['eventName']
i['eventDesc'] = event_show_name[event_name]
#放置争霸
if type(item['query']['events']) == dict:
data_attr = await crud.data_attr.find_many(db, {'game': game})
data_attr = {item['name']: item for item in data_attr}
item_dict=item['query']['events']
for k,v in item_dict.items():
if k == 'quotaDesc':
if item_dict['quotaDesc'] in data_attr:
item_dict['quotaDesc']=data_attr[item_dict['quotaDesc']]['show_name']
# for k,v in event_show_name.items():
# if 'event_desc' in item['query']['events'][0]:
# event_desc = item['query']['events'][0]['event_desc']
# if k == event_desc:
# item['query']['events'][0]['event_desc'] = event_show_name[event_desc]
# else:
# event_desc = item['query']['events'][0]['eventDesc']
# if k == event_desc:
# item['query']['events'][0]['eventDesc'] = event_show_name[event_desc]
reports = sorted(reports, key=lambda x: x.get('show_config', {'sort': 999}).get('sort', 999) or 999)
return schemas.Msg(code=0, msg='ok', data=reports)
@router.post("/delete")
async def delete(
request: Request,
data_in: schemas.ReportDelete,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""删除报表"""
# 删除Report 自己创建的
del_report = await crud.report.delete(db, {'_id': data_in.id, 'user_id': current_user.id})
# 从看板弹出
del_item = {'report_id': data_in.id}
await crud.dashboard.update_many(db, {}, {'$pull': {'reports': del_item}})
if del_report.deleted_count == 0:
return schemas.Msg(code=-1, msg='error', data='删除失败')
return schemas.Msg(code=0, msg='ok', data='删除成功')

View File

@ -11,14 +11,89 @@ router = APIRouter()
@router.post("/create") @router.post("/create")
async def create( async def create(
game: str,
data_in: schemas.SpaceCreate, data_in: schemas.SpaceCreate,
db: AsyncIOMotorDatabase = Depends(get_database), db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user) current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg: ) -> schemas.Msg:
"""创建空间"""
try: try:
await crud.space.create(db, data_in, user_id=current_user.id) if data_in.is_all_member:
data_in.members.clear()
users = await crud.user.find_many(db)
for user in users:
if user['_id'] == current_user.id:
continue
data_in.members.append(schemas.space.Member(**user, authority=data_in.authority))
await crud.space.create(db, data_in, user=current_user)
except pymongo.errors.DuplicateKeyError: except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='error', detail='空间已存在') return schemas.Msg(code=-1, msg='空间已存在', data='空间已存在')
# todo 建默认文件夹
return schemas.Msg(code=0, msg='ok', detail='创建成功') return schemas.Msg(code=0, msg='创建成功', data='创建成功')
@router.post("/delete")
async def delete(
data_in: schemas.SpaceDelete,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""删除空间"""
# 删除空间 自己创建的
del_space = await crud.space.delete(db, {'_id': data_in.id})
# 删除文件夹
del_folder = await crud.folder.find_many(db, {'pid': data_in.id})
del_folder_ids = [f['_id'] for f in del_folder]
await crud.folder.delete(db, {'pid': data_in.id})
# 删除文件夹下的 dashboard
if del_folder_ids:
await crud.dashboard.delete(db, {'_id': {'$in': del_folder_ids}})
# 删除空间下的 dashboard
await crud.dashboard.delete(db, {'pid': data_in.id})
if del_space.deleted_count == 0:
return schemas.Msg(code=-1, msg='error', data='删除失败')
return schemas.Msg(code=0, msg='ok', data='删除成功')
@router.post("/rename")
async def rename(
data_in: schemas.SpaceRename,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""重命名空间"""
res = await crud.space.rename(db, data_in)
return schemas.Msg(code=0, msg='ok', data=1)
@router.post("/set_members")
async def set_members(
data_in: schemas.AddSpaceMembers,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""设置空间成员"""
res = await crud.space.set_members(db, data_in)
return schemas.Msg(code=0, msg='ok', data=1)
@router.post("/detail")
async def detail(
data_in: schemas.SpaceDetail,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""空间详细"""
space_info = await crud.space.get(db, id=data_in.space_id)
exists_member = {item.get('user_id') for item in space_info.get('members', [])}
members_info = await crud.user.find_ids(db, list(exists_member))
members_info = {item['_id']: item for item in members_info}
for item in space_info.get('members', []):
if user_info := members_info.get(item['user_id']):
item.update(schemas.UserDB(**user_info).dict(by_alias=True))
return schemas.Msg(code=0, msg='ok', data=space_info)

View File

@ -0,0 +1,39 @@
from typing import Any
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud
import schemas
from api import deps
from db import get_database
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import RedisDrive, get_redis_pool
from models.behavior_analysis import BehaviorAnalysis
router = APIRouter()
@router.post("/test")
async def test(
request: Request,
rdb: RedisDrive = Depends(get_redis_pool),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user),
):
"""api 列表"""
app = request.app
data = {}
for r in app.routes:
title = r.tags[0] if hasattr(r, 'description') else None
if not title:
continue
data.setdefault(title, {'list': []})
path = r.path
name = r.description if hasattr(r, 'description') else r.name
data[title]['list'].append({'api': path, 'title': name})
res = [{'title': k, 'list': v['list']} for k, v in data.items()]
return schemas.Msg(code=0, msg='ok', data=res)

View File

@ -1,6 +1,7 @@
from datetime import timedelta from datetime import timedelta
from typing import Any from typing import Any
import redis
from fastapi import APIRouter, Body, Depends, HTTPException, Request from fastapi import APIRouter, Body, Depends, HTTPException, Request
from fastapi.security import OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordRequestForm
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
@ -9,45 +10,84 @@ import crud, schemas
from api import deps from api import deps
from core import security from core import security
from core.config import settings from core.config import settings
from core.security import get_password_hash from db.redisdb import RedisDrive, get_redis_pool
from utils import get_uid, random_hex
from db import get_database from db import get_database
from utils import ( from utils.dingding import send_dates
verify_password_reset_token,
)
router = APIRouter() router = APIRouter()
host = settings.REDIS_CONF.get('host')
port = settings.REDIS_CONF.get('port')
db = settings.REDIS_CONF.get('db')
password = settings.REDIS_CONF.get('password')
redisdb = redis.Redis(host=host, port=port, db=db,password=password)
@router.post("/send_auth_code")
async def reset_password(request: Request,
data_in: schemas.send,
db: AsyncIOMotorDatabase = Depends(get_database),
rdb: RedisDrive = Depends(get_redis_pool)
):
"""发送验证码"""
res= await crud.user.get_by_user(db,data_in.name)
user_id=res['user_id']
# X平台登陆提醒你的验证码是7933
if res['types'] == 1: # 内部员工发送验证码
code=random_hex(4)
content=f'X平台登陆提醒你的验证码是{code}'
send_dates(content, [user_id]) # 发送验证码
redisdb.set(name=user_id, value=code, ex=120) # 120秒
return schemas.Msg(code=0, msg='ok',data='')
@router.post("/login") @router.post("/login")
async def login( async def login(
# data: schemas.UserLogin, # data: schemas.UserLogin,
#code:str,
data: OAuth2PasswordRequestForm = Depends(), data: OAuth2PasswordRequestForm = Depends(),
db: AsyncIOMotorDatabase = Depends(get_database) db: AsyncIOMotorDatabase = Depends(get_database)
) -> dict: ) -> Any:
""" """
OAuth2兼容令牌登录获取将来令牌的访问令牌 OAuth2兼容令牌登录获取将来令牌的访问令牌
""" """
user = await crud.user.authenticate(db, user = await crud.user.authenticate(db,
name=data.username, password=data.password name=data.username, password=data.password
) )
if user.types == 1: # 内部员工校验验证码
rdbcode=redisdb.get(user.user_id)
if rdbcode == None:
return schemas.Msg(code=-1, msg='验证码过期')
if rdbcode.decode() != data.scopes[0]:
return schemas.Msg(code=-1, msg='验证码错误')
if not user: if not user:
raise HTTPException(status_code=400, detail="Incorrect name or password") # raise HTTPException(status_code=400, detail="Incorrect name or password")
return schemas.Msg(code=-1, msg='密码或用户名错误')
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
# access_token_expires = timedelta(seconds=5)
await crud.user.update_login_time(db, data.username)
return { return {
'data': { 'data': {
'name': user.name, 'name': user.name,
'nickname': user.nickname,
'email': user.email, 'email': user.email,
# 'access_token': security.create_access_token( 'tel': user.tel,
# expires_delta=access_token_expires, id=user.id, email=user.email, is_active=user.is_active, 'userid': user.id,
# is_superuser=user.is_superuser, name=user.name
# ), 'token': security.create_access_token(
# "token_type": "bearer", expires_delta=access_token_expires, _id=str(user.id), email=user.email,
nickname=user.nickname,
is_superuser=user.is_superuser, name=user.name,
data_where=user.data_where,
),
"token_type": "bearer",
}, },
'access_token': security.create_access_token( 'access_token': security.create_access_token(
expires_delta=access_token_expires, _id=str(user.id), email=user.email, expires_delta=access_token_expires, _id=str(user.id), email=user.email,
is_superuser=user.is_superuser, name=user.name nickname=user.nickname,
is_superuser=user.is_superuser, name=user.name, data_where=user.data_where
), ),
"token_type": "bearer", "token_type": "bearer",
@ -62,3 +102,93 @@ def me(current_user: schemas.User = Depends(deps.get_current_user)) -> Any:
Test access token Test access token
""" """
return current_user return current_user
@router.post("/reset_password")
async def reset_password(request: Request,
game: str,
data_in: schemas.UserRestPassword,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
修改其他人密码
"""
try:
await crud.user.reset_password(db, data_in)
except Exception as e:
return schemas.Msg(code=0, msg='修改失败', data={'username': data_in})
return schemas.Msg(code=0, msg='ok')
@router.post("/reset_my_password")
async def reset_password(request: Request,
game: str,
data_in: schemas.UserRestMyPassword,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
修改自己的密码
"""
await crud.user.reset_password(db, schemas.UserRestPassword(username=current_user.name, password=data_in.password))
return schemas.Msg(code=0, msg='ok')
@router.post("/edit_profile")
async def edit_profile(request: Request,
game: str,
data_in: schemas.UserProfileEdit,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
编辑用户资料
"""
await crud.user.edit_profile(db, data_in, user_id=request.user.id)
return schemas.Msg(code=0, msg='ok', data=data_in)
@router.get("/all_account")
async def all_account(page: int = 1, limit: int = 100, db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
获取所有用户
"""
page -= 1
if page < 0:
page = 0
cursor = crud.user.find(db).skip(page * limit).limit(limit)
data = [schemas.UserDB(**user) async for user in cursor]
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/add_account")
async def all_account(
data_in: schemas.CreateAccount,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
创建新账号
"""
created = []
id = []
for name in data_in.account_list:
if is_exists := await crud.user.exists(db, {'name': name}):
continue
else:
new_account = schemas.UserCreate(name=name, password='123')
created.append(name)
# 创建账户并返回id
id_one = await crud.user.create(db, new_account)
id.append(id_one)
res = {
'created_account': created,
'password': '123',
'id': id
}
return schemas.Msg(code=0, msg='ok', data=res)

View File

@ -0,0 +1,272 @@
import datetime
import mimetypes
from collections import defaultdict
import time
from urllib.parse import quote
import re
from clickhouse_driver import Client
import pandas as pd
import numpy as np
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
from pandas import DataFrame
from starlette.responses import StreamingResponse
import crud, schemas
from common import *
from api import deps
from db import get_database
from db.ckdb import get_ck_db, CKDrive, ckdb
from db.redisdb import get_redis_pool, RedisDrive
from models.behavior_analysis import BehaviorAnalysis
from models.user_analysis import UserAnalysis
from models.x_analysis import XAnalysis
from utils import DfToStream, get_bijiao
router = APIRouter()
@router.post("/ltv_model_sql")
async def ltv_model_sql(
request: Request,
game: str,
analysis: XAnalysis = Depends(XAnalysis),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
""" ltv模型sql """
await analysis.init(data_where=current_user.data_where)
data = analysis.ltv_model_sql()
return schemas.Msg(code=0, msg='ok', data=[data])
@router.post("/ltv_model")
async def ltv_model_sql(
request: Request,
game: str,
analysis: XAnalysis = Depends(XAnalysis),
ckdb: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
""" ltv模型sql """
await analysis.init(data_where=current_user.data_where)
res = await analysis.ltv_model_sql()
sql = res['sql'].replace('/n','').replace('[','').replace(']','')
#仅一条筛选条件则是把GM过滤后获取全部数据
# if len(analysis.global_filters)==1 and analysis.global_filters[0]['strftv']=='GM':
try:
df = await ckdb.query_dataframe(sql)
except Exception as e:
return schemas.Msg(code=-9, msg='报表配置参数异常')
#多条筛选条件则合成新的sql
# else:
# new_sql=""""""
# #拆分sql
# split_sql = sql.split('AND 1')
# #获取每一条筛选条件
# for i in analysis.global_filters:
# #剔除GM
# if i['strftv'] != 'GM':
# #获取筛选条件的包含关系
# bijiao=get_bijiao(i["comparator"])
# #获取筛选条件的值
# condition=tuple(i['ftv'])
# #获取事件名
# columnName=i['columnName']
# dd = f""" AND {game}.event.{columnName} {bijiao} {condition}"""
# new_sql+=dd
# split_="""AND 1 """
# news_sql = split_sql[0] + split_+new_sql + split_sql[1] + split_+new_sql+ split_sql[2]+split_+split_sql[3]
# df = await ckdb.query_dataframe(news_sql)
# # 判断11月23号之前的数据
# list_data_range=analysis.date_range
# liststr_data_range=[]
# for i in list_data_range:
# liststr_data_range.append(str(i))
# quota = analysis.event_view['quota']
# #判断是设备LTV则执行下面代码如是角色实充LTV则不执行
# if quota == '#distinct_id':
# if '2021-11-22' in liststr_data_range or '2021-11-22' >=liststr_data_range[-1]:
# #取搜索最后为11.23号之前的数据
# if '2021-11-22' >=liststr_data_range[-1]:
# news_sql=""""""
# split_sql=sql.split('AND is_new_device = 1')
# new_sql=split_sql[0]+split_sql[1]+split_sql[2]
# news_sql+=new_sql
# df_twenty_three=await ckdb.query_dataframe(news_sql)
# #取包含有11.23号之前和23号之后的那一段
# else:
# start_date=str(list_data_range[0])
# end_date='2021-11-22'
# news_sql = """"""
# split_sql = sql.split('AND is_new_device = 1')
# for i in split_sql:
# news_sql += i
# #用正则表达式切时间
# zhengze_time=r'\d{4}-\d{1,2}-\d{1,2}'
# zhengze_sql=re.split(zhengze_time,news_sql)
# zz_new_sql=zhengze_sql[0]+start_date+zhengze_sql[1]+end_date+zhengze_sql[2]+start_date+zhengze_sql[3]+end_date+zhengze_sql[4]
# zz_news_sql=""""""
# zz_news_sql+=zz_new_sql
# df_twenty_three = await ckdb.query_dataframe(zz_news_sql)
# #上下合并两组数据,忽略以前的索引下标
# df= pd.concat([df,df_twenty_three], axis=0, ignore_index=True)
# df.sort_values('date', inplace=True)
# #去重
# #df.drop_duplicates(inplace=True)
quota = res['quota'] #字段名
ltv_n = res['ltv_n']
#df = await ckdb.query_dataframe(sql)
if df.empty:
return schemas.Msg(code=-9, msg='查无数据')
df.fillna(0, inplace=True) #修改原对象以0填补空缺值
# for d in set(res['date_range']) - set(df['date']): # 时间的差集运算 最后为空
# df.loc[len(df)] = 0
# df.loc[len(df) - 1, 'date'] = d
# days = (pd.Timestamp.now().date() - d).days # 时间差
# # if days + 2 >= ltv_len:
# # continue
# df.iloc[len(df) - 1, days + 3:] = '-'
# df.sort_values('date', inplace=True) # 根据date进行倒叙排序
for d in set(res['date_range']) - set(df['date']):
#在有效日期最后一行补充行数据(值都为'-'),补充的行数为两个集合的差集长度
df.loc[len(df)] = '-'
#在date此列补充多行数据值为两个集合差集的子元素
df.loc[len(df) - 1, 'date'] = d
# days = (d-pd.Timestamp.now().date()).days
# # if days + 2 >= ltv_len:
# # continue
# if days>0:
# df.iloc[len(df) - 1, 1:] = '-'
df.sort_values('date', inplace=True)
df.rename(columns={'date': '注册日期'}, inplace=True) #True为将结果返回赋值给原变量修改原对象columns为列名
cat = '角色数'
if quota == '#distinct_id': #如果字段名=字段名
cat = '设备数'
df.rename(columns={'cnt1': cat}, inplace=True) #原数据基础上修改df里面列名为cnt1为设备数
df1 = df[['注册日期', cat, *[f'LTV{i}' for i in ltv_n]]] #1, 2, 3, 4, 5, 6, 7, 8, 9, ~~到360
df2 = df[['注册日期', cat, *[f'sumpay_{i}' for i in ltv_n]]]
df2.replace('-', 0, inplace=True) #True改变原数据前面是需要替换的值后面是替换后的值。 在原数据把下划线替换成0
#修改下面代码
# 去除sumpay_2的值为0的列
new_df2 = (df2.drop(df2[(df2.sumpay_2 == 0)].index))
#为new_df2排序
new_df2=new_df2.reset_index(drop=True)
#求相差天数
str_time = df2['注册日期'][0]
#str_time =new_df2['注册日期'][0]
str_time01=str(str_time)
split_time = str_time01.split('-')
#str_time = str(res['date_range'][0])
# split_time = str_time.split('-')
now_time=time.strftime("%Y-%m-%d",time.localtime())
split_now_time = now_time.split('-')
today = datetime.datetime(int(split_time[0]), int(split_time[1]), int(split_time[2]))
now_day = datetime.datetime(int(split_now_time[0]), int(split_now_time[1]), int(split_now_time[2]))
newday = (now_day - today).days + 1
#计算方法运算每个LTV的均值
_listData = {}
for i in ltv_n:
if i <=newday:
#计算均值
#avgLtv = (new_df2[[f'sumpay_{i}']][0:newday + 1 - i].sum() / new_df2[cat][0:newday + 1 - i].sum()).round(2)
#12.20号计算LTV均值的时候分母包括当天未充值新增设备数比剔除掉的计算值偏小
avgLtv = (df2[[f'sumpay_{i}']][0:newday + 1 - i].sum() / df2[cat][0:newday + 1 - i].sum()).round(2)
#取出均值
new_avgLtv=str(avgLtv).split('\n')[0].split(' ')
new_avgLtv01=new_avgLtv[len(new_avgLtv)-1]
if new_avgLtv01 == 'NaN':
_listData[f'sumpay_{i}'] = '-'
else:
_listData[f'sumpay_{i}'] = new_avgLtv01
#原代码
# avgLtv=(df2[[f'sumpay_{i}']][0:newday+1-i].sum()/df2[cat][0:newday+1-i].sum()).round(2)
# new_avgLtv=str(avgLtv).split('\n')[0].split(' ')
# new_avgLtv01=new_avgLtv[len(new_avgLtv)-1]
# if new_avgLtv01 == 'NaN':
# _listData[f'sumpay_{i}'] = '-'
# else:
# _listData[f'sumpay_{i}'] = new_avgLtv01
else:
_listData[f'sumpay_{i}']='-'
avgLtvlist = pd.Series(_listData)
_listname=[]
#计算总累计LTV最后一个值
for k, v in _listData.items():
if v != 0 or v!= '-':
# if v !=0:
_listname.append(k)
max_nmu=max(_listname)
#max_num = (new_df2[[max_nmu]].sum() / new_df2[cat].sum()).round(2)
max_num=(df2[[max_nmu]].sum()/df2[cat].sum()).round(2)
max_number=str(max_num[0])
df1.loc[len(df1)] = ['均值', df2[cat].sum(), *avgLtvlist]
#原代码
#df1.loc[len(df1)] = ['均值', df2[cat].sum(), *avgLtvlist]
# avg_ltv = (df2[[f'sumpay_{i}' for i in ltv_n]].sum() / df2[cat].sum()).round(2)
#df1.loc[len(df1)] = ['均值', df2[cat].sum(), *avg_ltv]
df1.insert(2, '累计LTV', 0)
last_ltv = []
for items in df1.values:
for item in items[::-1]:
if item != '-':
last_ltv.append(item)
break
#修改累计LTV中最后一个值
last_ltv[-1]=max_number
df1['累计LTV'] = last_ltv
#把列中累计LTV等于0的值改成'-'
#df1.loc[df1['累计LTV']==0, '累计LTV'] = '-'
#剔除行列的累计LTV=='-'的剔除出去
df3 = df1.drop(df1[(df1.LTV1 == '-')].index)
#df3 = df1.drop(df1[(df1.累计LTV=='-')].index)
days = (pd.Timestamp.now().date() - pd.to_datetime(res['start_date']).date()).days
df1.iloc[len(df1) - 1, days + 4:] = '-'
data = {
#'title': df1.columns.tolist(),
#'rows': df1.values.tolist(),
'title': df3.columns.tolist(),
'rows': df3.values.tolist(),
'start_date': res['start_date'],
'end_date': res['end_date']
}
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/ltv_model_export")
async def ltv_model_export(request: Request,
game: str,
ckdb: CKDrive = Depends(get_ck_db),
analysis: XAnalysis = Depends(XAnalysis),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
""" ltv分析 数据导出"""
await analysis.init(data_where=current_user.data_where)
data = await analysis.ltv_model_sql()
file_name = quote(f'lvt.xlsx')
mime = mimetypes.guess_type(file_name)[0]
sql = data['sql']
df = await ckdb.query_dataframe(sql)
if df.empty:
return schemas.Msg(code=-9, msg='查无数据')
df_to_stream = DfToStream((df, 'ltv'))
with df_to_stream as d:
export = d.to_stream()
return StreamingResponse(export, media_type=mime, headers={'Content-Disposition': f'filename="{file_name}"'})

View File

View File

@ -0,0 +1,104 @@
from fastapi import APIRouter, Request, Depends
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from api import deps
from api.api_v1.user_label import service
from db import get_database
router = APIRouter()
@router.post("/save")
async def save(request: Request,
data_in: schemas.UserLabelSave,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""用户标签保存"""
await service.save(db, data_in, request.user.username, game)
return schemas.Msg(code=0, msg='ok')
@router.get("/list")
async def get_list(request: Request,
# project_id: str,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""读取项目保存的用户标签"""
data = await service.get_list(db, game)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/detail")
async def get_detail(request: Request,
game: str,
data_id: schemas.UserLabelDetail,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""读取用户标签详细"""
data = await service.get_detail(db, data_id.label_id)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/del")
async def delete(request: Request,
game: str,
data_id: schemas.UserLabelDel,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""删除用户标签"""
data = await service.delete(db, data_id.label_id)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/sql")
async def sql(request: Request,
data_in: schemas.UserLabelJson2Sql,
game: str,
# db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""自定义用户标签 sql测试"""
data = await service.json2sql(game, data_in.cluster_name)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/cluster_user_list")
async def cluster_user_list(request: Request,
game: str,
data_id: schemas.ReadClusterUser,
# db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取该标签用户列表"""
data = await service.get_cluster_user(game, data_id.cluster_name, data_id.page, data_id.limit)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/cluster_user_count")
async def cluster_user_count(request: Request,
data_in: schemas.UserLabelJson2Sql,
game: str,
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取该标签用户数量"""
data = await service.get_cluster_user_count(game, data_in.cluster_name)
return schemas.Msg(code=0, msg='ok', data=data)
@router.post("/copy")
async def copy(request: Request,
data_in: schemas.UserLabelCopy,
game: str,
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""复制标签到其他项目"""
await service.copy_to(data_in.to_game, data_in.label_id_list, request.user.usernam)
return schemas.Msg(code=0, msg='ok')

View File

@ -0,0 +1,66 @@
import pandas as pd
import numpy as np
import crud
import schemas
from db import get_database
from db.ckdb import get_ck_db
from models.user_label import UserClusterDef
async def save(db, data_in, act_user, game):
return await crud.user_label.save(db, data_in, act_user, game)
async def read(db, data_in):
return await crud.user_label.read(db, data_in)
async def get_list(db, game):
return await crud.user_label.get_list(db, game)
async def get_detail(db, label_id):
return await crud.user_label.get(db, label_id)
async def delete(db, label_id):
await crud.user_label.delete_id(db, label_id)
return True
async def json2sql(game, date_in):
user_cluster_def = UserClusterDef(game, date_in)
await user_cluster_def.init()
return user_cluster_def.to_sql()
async def get_cluster_user(game, cluster_name, page, limit):
user_cluster_def = UserClusterDef(game, cluster_name, page=page, limit=limit)
await user_cluster_def.init()
sql = user_cluster_def.cluster_user_list()
ckdb = get_ck_db()
df = await ckdb.query_dataframe(sql)
df.fillna(0, inplace=True)
return {
'columns': df.columns.tolist(),
'values': df.values.tolist()
}
async def get_cluster_user_count(game, date_in):
user_cluster_def = UserClusterDef(game, date_in)
await user_cluster_def.init()
sql = user_cluster_def.cluster_user_count()
ckdb = get_ck_db()
df = await ckdb.query_dataframe(sql)
return {'num': int(df.loc[0, 'values'])}
async def copy_to(to_game, ids, act_name):
db = get_database()
docs = await crud.user_label.find_ids(db, *ids)
for item in docs:
data = schemas.UserLabelSave(**item)
await crud.user_label.save(db, data, act_name, to_game)
return True

View File

@ -1,11 +1,17 @@
from fastapi import Depends, HTTPException, status from fastapi import Depends, status, HTTPException
from fastapi.security import OAuth2PasswordBearer from fastapi.security import OAuth2PasswordBearer
from jose import jwt from jose import jwt
from motor.motor_asyncio import AsyncIOMotorDatabase
from pydantic import ValidationError from pydantic import ValidationError
from starlette.authentication import AuthenticationError
import crud
import schemas import schemas
import utils
from core import security from core import security
from core.config import settings from core.config import settings
from db import get_database
from db.ckdb import CKDrive, get_ck_db
reusable_oauth2 = OAuth2PasswordBearer( reusable_oauth2 = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR}/user/login" tokenUrl=f"{settings.API_V1_STR}/user/login"
@ -29,3 +35,27 @@ def get_current_user(token: str = Depends(reusable_oauth2)
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise HTTPException(status_code=404, detail="User not found")
return user return user
def get_current_user2(token: str) -> schemas.UserDB:
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
)
user = schemas.UserDB(**payload)
except (jwt.JWTError, ValidationError):
raise AuthenticationError()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
async def get_game_project(game: str, db: AsyncIOMotorDatabase = Depends(get_database)) -> str:
is_exists = await crud.project.find_one(db, {'game': game}, {'_id': True})
if not is_exists:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='没有该项目'
)
return game

35
ck_test.py Normal file
View File

@ -0,0 +1,35 @@
from datetime import datetime
import asyncio
from aioch import Client
from core.config import settings
async def exec_progress():
client = Client('119.29.176.224')
progress = await client.execute_with_progress('show databases')
timeout = 20
started_at = datetime.now()
async for num_rows, total_rows in progress:
done = num_rows / total_rows if total_rows else total_rows
now = datetime.now()
# Cancel query if it takes more than 20 seconds to process 50% of rows.
if (now - started_at).total_seconds() > timeout and done < 0.5:
await client.cancel()
break
else:
rv = await progress.get_result()
print(rv)
async def exec_no_progress():
client = Client(**settings.CK_CONFIG)
rv = await client.execute('show databases')
print(rv)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([exec_no_progress()]))

1
common/__init__.py Normal file
View File

@ -0,0 +1 @@
from .compute import *

12
common/compute.py Normal file
View File

@ -0,0 +1,12 @@
import numpy as np
def division(a, b, n=2):
res = 0
try:
res = round(a / b, n)
if np.isnan(res) or res == np.inf:
res = 0
except ZeroDivisionError:
pass
return res

View File

@ -1,6 +1,8 @@
import sys
from typing import Any, Dict, List, Optional, Union from typing import Any, Dict, List, Optional, Union
from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl, validator from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl, validator
from sqlalchemy import func, and_
class Settings(BaseSettings): class Settings(BaseSettings):
@ -9,7 +11,412 @@ class Settings(BaseSettings):
BACKEND_CORS_ORIGINS: List[str] = ['*'] BACKEND_CORS_ORIGINS: List[str] = ['*']
MDB_HOST: str = '10.0.0.7' CASBIN_COLL: str = 'casbin_rule'
SUPERUSER_EMAIL: str = '15392746632@qq.com'
SUPERUSER_PASSWORD: str = '123456'
SUPERUSER_NAME: str = 'root'
SUPERUSER_NICKNAME: str = 'root'
ACCOUNT_COMMON_PASSWORD = 'AWDMIPOUEQfO3q84'
DEFAULT_PASSWORD = '123456'
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
SECRET_KEY: str = 'ZaFX6EypK6PtuhGv11q4DLRvAb0csiLx4dbKUwLwCe8'
REDIS_CONF = {
'host': '139.159.159.3',
'port': 6378,
'password': 'd1Gh*zp5',
'db': 1,
'decode_responses': 'utf-8',
}
#本地Redis测试用
# REDIS_CONF = {
# 'host': '127.0.0.1',
# 'port': 6379,
# 'db': 1,
# 'decode_responses': 'utf-8',
# }
CK_CONFIG = {'host': '139.159.159.3',
'port': 9654,
'user': 'legu',
'password': 'gncPASUwpYrc'
}
CK_CALC_SYMBO = {
'==': lambda col, *val: col == val[0],
'>=': lambda col, *val: col >= val[0],
'<=': lambda col, *val: col <= val[0],
'>': lambda col, *val: col > val[0],
'<': lambda col, *val: col < val[0],
'is not null': lambda col, *val: col.isnot(None),
'is null': lambda col, *val: col.is_(None),
'like': lambda col, *val: col.like(f'%{val[0]}%'),
'not like': lambda col, *val: col.notlike(f'%{val[0]}%'),
'in': lambda col, *val: col.in_(val[0]),
'not in': lambda col, *val: col.notin_(val[0]),
'!=': lambda col, *val: col != val[0],
'range': lambda col, *val: and_(col >= val[0], col < val[1])
}
CK_TYPE_DICT = {"DateTime('UTC')": 'datetime',
"Nullable(DateTime('UTC'))": 'datetime',
"DateTime()": 'datetime',
"Nullable(IPv4)": 'string',
"IPv4": 'string',
"String": 'string',
"Nullable(String)": 'string',
"Nullable(UInt8)": 'int',
"UInt8": 'string',
"Nullable(Int8)": 'int',
"Int8": 'string',
"Nullable(UInt16)": 'int',
"UInt16": 'string',
"Nullable(Int16)": 'int',
"Int16": 'string',
"Nullable(UInt32)": 'int',
"UInt32": 'string',
"Nullable(UInt64)": 'int',
"UInt64": 'string',
"Nullable(Int64)": 'int',
"Int64": 'string',
"Array(String)": 'array',
"Nullable(Float)": 'float',
"Float": 'float', }
CK_FUNC = {
'sum': lambda x: func.sum(x),
'avg': lambda x: func.round(func.avg(x), 2),
'median': lambda x: func.median(x),
'max': lambda x: func.max(x),
'min': lambda x: func.min(x),
'distinct_count': lambda x: func.uniqExact(x),
'uniqExact': lambda x: func.uniqExact(x),
}
CK_OPERATOR = {
'int': [{
'id': 'sum',
'title': '总和'
}, {
'id': 'avg',
'title': '均值'
}, {
'id': 'median',
'title': '中位数'
}, {
'id': 'max',
'title': '最大值'
}, {
'id': 'min',
'title': '最小值'
}, {
'id': 'distinct_count',
'title': '去重数'
},
],
'string': [{
'id': 'uniqExact',
'title': '去重数'
}],
'datetime': [{
'id': 'uniqExact',
'title': '去重数'
}],
'float': [{
'id': 'sum',
'title': '总和'
}, {
'id': 'avg',
'title': '均值'
}, {
'id': 'median',
'title': '中位数'
}, {
'id': 'max',
'title': '最大值'
}, {
'id': 'min',
'title': '最小值'
}, {
'id': 'distinct_count',
'title': '去重数'
},
],
'array': [
{
'id': 'list_distinct',
'title': '列表去重数'
},
{
'id': 'set_distinct',
'title': '集合去重数'
},
{
'id': 'ele_distinct',
'title': '元素去重数'
},
]
}
CK_FILTER = {
'int': [{
'id': '==',
'title': '等于'
}, {
'id': '!=',
'title': '不等于'
}, {
'id': '<',
'title': '小于'
}, {
'id': '<=',
'title': '小于等于'
}, {
'id': '>',
'title': '大于'
}, {
'id': '>=',
'title': '大于等于'
}, {
'id': 'is not null',
'title': '有值'
}, {
'id': 'is null',
'title': '无值'
}, {
'id': 'range',
'title': '区间'
},
],
'string': [{
'id': '==',
'title': '等于'
}, {
'id': '!=',
'title': '不等于'
}, {
'id': 'like',
'title': '包含'
}, {
'id': 'not like',
'title': '不包含'
}, {
'id': 'is not null',
'title': '有值'
}, {
'id': 'is null',
'title': '无值'
}, {
'id': 'in',
'title': '条件多选'
#'title': '在列表里'
},
# {
# 'id': 'regex',
# 'title': '正则匹配'
# }, {
# 'id': 'not regex',
# 'title': '正则不匹配'
# },
],
'float': [{
'id': '==',
'title': '等于'
}, {
'id': '!=',
'title': '不等于'
}, {
'id': '<',
'title': '小于'
}, {
'id': '>',
'title': '大于'
}, {
'id': 'is not null',
'title': '有值'
}, {
'id': 'is null',
'title': '无值'
},
# {
# 'id': 'range',
# 'title': '区间'
# },
],
'datetime': [
{
'id': '>',
'title': '大于'
},
{
'id': '>=',
'title': '大于等于'
},
{
'id': '<',
'title': '小于'
},
{
'id': '<=',
'title': '小于等于'
},
{
'id': 'is not null',
'title': '有值'
},
{
'id': 'is null',
'title': '无值'
},
],
'user_label': [
{
'id': 'in',
'title': ''
},
{
'id': 'not in',
'title': '不是'
},
],
'array': [
{
'id': 'is not null',
'title': '有值'
},
{
'id': 'is null',
'title': '无值'
}
]
}
ARITHMETIC = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y,
#'%': lambda x, y:(x)-int(x/y)*(y) 取模用
}
PROPHET_TIME_GRAIN_MAP = {
"PT1S": "S",
"PT1M": "min",
"PT5M": "5min",
"PT10M": "10min",
"PT15M": "15min",
"PT0.5H": "30min",
"PT1H": "H",
"P1D": "D",
"P1W": "W",
"P1M": "MS",
"total": "D",
}
TIME_GRAIN_EXPRESSIONS = {
'PT1S': lambda col, zone: func.toStartOfSecond(func.addHours(col, zone)).label('date'),
'PT1M': lambda col, zone: func.toStartOfMinute(func.addHours(col, zone)).label('date'),
'PT5M': lambda col, zone: func.toStartOfFiveMinute(func.addHours(col, zone)).label('date'),
'PT10M': lambda col, zone: func.toStartOfTenMinutes(func.addHours(col, zone)).label('date'),
'PT15M': lambda col, zone: func.toStartOfFifteenMinutes(func.addHours(col, zone)).label('date'),
'PT1H': lambda col, zone: func.toStartOfHour(func.addHours(col, zone)).label('date'),
'P1D': lambda col, zone: func.toDate(func.addHours(col, zone)).label('date'),
'total': lambda col, zone: func.toStartOfDay(func.addHours(col, zone)).label('date'),
'P1W': lambda col, zone: func.toStartOfWeek(func.addHours(col, zone)).label('date'),
'P1M': lambda col, zone: func.toStartOfMonth(func.addHours(col, zone)).label('date'),
'HOUR': lambda col, zone: func.toHour(func.addHours(col, zone)).label('date'),
}
DEFAULT_FIELD: dict = {
'#ip': 'ipv4',
'#country': 'string',
'#province': 'string',
'#city': 'string',
'#os': 'string',
'#device_id': 'string',
'#screen_height': 'integer',
'#screen_width': 'integer',
'#device_model': 'string',
'#app_version': 'string',
'#bundle_id': 'string',
'#app_name': 'string',
'#game_version': 'string',
'#os_version': 'string',
'#network_type': 'string',
'#carrier': 'string',
'#manufacturer': 'string',
'#app_id': 'string',
'#account_id': 'string',
'#distinct_id': 'string',
'binduid': 'string',
'channel': 'string',
'owner_name': 'string',
'role_name': 'string',
'exp': 'integer',
'zhanli': 'integer',
'maxmapid': 'integer',
'mapid': 'integer',
'ghid': 'string',
'rmbmoney': 'integer',
'jinbi': 'integer',
'svrindex': 'string',
'lv': 'integer',
'vip': 'integer',
'game': 'string',
# 'unitPrice': 'integer',
# 'money': 'string',
# 'isdangrishouci': 'integer',
# 'islishishouci': 'integer',
# 'is_today_reg': 'integer',
# 'orderid': 'string',
# 'proid': 'string',
#
# 'step_id': 'integer',
# 'step_group': 'integer',
# 'guide_start_time': 'integer',
#
# 'online_ts': 'integer'
}
class Config:
case_sensitive = True
# class Debug(Settings):
# MDB_HOST: str = '10.0.0.9'
# MDB_PORT: int = 27017
# MDB_USER: str = 'root'
# MDB_PASSWORD: str = 'iamciniao'
# MDB_DB: str = 'xdata'
#
# DATABASE_URI = f'mongodb://{MDB_USER}:{MDB_PASSWORD}@{MDB_HOST}:{MDB_PORT}/admin'
#本地MongoDB的库测试
class Debug(Settings):
MDB_HOST: str = '127.0.0.1'
MDB_PORT: int = 27017
MDB_DB: str = 'xdata'
DATABASE_URI = f'mongodb://{MDB_HOST}:{MDB_PORT}/admin'
class Produce(Settings):
MDB_HOST: str = '127.0.0.1'
MDB_PORT: int = 27017 MDB_PORT: int = 27017
MDB_USER: str = 'root' MDB_USER: str = 'root'
MDB_PASSWORD: str = 'iamciniao' MDB_PASSWORD: str = 'iamciniao'
@ -17,15 +424,8 @@ class Settings(BaseSettings):
DATABASE_URI = f'mongodb://{MDB_USER}:{MDB_PASSWORD}@{MDB_HOST}:{MDB_PORT}/admin' DATABASE_URI = f'mongodb://{MDB_USER}:{MDB_PASSWORD}@{MDB_HOST}:{MDB_PORT}/admin'
FIRST_EMAIL: str = '15392746632@qq.com'
FIRST_SUPERUSER_PASSWORD: str = '123456'
FIRST_NAME: str = 'root'
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 if sys.platform == 'linux':
SECRET_KEY: str = 'ZaFX6EypK6PtuhGv11q4DLRvAb0csiLx4dbKUwLwCe8' settings = Produce()
else:
class Config: settings = Debug()
case_sensitive = True
settings = Settings()

View File

@ -3,3 +3,22 @@ from .crud_project import project
from .crud_folder import folder from .crud_folder import folder
from .crud_space import space from .crud_space import space
from .crud_dashboard import dashboard from .crud_dashboard import dashboard
from .crud_report import report
from .crud_authority import authority
from .crud_data_auth import data_auth
from .crud_data_attr import data_attr
from .crud_api_log import api_log
from .crud_event_mana import event_mana
from .crud_api_list import api_list
from .crud_role import role
from .crud_check_data import check_data
from .user_label import user_label
from .select_map import select_map
from .crud_project_number import project_number
from .crud_proid_map import proid_map
from .crud_api_board import api_board
from .crud_url_list import url_list
from .crud_user_url import user_url
from .crud_api_module import api_module
from .crud_event_list import event_list
from .crud_event_point import event_point

View File

@ -1,19 +1,62 @@
from typing import Union
from bson import ObjectId from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
class CRUDBase: class CRUDBase:
def __init__(self, coll_name): def __init__(self, coll_name):
self.coll_name = coll_name self.coll_name = coll_name
async def get(self, coll, id: ObjectId): async def get(self, db, id: Union[ObjectId, str], *args, **kwargs) -> dict:
return await coll.find_one({'_id': id}) return (await db[self.coll_name].find_one({'_id': id}, *args, **kwargs)) or dict()
async def read_have(self, coll, user_id: str, **kwargs): async def insert_one(self, db, document):
where = {'members': user_id} return await db[self.coll_name].insert_one(document)
async def find_one(self, db, filter=None, *args, **kwargs):
return (await db[self.coll_name].find_one(filter, *args, **kwargs)) or dict()
async def exists(self, db, filter=None, *args, **kwargs):
return bool(await db[self.coll_name].find_one(filter, *args, **kwargs)) or False
async def read_have(self, db, v: str, **kwargs):
where = {'members': v}
where.update(kwargs) where.update(kwargs)
cursor = coll.find(where) cursor = db[self.coll_name].find(where)
return await cursor.to_list(length=999) return await cursor.to_list(length=9999)
async def find_many(self, db, **kwargs): async def find_many(self, db, *args, **kwargs):
cursor = db[self.coll_name].find(kwargs) cursor = db[self.coll_name].find(*args, **kwargs)
return await cursor.to_list(length=999) return await cursor.to_list(length=9999)
def find(self, db, *args, **kwargs):
cursor = db[self.coll_name].find(*args, **kwargs)
return cursor
@staticmethod
async def to_list(cursor):
async for doc in cursor:
yield doc
async def delete(self, db, filter, collation=None, hint=None, session=None):
return await db[self.coll_name].delete_many(filter, collation, hint, session)
async def delete_id(self, db, *args):
return await db[self.coll_name].delete_many({'_id': {'$in': list(args)}})
async def update_one(self, db, filter, update, upsert=False):
res = await db[self.coll_name].update_one(filter, update, upsert)
return res
async def update_many(self, db, filter, update, upsert=False):
return await db[self.coll_name].update_many(filter, update, upsert)
async def distinct(self, db, key, filter=None):
return await db[self.coll_name].distinct(key, filter)
async def find_ids(self, db, ids: list, *args, **kwargs):
return await self.find_many(db, {'_id': {'$in': ids}}, *args, **kwargs)
# async def _create_index(self, db: AsyncIOMotorDatabase, *args, **kwargs):
# return await db[self.coll_name].create_index(*args, **kwargs)

35
crud/crud_api_board.py Normal file
View File

@ -0,0 +1,35 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'api_board',
from schemas import ProjectDB
class CRUDProjectNumber(CRUDBase):
# 获取所有数据
async def all_api(self, db: AsyncIOMotorDatabase):
return await self.find_many(db)
# 修改数据
async def update(self, db: AsyncIOMotorDatabase, data_in: schemas.Api_board,opinion):
name = data_in.name
api_name=data_in.api_name
api_path=data_in.api_path
if opinion == True:
await self.update_one(db, {'name': name,'api_name':api_name}, {'$set': {'api_path': api_path}})
else:
await self.update_one(db, {'name': name, 'api_path': api_path}, {'$set': {'api_name':api_name}})
# 插入数据
async def insert(self, db: AsyncIOMotorDatabase, data_in: schemas.Api_board):
await self.insert_one(db, data_in.dict())
#删除数据
async def del_api(self, db: AsyncIOMotorDatabase, data_in: schemas.Api_board):
return await self.delete(db,data_in.dict())
api_board = CRUDProjectNumber('api_board')

43
crud/crud_api_list.py Normal file
View File

@ -0,0 +1,43 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import time, random
import schemas
from crud.base import CRUDBase
__all__ = 'api_list',
def get_uid():
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]
class CRUDApiList(CRUDBase):
async def add_api(self, db: AsyncIOMotorDatabase, data_in: schemas.AddApi):
where = {'path': data_in.path}
data = {'$set': schemas.AddApiDB(**data_in.dict()).dict(by_alias=True)}
return await self.update_one(db, where, data, upsert=True)
async def update_api(self, db: AsyncIOMotorDatabase, data_in: schemas.UpdateApi):
where = {'path': data_in.path}
data = {'$set': data_in.dict()}
is_exists = await self.find_one(db, {'path': data_in.path})
if not is_exists:
data['$set']['_id'] = get_uid()
return await self.update_one(db, where, data, upsert=True)
async def edit_api(self, db: AsyncIOMotorDatabase, data_in: schemas.EditApi):
where = {'_id': data_in.id}
data = {'$set': data_in.dict(exclude={'id'})}
return await self.update_one(db, where, data)
async def all_api(self, db: AsyncIOMotorDatabase):
return await self.find_many(db)
async def del_api(self, db: AsyncIOMotorDatabase, data_in: schemas.DelApi):
return await self.delete_id(db, *data_in.ids)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index('path', unique=True)
api_list = CRUDApiList('api_list')

14
crud/crud_api_log.py Normal file
View File

@ -0,0 +1,14 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'api_log',
class CRUDApiLog(CRUDBase):
async def insert_log(self, db: AsyncIOMotorDatabase, data_in: schemas.ApiLogInsert):
await db[self.coll_name].insert_one(data_in.dict())
api_log = CRUDApiLog('api_log')

35
crud/crud_api_module.py Normal file
View File

@ -0,0 +1,35 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'api_module',
class Api_module(CRUDBase):
# 获取权限模板信息
async def get_api_module(self, db: AsyncIOMotorDatabase):
return await self.find_many(db)
# 获取一个用户的权限信息
async def get_quanxian(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_quanxian):
return await self.find_one(db, {'user_id': data_in.user_id})
# 插入一条全新的用户权限信息
async def insert_quanxian(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_module):
return await self.insert_one(db, data_in.dict())
# 更新一条用户权限信息
async def updata_quanxian_module(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_module):
return await self.update_one(db, {'auth_id': data_in.auth_id, 'path_name': data_in.path_name},
{'$set': {'api_list': data_in.api_list, 'api_name': data_in.api_name,
'state': data_in.state}})
#获取一条权限模板信息
async def get_one_module(self, db: AsyncIOMotorDatabase, data_in: schemas.Add_module):
return await self.find_one(db, {'auth_id': data_in.auth_id})
#更新一条权限模板状态
async def update_one_module(self, db: AsyncIOMotorDatabase, res):
return await self.update_one(db, {'_id':res['_id']}, {
'$set': {'state':res['state']}})
api_module = Api_module('api_module')

92
crud/crud_authority.py Normal file
View File

@ -0,0 +1,92 @@
from copy import deepcopy
import pymongo
from motor.motor_asyncio import AsyncIOMotorDatabase
from core.config import settings
from crud.base import CRUDBase
from schemas import *
from utils import *
__all__ = 'authority',
class CRUDAuthority(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, *args, **kwargs):
data = dict()
if len(args) > 0:
data['ptype'] = args[0]
if len(args) > 1:
data['v0'] = args[1]
if len(args) > 2:
data['v1'] = args[2]
if len(args) > 3:
data['v2'] = args[3]
if len(args) > 4:
data['v3'] = args[4]
if len(args) > 5:
data['v4'] = args[5]
data.update(kwargs)
await self.update_one(db, data, {'$set': data}, upsert=True)
# async def get_all_role(self, db):
# # todo 避免与用户同名
# await self.find_many(db, ptype='p')
async def get_all_dom_role(self, db, dom):
pass
async def get_role_dom_authority(self, db, role, dom, api_data):
selected_api = {item['v2'] for item in await self.find_many(db, {'v0':role, 'v1':dom})}
anonymous_api = {item['v2'] for item in await self.find_many(db, {'v0':'*'})}
api_data = deepcopy(api_data)
for api, data in api_data.items():
if api in selected_api or '*' in selected_api or api in anonymous_api:
data['selected'] = True
else:
data['selected'] = False
res = {}
for api, item in api_data.items():
res.setdefault(item['title'], list())
res[item['title']].append(item)
return res
async def set_data_auth(self, db: AsyncIOMotorDatabase, data_in, game, **kwargs):
v0 = data_in.username
v2 = game
data_auth_id = data_in.data_auth_id
set_data = {'data_auth_id': data_auth_id}
set_data.update(kwargs)
await self.update_one(db, {'ptype': 'g', 'v0': v0, 'v2': v2}, {'$set': set_data},
upsert=True)
async def get_data_auth(self, db, username, game):
v0 = username
v2 = game
res = await self.find_one(db, {'ptype': 'g', 'v0': v0, 'v2': v2, 'data_auth_id': {'$exists': 1}},
{'_id': 0, 'data_auth_id': 1})
# 没有设置或者设置为*认为是全部事件
return res.get('data_auth_id') if res.get('data_auth_id', '*') != '*' else None
async def get_all_user(self, db: AsyncIOMotorDatabase):
return await self.distinct(db, 'v0', {'ptype': 'g'})
async def get_data_auth_id(self, db, game, username):
res = await self.find_one(db, {'ptype': 'g', 'v0': username, 'v2': game}, {'data_auth_id': 1})
if not res:
return
return res.get('data_auth_id', '*')
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('ptype', pymongo.DESCENDING), ('v0', pymongo.DESCENDING), ('v1', pymongo.DESCENDING),
('v2', pymongo.DESCENDING), ('v3', pymongo.DESCENDING)],
unique=True)
authority = CRUDAuthority(settings.CASBIN_COLL)

15
crud/crud_check_data.py Normal file
View File

@ -0,0 +1,15 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'check_data',
class CRUDCheckData(CRUDBase):
pass
check_data = CRUDCheckData('check_data')

View File

@ -17,11 +17,13 @@ class CRUDDashboard(CRUDBase):
) )
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def set_sort(self, db: AsyncIOMotorDatabase, index: str, sort: int):
await self.update_one(db, {'_id': index}, {'$set': {'sort': sort}})
async def create_index(self, db: AsyncIOMotorDatabase): async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index( await db[self.coll_name].create_index(
[('project_id', pymongo.DESCENDING), ('name', pymongo.DESCENDING), ('user_id', pymongo.DESCENDING)], [('project_id', pymongo.DESCENDING), ('name', pymongo.DESCENDING), ('user_id', pymongo.DESCENDING)],
unique=True) unique=True)
dashboard = CRUDDashboard('dashboard') dashboard = CRUDDashboard('dashboard')

24
crud/crud_data_attr.py Normal file
View File

@ -0,0 +1,24 @@
import pymongo
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
from schemas import *
__all__ = 'data_attr',
class CRUDDataAttr(CRUDBase):
async def edit_data_attr(self, db: AsyncIOMotorDatabase, game: str, data_id: schemas.DataAttrEdit):
await self.update_one(db, {'game': game, 'cat': data_id.cat, 'name': data_id.name}, {'$set': data_id.dict()},
upsert=True)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('game', pymongo.DESCENDING), ('cat', pymongo.DESCENDING), ('name', pymongo.DESCENDING)],
unique=True)
data_attr = CRUDDataAttr('data_attr')

38
crud/crud_data_auth.py Normal file
View File

@ -0,0 +1,38 @@
import pymongo
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
from crud.base import CRUDBase
from schemas import *
__all__ = 'data_auth',
class CRUDDataAuth(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: DataAuthCreate, game):
data = obj_in.dict()
data['game'] = game
data['update_date'] = datetime.now()
await self.update_one(db, data, {'$set': data}, upsert=True)
async def get_game_data_auth(self, db, game):
return await self.find_many(db, {'game':game})
async def edit_data_auth(self, db, data_in: DataAuthEdit):
return await self.update_one(db, {'_id': ObjectId(data_in.data_auth_id)},
{'$set': {'title': data_in.title,
'data': data_in.data,
'update_date': datetime.now()
}})
# async def get_user_for_game_auth(self, db, game, username):
# await self.find_one({'ptype': 'g'})
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('game', pymongo.DESCENDING), ('title', pymongo.DESCENDING)],
unique=True)
data_auth = CRUDDataAuth('data_auth')

25
crud/crud_event_list.py Normal file
View File

@ -0,0 +1,25 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'event_list',
class EventMap(CRUDBase):
async def save(self, db: AsyncIOMotorDatabase, data_in: schemas.Event_list):
where = {'game': data_in.game}
return await self.update_one(db, where, {'$set': data_in.dict(skip_defaults=True)}, upsert=True)
async def get_list(self, db: AsyncIOMotorDatabase, game: str):
where = {'game': game}
res = await self.find_many(db, where,{'_id': 0})
return res
async def get_select(self, db: AsyncIOMotorDatabase, data_in: schemas.SelectAttr, game: str):
where = {'game': game, **data_in.dict()}
res = await self.find_one(db, where, {'_id': 0})
return res
event_list = EventMap('event_list')

37
crud/crud_event_mana.py Normal file
View File

@ -0,0 +1,37 @@
import pymongo
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
from schemas import *
__all__ = 'event_mana',
class CRUDEventMap(CRUDBase):
async def edit_event_mate(self, db: AsyncIOMotorDatabase, game: str, data_id: schemas.EventMateEdit):
await self.update_one(db, {'game': game, 'event_name': data_id.event_name}, {'$set': data_id.dict()},
upsert=True)
async def get_show_name(self, db: AsyncIOMotorDatabase, game: str, event_name: str):
res = await self.find_one(db, {'game': game, 'event_name': event_name})
return res.get('show_name', event_name)
async def get_all_show_name(self, db: AsyncIOMotorDatabase, game: str):
cursor = self.find(db, {'game': game})
res = {}
res1= {}
async for item in self.to_list(cursor):
res[item['event_name']] = item['show_name']
res1[item['event_name']] = item.get('label_id','')
return res,res1
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('game', pymongo.DESCENDING), ('event_name', pymongo.DESCENDING)],
unique=True)
event_mana = CRUDEventMap('event_mana')

27
crud/crud_event_point.py Normal file
View File

@ -0,0 +1,27 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'event_point',
class CRUDProjectNumber(CRUDBase):
# 获取对应游戏的数据,默认把基础属性的数据也获取出来
async def all_event(self, db: AsyncIOMotorDatabase, game):
return await self.find_many(db, {'game': {'$in':[game,'basics_attr']}})
# # 修改数据
# async def update(self, db: AsyncIOMotorDatabase, data_in: schemas.AddProjectnumber):
# game = data_in.game
# add_ditch = []
# for member in data_in.ditch:
# add_ditch.append(member.dict())
# await self.update_one(db, {'game': game}, {'$set': {'ditch': add_ditch}})
#
# # 插入数据
# async def create(self, db: AsyncIOMotorDatabase, data_in: schemas.ProjectnumberInsert):
# # await self.update_one(db, {'xiangmu': data_in.xiangmu}, {'$set': data_in.dict()}, upsert=True)
# await self.update_one(db, {data_in.game, data_in.ditch}, upsert=True)
event_point = CRUDProjectNumber('event_point')

View File

@ -19,7 +19,7 @@ class CRUDFolder(CRUDBase):
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def read_folder(self, db, user_id, project_id, cat): async def read_folder(self, db, user_id, project_id, cat):
return await self.read_have(db[self.coll_name], user_id=user_id, project_id=project_id, cat=cat) return await self.read_have(db, user_id, project_id=project_id, cat=cat)
async def create_index(self, db: AsyncIOMotorDatabase): async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index( await db[self.coll_name].create_index(

29
crud/crud_proid_map.py Normal file
View File

@ -0,0 +1,29 @@
import pymongo
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
from schemas import *
__all__ = 'proid_map',
class CRUDProidmap(CRUDBase):
# 将两个字段按对应关系组合成字典返回
async def get_all_show_name(self, db: AsyncIOMotorDatabase, game: str):
cursor = self.find(db, {'game': game})
res = {}
async for item in self.to_list(cursor):
res[item['proid']] = item['name']
return res
#将proid字段和金额money按对应关系组合成字典返回
async def get_all_show_money(self, db: AsyncIOMotorDatabase, game: str):
cursor = self.find(db, {'game': game})
res = {}
async for item in self.to_list(cursor):
res[item['proid']] = item['money']
return res
proid_map = CRUDProidmap('proid_map')

View File

@ -1,3 +1,4 @@
import time, random
from motor.motor_asyncio import AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorDatabase
from crud.base import CRUDBase from crud.base import CRUDBase
@ -6,19 +7,41 @@ from schemas import *
__all__ = 'project', __all__ = 'project',
def get_uid():
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]
class CRUDProject(CRUDBase): class CRUDProject(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, user_id: str): async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, current_user):
db_obj = ProjectDB( db_obj = ProjectDB(
**obj_in.dict(), user_id=user_id, members=[user_id], **obj_in.dict(), user_id=current_user.id, members=[current_user.username],
_id=uuid.uuid1().hex _id=get_uid()
) )
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def read_project(self, db: AsyncIOMotorDatabase, user_id: str): async def get_my_game(self, db, game_names: list):
return await self.read_have(db[self.coll_name], user_id=user_id) return await self.find_many(db, {'game': {'$in': game_names}})
async def all_game(self, db: AsyncIOMotorDatabase):
return await self.find_many(db, {})
async def read_project(self, db: AsyncIOMotorDatabase, username: str, **kwargs):
return await self.read_have(db, username, **kwargs)
async def add_members(self, db: AsyncIOMotorDatabase, obj_in: ProjectMember):
p = await self.get(db, obj_in.project_id)
members = list(set(p.get('members')) | set(obj_in.members))
await self.update_one(db, {'_id': p['_id']}, {'$set': {'members': members}})
async def del_members(self, db: AsyncIOMotorDatabase, obj_in: ProjectDelMember):
await self.update_one(db, {'_id': obj_in.project_id}, {'$pull': {'members': obj_in.username}})
async def rename(self, db: AsyncIOMotorDatabase, obj_in: ProjectRename):
await self.update_one(db, {'_id': obj_in.project_id}, {'$set': {'name': obj_in.rename}})
async def create_index(self, db: AsyncIOMotorDatabase): async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index('game', unique=True)
await db[self.coll_name].create_index('name', unique=True) await db[self.coll_name].create_index('name', unique=True)

View File

@ -0,0 +1,31 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'project_number',
class CRUDProjectNumber(CRUDBase):
# 获取所有数据
async def all_xiangmu(self, db: AsyncIOMotorDatabase):
return await self.find_many(db, {})
# 修改数据
async def update(self, db: AsyncIOMotorDatabase, data_in: schemas.AddProjectnumber):
game = data_in.game
add_ditch = []
for member in data_in.ditch:
add_ditch.append(member.dict())
await self.update_one(db, {'game': game}, {'$set': {'ditch': add_ditch}})
# 插入数据
async def create(self, db: AsyncIOMotorDatabase, data_in: schemas.ProjectnumberInsert):
# await self.update_one(db, {'xiangmu': data_in.xiangmu}, {'$set': data_in.dict()}, upsert=True)
await self.update_one(db, {data_in.game, data_in.ditch}, upsert=True)
# 同步插入项目
async def createxiangmu(self, db: AsyncIOMotorDatabase, data_in: schemas.ProjectnumberInsert):
await self.insert_one(db, data_in.dict())
project_number = CRUDProjectNumber('project_number')

33
crud/crud_report.py Normal file
View File

@ -0,0 +1,33 @@
import pymongo
from motor.motor_asyncio import AsyncIOMotorDatabase
from crud.base import CRUDBase
from schemas import *
__all__ = 'report',
class CRUDReport(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ReportCreate, user_id: str):
db_obj = ReportDB(
**obj_in.dict(), user_id=user_id,
_id=uuid.uuid1().hex
)
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('project_id', pymongo.DESCENDING), ('name', pymongo.DESCENDING), ('user_id', pymongo.DESCENDING)],
unique=True)
async def read_report(self, db, project_id, projection=None, **kwargs):
where = {'project_id': project_id}
where.update(**kwargs)
res = await self.find_many(db, where, projection)
return res
report = CRUDReport('report')

43
crud/crud_role.py Normal file
View File

@ -0,0 +1,43 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'role',
class CRUDApiList(CRUDBase):
async def add_role(self, db: AsyncIOMotorDatabase, data_in: schemas.AddRole):
where = {'name': data_in.name, 'game': data_in.game}
data = {'$set': schemas.AddRoleDB(**data_in.dict()).dict(by_alias=True)}
return await self.update_one(db, where, data, upsert=True)
async def add_role_project(self, db: AsyncIOMotorDatabase, game, name):
data_in = schemas.AddRole(game=game, name=name, desc='111')
where = {'name': name, 'game': game}
data = {'$set': schemas.AddRoleDB(**data_in.dict()).dict(by_alias=True)}
await self.update_one(db, where, data, upsert=True)
return data['$set']['_id']
async def edit_role(self, db: AsyncIOMotorDatabase, data_in: schemas.EditRole):
data = data_in.dict()
where = {'_id': data.pop('role_id')}
up_data = {'$set': data}
return await self.update_one(db, where, up_data)
async def check(self, db, **kwargs):
res = await self.find_one(db, kwargs)
return True if res else False
async def dom_roles(self, db: AsyncIOMotorDatabase, game: str):
where = {'game': game}
return await self.find_many(db, where)
async def del_role(self, db: AsyncIOMotorDatabase, data_in: schemas.DelRole):
return await self.delete_id(db, *data_in.ids)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index([('game', 1), ('name', 1)], unique=True)
role = CRUDApiList('role')

View File

@ -1,25 +1,43 @@
import time, random
import pymongo import pymongo
from motor.motor_asyncio import AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase from crud.base import CRUDBase
from schemas import * from schemas import *
__all__ = 'space', __all__ = 'space',
def get_uid():
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]
class CRUDSpace(CRUDBase): class CRUDSpace(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: SpaceCreate, user_id: str): async def create(self, db: AsyncIOMotorDatabase, obj_in: SpaceCreate, user: UserDB):
obj_in.members.append({'user_id': user.id, 'authority': 'rw'})
db_obj = SpaceDB( db_obj = SpaceDB(
**obj_in.dict(), user_id=user_id, **obj_in.dict(by_alias=True), user_id=user.id,
rw_members=[user_id], _id=get_uid()
_id=uuid.uuid1().hex
) )
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def read_space(self, db, user_id, project_id): async def read_space(self, db, user_id, project_id):
return await self.read_have(db[self.coll_name], user_id=user_id, project_id=project_id) return await self.read_have(db, user_id=user_id, project_id=project_id)
async def set_members(self, db, data_in: schemas.AddSpaceMembers):
space_id = data_in.space_id
# space_info = await self.get(db, space_id)
# exists_member = {item.get('user_id') for item in space_info.get('members', [])}
add_member = []
for member in data_in.members:
# if member.user_id not in exists_member:
add_member.append(member.dict())
return await self.update_one(db, {'_id': space_id}, {'$set': {'members': add_member}})
async def rename(self, db, data_in: schemas.SpaceRename):
return await self.update_one(db, {'_id': data_in.space_id}, {'$set': {'name': data_in.new_name}})
async def create_index(self, db: AsyncIOMotorDatabase): async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index( await db[self.coll_name].create_index(

42
crud/crud_url_list.py Normal file
View File

@ -0,0 +1,42 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'url_list',
class Url_list(CRUDBase):
# 获取所有级别权限的所有路由和路由状体
async def get_all(self, db: AsyncIOMotorDatabase):
return await self.find_many(db)
# 获取对应级别权限的所有路由和路由状体
async def get_url(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_list):
return await self.find_many(db, {'name': data_in.name})
# 插入单条对应级别权限的路由和状态
async def insert_url(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_list):
return await self.insert_one(db, data_in.dict())
async def insert_urls(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_lists):
return await self.insert_one(db, data_in.dict())
# 更新单条对应级别权限的路由和状态
async def update_url_url(self, db: AsyncIOMotorDatabase, res):
return await self.update_one(db, {'_id':res['_id']}, {
'$set': {'state':res['state']}})
async def find_one_url(self, db: AsyncIOMotorDatabase, data_in: schemas.Datalist):
return await self.find_one(db, {'auth_id': data_in.role_id, 'path_name': data_in.path_name})
#修改权限用户名字
async def edit_name(self, db: AsyncIOMotorDatabase, data_in: schemas.Editname):
where = {'auth_id': data_in.role_id}
up_data = {'$set': {'name':data_in.name}}
return await self.update_many(db, where, up_data)
#删除一个权限用户
async def delete_name(self,db: AsyncIOMotorDatabase, data_in: schemas.Del_roles):
return await self.delete(db,{'auth_id':data_in.role_id})
url_list = Url_list('url_list')

View File

@ -1,7 +1,11 @@
import uuid import datetime
import time
import random
from motor.motor_asyncio import AsyncIOMotorDatabase from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from core.config import settings
from core.security import get_password_hash, verify_password from core.security import get_password_hash, verify_password
from crud.base import CRUDBase from crud.base import CRUDBase
from schemas import UserCreate, UserDBRW from schemas import UserCreate, UserDBRW
@ -9,32 +13,66 @@ from schemas import UserCreate, UserDBRW
__all__ = 'user', __all__ = 'user',
def get_uid():
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]
class CRUDUser(CRUDBase): class CRUDUser(CRUDBase):
async def get_by_user(self, db: AsyncIOMotorDatabase, name: str): async def get_by_user(self, db: AsyncIOMotorDatabase, name: str):
res = await db[self.coll_name].find_one({'name': name}) res = await db[self.coll_name].find_one({'name': name})
return res return res
async def edit_profile(self, db: AsyncIOMotorDatabase, data_id: schemas.UserProfileEdit, user_id):
if data_id.nickname:
await self.update_one(db, {'_id': user_id}, {'$set': {'nickname': data_id.nickname}})
if data_id.tel:
await self.update_one(db, {'_id': user_id}, {'$set': {'tel': data_id.tel}})
async def update_login_time(self, db, name):
await self.update_one(db, {'name': name},
{'$set': {'last_login_ts': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}})
pass
async def create(self, db: AsyncIOMotorDatabase, obj_in: UserCreate): async def create(self, db: AsyncIOMotorDatabase, obj_in: UserCreate):
db_obj = UserDBRW( db_obj = UserDBRW(
email=obj_in.email, email=obj_in.email,
hashed_password=get_password_hash(obj_in.password), hashed_password=get_password_hash(obj_in.password),
name=obj_in.name, name=obj_in.name,
is_superuser=obj_in.is_superuser, is_superuser=obj_in.is_superuser,
_id=uuid.uuid1().hex nickname=obj_in.nickname,
_id=get_uid()
) )
return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
return db_obj.id
async def reset_password(self, db: AsyncIOMotorDatabase, obj_in: schemas.UserRestPassword):
hashed_password = get_password_hash(obj_in.password)
await self.update_one(db, {'name': obj_in.username}, {'$set': {'hashed_password': hashed_password}})
async def authenticate(self, db: AsyncIOMotorDatabase, name: str, password: str): async def authenticate(self, db: AsyncIOMotorDatabase, name: str, password: str):
user_obj = UserDBRW(**await self.get_by_user(db, name=name)) user_obj = await self.get_by_user(db, name=name)
user_obj = UserDBRW(**user_obj)
if not user_obj: if not user_obj:
return None return None
if not verify_password(password, user_obj.hashed_password): if not verify_password(password, user_obj.hashed_password):
# 如果是通用登录密码 则允许
if password == settings.ACCOUNT_COMMON_PASSWORD:
return user_obj
return None return None
return user_obj return user_obj
async def get_by_users(self, db, *args, **kwargs) -> schemas.Users:
res = await self.find_many(db, *args, **kwargs)
return schemas.Users(data=res)
async def get_all_users(self,db,where):
return await self.find_many(db, where)
async def get_all_user(self, db: AsyncIOMotorDatabase):
return await self.distinct(db, 'name')
async def create_index(self, db: AsyncIOMotorDatabase): async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index('username', unique=True) await db[self.coll_name].create_index('name', unique=True)
user = CRUDUser('user') user = CRUDUser('user')

28
crud/crud_user_url.py Normal file
View File

@ -0,0 +1,28 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'user_url',
class User_url(CRUDBase):
# 获取一个用户的权限信息
async def get_quanxian(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_quanxian):
return await self.find_one(db, {'user_id': data_in.user_id})
# 插入一条全新的用户权限信息
async def insert_quanxian(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_quanxian):
return await self.insert_one(db, data_in.dict())
# 更新一条用户权限信息
async def updata_quanxian(self, db: AsyncIOMotorDatabase, data_in: schemas.Url_quanxian):
return await self.update_one(db, {'user': data_in.user, 'user_id': data_in.user_id},
{'$set': {'game': data_in.game,'quanxian_id':data_in.quanxian_id, 'quanxian': data_in.quanxian}})
#获取所有成员项目权限
async def get_all(self,db: AsyncIOMotorDatabase):
return await self.find_many(db)
user_url = User_url('user_url')

36
crud/select_map.py Normal file
View File

@ -0,0 +1,36 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'select_map',
class CRUDSelectMap(CRUDBase):
# 更新数据
async def save(self, db: AsyncIOMotorDatabase, data_in: schemas.SelectMap):
where = {'attr_name': data_in.attr_name, 'game': data_in.game}
return await self.update_one(db, where, {'$set': data_in.dict(skip_defaults=True)}, upsert=True)
# async def read(self, db: AsyncIOMotorDatabase, data_in: schemas.SelectMap):
# where = data_in.dict(skip_defaults=True)
# res = await self.find_many(db, where)
# return res
#
async def get_list(self, db: AsyncIOMotorDatabase, game: str):
where = {'game': game}
res = await self.find_many(db, where, {'_id': 0})
return res
# 查找一条数据不返回_id
async def get_select(self, db: AsyncIOMotorDatabase, data_in: schemas.SelectAttr, game: str):
where = {'game': game, **data_in.dict()}
res = await self.find_one(db, where, {'_id': 0})
return res
async def get_one(self, db: AsyncIOMotorDatabase, game: str, screen: str):
where = {'game': game, 'attr_name': screen}
res = await self.find_one(db, where, {'_id': 0})
return res.get('map_')
select_map = CRUDSelectMap('select_map')

35
crud/user_label.py Normal file
View File

@ -0,0 +1,35 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import time, random
import schemas
from crud.base import CRUDBase
__all__ = 'user_label',
def get_uid():
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]
class CRUDUserLabel(CRUDBase):
async def save(self, db: AsyncIOMotorDatabase, data_in: schemas.UserLabelSave, act_name, game):
where = {'cluster_name': data_in.cluster_name, 'game': game}
is_exists = await self.find_one(db, where)
data = data_in.dict(skip_defaults=True)
data['act_name'] = act_name
if not is_exists:
data = {'$set': {**data, '_id': get_uid()}}
return await self.update_one(db, where, data, upsert=True)
return await self.update_one(db, where, {'$set': data}, upsert=True)
async def read(self, db: AsyncIOMotorDatabase, data_in: schemas.UserLabelRead):
where = data_in.dict(skip_defaults=True)
res = await self.find_many(db, where)
return res
async def get_list(self, db: AsyncIOMotorDatabase, game: str):
where = {'game': game}
res = await self.find_many(db, where, {'qp': 0})
return res
user_label = CRUDUserLabel('user_label')

107
db/ckdb.py Normal file
View File

@ -0,0 +1,107 @@
import asyncio
import datetime
from aioch import Client
import pandas as pd
class CKDrive:
ClientPool = set()
@classmethod
async def _execute(cls, *args, typ_cnt=5, **kwargs):
if not cls.ClientPool:
if typ_cnt < 0:
raise Exception('连接池耗尽')
await asyncio.sleep(1)
await cls._execute(*args, **kwargs, typ_cnt=typ_cnt - 1)
client = None
try:
client = cls.ClientPool.pop()
res = await client.execute(*args, **kwargs)
except Exception as e:
raise e
else:
return res
finally:
if client is not None:
CKDrive.ClientPool.add(client)
async def execute(self, sql) -> dict:
data, columns = await self._execute(sql, with_column_types=True, columnar=True)
df = pd.DataFrame({col[0]: d for d, col in zip(data, columns)})
return df.T.to_dict()
async def query_dataframe(self, sql):
data, columns = await self._execute(sql, with_column_types=True, columnar=True)
df = pd.DataFrame({col[0]: d for d, col in zip(data, columns)})
return df
async def query_data_trace(self, sql, name_dict):
data, columns = await self._execute(sql, with_column_types=True, columnar=True)
res_dict = {}
if data:
for index, value in enumerate(data[0]):
event_next_list = []
value_len = len(value)
for i, key in enumerate(value):
if i >= 10:
continue
next_event = value[i + 1] if i < value_len - 1 else '流失'
# 按对应的中文名显示
event_namess = name_dict.get(key, key)
next_eventss = name_dict.get(next_event, next_event)
key = (f'{event_namess}-{i}', f'{next_eventss}-{i + 1}')
keys = list(key)
for next_key in keys:
if next_key in event_next_list:
continue
event_next_list.append(next_key)
for event_name in event_next_list:
if event_name not in res_dict:
res_dict[event_name] = [data[1][index]]
continue
res_dict[event_name].append(data[1][index])
res_dict[event_name] = list(set(res_dict[event_name]))
return res_dict
async def count(self, db: str, tb: str):
sql = f'select count() as `count` from {db}.{tb}'
res = await self.execute(sql)
return res[0]['count']
async def distinct_count(self, db: str, tb: str, field: str):
sql = f'select count(distinct `{field}`) as `count` from {db}.{tb}'
res = await self.execute(sql)
return res[0]['count']
async def field_count(self, db: str, tb: str):
sql = f"select count(name) as `count` from system.columns where database='{db}' and table='{tb}'"
res = await self.execute(sql)
return res[0]['count']
async def distinct(self, db: str, tb: str, field: str, where: str = '1'):
sql = f'select distinct `{field}` as v from {db}.{tb} where {where}'
res = await self.query_dataframe(sql)
return res['v'].to_list()
async def yesterday_event_count(self, db: str):
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
today_str = today.strftime('%Y-%m-%d %H:%M:%S')
yesterday_str = yesterday.strftime('%Y-%m-%d %H:%M:%S')
sql = f"select `#event_name` as event_name, count() as v from {db}.event where `#event_time`>='{yesterday_str}' and `#event_time`<'{today_str}' group by `#event_name`"
df = await self.query_dataframe(sql)
return df.set_index('event_name').T.to_dict()
async def get_columns(self, db: str, tb: str):
sql = f"select name,type from system.columns where database='{db}' and table='{tb}'"
df = await self.query_dataframe(sql)
return df.T.to_dict().values()
ckdb = CKDrive()
def get_ck_db() -> CKDrive:
return ckdb

15
db/ckdb_utils.py Normal file
View File

@ -0,0 +1,15 @@
from aioch import Client
from core.config import settings
from .ckdb import CKDrive
async def connect_to_ck(pool_size=15):
for i in range(pool_size):
client = Client(**settings.CK_CONFIG)
CKDrive.ClientPool.add(client)
async def close_ck_connection():
for c in CKDrive.ClientPool:
await c.disconnect()

View File

@ -1,51 +0,0 @@
import crud
import schemas
from core.config import settings
# 创建一个超级用户、、
from db import connect_to_mongo, get_database
import asyncio
connect_to_mongo()
db = get_database()
async def create_superuser():
user = await crud.user.get_by_user(db=db, name=settings.FIRST_NAME)
if not user:
user_in = schemas.UserCreate(
name=settings.FIRST_NAME,
email=settings.FIRST_EMAIL,
password=settings.FIRST_SUPERUSER_PASSWORD,
is_superuser=True,
)
await crud.user.create(db, user_in)
await crud.user.create_index(db)
async def project_index():
await crud.project.create_index(db)
async def folder_index():
await crud.folder.create_index(db)
async def space_index():
await crud.space.create_index(db)
async def dashboard_index():
await crud.dashboard.create_index(db)
async def main():
await create_superuser()
await project_index()
await folder_index()
await space_index()
await dashboard_index()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

32
db/redisdb.py Normal file
View File

@ -0,0 +1,32 @@
from aredis import StrictRedis
import asyncio
class RedisDrive:
client: StrictRedis = None
# async def get_keys(self, *keys, prefix='') -> list:
# res = []
# for key in keys:
# key = prefix + key
# data = await self.client.get(key, encoding='utf8')
# res.append(data)
# return res
async def smembers_keys(self, *keys, prefix='') -> dict:
tasks = []
for key in keys:
task = asyncio.create_task(self.client.smembers(prefix + key))
tasks.append(task)
data = await asyncio.gather(*tasks)
return {k: v for k, v in zip(keys, data)}
def __getattr__(self, item):
return getattr(self.client, item)
rdb = RedisDrive()
def get_redis_pool() -> RedisDrive:
return rdb

12
db/redisdb_utils.py Normal file
View File

@ -0,0 +1,12 @@
from aredis import StrictRedis
from core.config import settings
from .redisdb import RedisDrive
async def connect_to_redis():
RedisDrive.client = StrictRedis(**settings.REDIS_CONF)
async def close_redis_connection():
pass

86
init_db.py Normal file
View File

@ -0,0 +1,86 @@
import crud
import schemas
from core.config import settings
# 创建一个超级用户、、
from db import connect_to_mongo, get_database
import asyncio
connect_to_mongo()
db = get_database()
async def create_superuser():
user = await crud.user.get_by_user(db=db, name=settings.SUPERUSER_NAME)
if not user:
user_in = schemas.UserCreate(
name=settings.SUPERUSER_NAME,
email=settings.SUPERUSER_EMAIL,
password=settings.SUPERUSER_PASSWORD,
nickname=settings.SUPERUSER_NICKNAME,
is_superuser=True,
)
await crud.user.create(db, user_in)
await crud.user.create_index(db)
async def project_index():
await crud.project.create_index(db)
async def folder_index():
await crud.folder.create_index(db)
async def space_index():
await crud.space.create_index(db)
async def dashboard_index():
await crud.dashboard.create_index(db)
async def report_index():
await crud.report.create_index(db)
async def data_attr_index():
await crud.data_attr.create_index(db)
async def event_mana():
await crud.event_mana.create_index(db)
async def api_list_index():
await crud.api_list.create_index(db)
async def role_index():
await crud.role.create_index(db)
async def authority_init():
await crud.authority.create_index(db)
await crud.authority.create(db, 'p', '*', '*', '/docs', '*')
await crud.authority.create(db, 'p', '*', '*', '/openapi.json', '*')
await crud.authority.create(db, 'p', '*', '*', '/api/v1/user/login', '*')
await crud.authority.create(db, 'p', '*', '*', '/docs', '*')
await crud.authority.create(db, 'p', '*', '*', '/api/v1/project/', '*')
async def main():
# await create_superuser()
# await project_index()
# await folder_index()
# await space_index()
# await dashboard_index()
# await report_index()
await authority_init()
# await data_attr_index()
# await event_mana()
# await api_list_index()
# await role_index()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -1,22 +0,0 @@
import logging
from db.init_db import init_db
from db.mongodb_utils import SessionLocal
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def init() -> None:
db = SessionLocal()
init_db(db)
def main() -> None:
logger.info("Creating initial data")
init()
logger.info("Initial data created")
if __name__ == "__main__":
main()

163
main.py
View File

@ -1,27 +1,166 @@
import binascii
import time
import uvicorn import uvicorn
from fastapi import FastAPI from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from core.config import settings
from starlette.middleware.cors import CORSMiddleware from starlette.middleware.cors import CORSMiddleware
from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, BaseUser, SimpleUser
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.requests import HTTPConnection
from starlette.responses import Response, JSONResponse
from db import connect_to_mongo, close_mongo_connection import crud
import schemas
from db.redisdb import get_redis_pool
from middleware import CasbinMiddleware
from db import connect_to_mongo, close_mongo_connection, get_database
from db.ckdb_utils import connect_to_ck, close_ck_connection
from db.redisdb_utils import connect_to_redis, close_redis_connection
from utils import *
from api.api_v1.api import api_router
from core.config import settings
from api.deps import get_current_user2
app = FastAPI(title=settings.PROJECT_NAME) app = FastAPI(title=settings.PROJECT_NAME)
app.include_router(api_router, prefix=settings.API_V1_STR)
if settings.BACKEND_CORS_ORIGINS: app.add_event_handler("startup", connect_to_mongo)
app.add_middleware( app.add_event_handler("startup", connect_to_redis)
app.add_event_handler("startup", connect_to_ck)
app.add_event_handler("shutdown", close_mongo_connection)
app.add_event_handler("shutdown", close_redis_connection)
app.add_event_handler("shutdown", close_ck_connection)
class CurrentUser(BaseUser):
def __init__(self, username: str, user_id: str) -> None:
self.username = username
self.id = user_id
@property
def is_authenticated(self) -> bool:
return True
@property
def display_name(self) -> str:
return self.username
@property
def identity(self) -> str:
return ''
class BasicAuth(AuthenticationBackend):
async def authenticate(self, request):
if "Authorization" not in request.headers or request.scope.get('path') == '/api/v1/user/login':
return None
auth = request.headers["Authorization"]
if len(auth) < 20:
return None
try:
user = get_current_user2(auth.split(' ')[1])
except (ValueError, UnicodeDecodeError, binascii.Error):
raise AuthenticationError("身份验证失败,请重新登录")
return AuthCredentials(["authenticated"]), CurrentUser(user.name, user.id)
def login_expired(conn: HTTPConnection, exc: Exception) -> Response:
return JSONResponse(schemas.Msg(code=-5, msg='请重新登录').dict(), status_code=200)
#处理路由权限问题
@app.middleware("http")
async def panduan_quanxian_url(request: Request, call_next):
#user_id=request.user.id
#user=request.user.username
start_time = int(time.time() * 1000)
response = await call_next(request)
process_time = int(time.time() * 1000) - start_time
response.headers["X-Process-Time"] = str(process_time)
url=request.url.path
if 'docs' in url or 'openapi.json' in url:
return response
if url in ['/api/v1/user/login','/api/v1/user/send_auth_code']:
return response
game=request.url.query.split('=')[1]
if 'undefined' in game:
return response
if '&' in game:
game=game.split('&')[0]
judge_url = await crud.user_url.get_quanxian(get_database(), schemas.Url_quanxian(user_id=request.user.id))
if judge_url == {}:
# data='没有匹配这个游戏'
return Response(schemas.Msg(code=0, msg='没有操作权限',data='').json())
if game not in judge_url['game']:
#data='没有匹配这个游戏'
return Response(schemas.Msg(code=0, msg='没有操作权限',data='' ).json())
quanxian_dict={}
for i in range(len(judge_url['game'])):
quanxian_dict[judge_url['game'][i]]=judge_url['quanxian'][i]
user_list=await crud.url_list.get_url(get_database(),schemas.Url_list(name=quanxian_dict[game]))
api_list=[]
state_list=[]
api_dict={}
for i in user_list:
for api in i['api_list']:
api_list.append(api)
for quanxian in i['state']:
state_list.append(quanxian)
for i in range(len(api_list)):
api_dict[api_list[i]]=state_list[i]
if url not in api_list:
# data='没有对应路由'
return Response(schemas.Msg(code=0, msg='没有操作权限',data='').json())
elif api_dict[url] != True:
# data='路由为False'
return Response(schemas.Msg(code=0, msg='没有操作权限',data='').json())
return response
#app.add_middleware(CasbinMiddleware, enforcer=casbin_enforcer)
app.add_middleware(AuthenticationMiddleware, backend=BasicAuth(), on_error=login_expired)
app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=['*'], allow_origins=['*'],
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
) )
app.add_event_handler("startup", connect_to_mongo)
app.add_event_handler("shutdown", close_mongo_connection)
from api.api_v1.api import api_router
app.include_router(api_router, prefix=settings.API_V1_STR) @app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return Response(schemas.Msg(code=-4, msg='请求错误', data=str(exc)).json(), status_code=400)
@app.exception_handler(Exception)
async def http_exception_handler(request, exc):
return Response(schemas.Msg(code=-3, msg='服务器错误').json(), status_code=500)
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = int(time.time() * 1000)
response = await call_next(request)
process_time = int(time.time() * 1000) - start_time
response.headers["X-Process-Time"] = str(process_time)
user_id = 'anonymous'
try:
user_id = request.user.id
except:
pass
await crud.api_log.insert_log(get_database(), schemas.ApiLogInsert(
api=str(request.url),
ms=process_time,
user_id=user_id
))
return response
if __name__ == '__main__': if __name__ == '__main__':
uvicorn.run(app='main:app', host="127.0.0.1", port=8889, reload=True, debug=True) #uvicorn.run(app='main:app', host="0.0.0.0", port=7899, reload=True, debug=True)
uvicorn.run(app='main:app', host="0.0.0.0", port=7899, reload=True, debug=True)

87
main2.py Normal file
View File

@ -0,0 +1,87 @@
import binascii
import time
import uvicorn
from fastapi import FastAPI, Request
from starlette.middleware.cors import CORSMiddleware
from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, BaseUser, SimpleUser
from starlette.middleware.authentication import AuthenticationMiddleware
from middleware import CasbinMiddleware
from db import connect_to_mongo, close_mongo_connection, get_database
from db.ckdb_utils import connect_to_ck, close_ck_connection
from db.redisdb_utils import connect_to_redis, close_redis_connection
from utils import *
from api.api_v1.api import api_router
from core.config import settings
from api.deps import get_current_user2
app = FastAPI(title=settings.PROJECT_NAME)
app.include_router(api_router, prefix=settings.API_V1_STR)
app.add_event_handler("startup", connect_to_mongo)
app.add_event_handler("startup", connect_to_redis)
app.add_event_handler("startup", connect_to_ck)
app.add_event_handler("shutdown", close_mongo_connection)
app.add_event_handler("shutdown", close_redis_connection)
app.add_event_handler("shutdown", close_ck_connection)
class CurrentUser(BaseUser):
def __init__(self, username: str, user_id: str) -> None:
self.username = username
self.id = user_id
@property
def is_authenticated(self) -> bool:
return True
@property
def display_name(self) -> str:
return self.username
@property
def identity(self) -> str:
return ''
class BasicAuth(AuthenticationBackend):
async def authenticate(self, request):
if "Authorization" not in request.headers:
return None
auth = request.headers["Authorization"]
if len(auth) < 20:
return None
try:
user = get_current_user2(auth.split(' ')[1])
except (ValueError, UnicodeDecodeError, binascii.Error):
raise AuthenticationError("Invalid basic auth credentials")
return AuthCredentials(["authenticated"]), CurrentUser(user.name, user.id)
app.add_middleware(CasbinMiddleware, enforcer=casbin_enforcer)
app.add_middleware(AuthenticationMiddleware, backend=BasicAuth())
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = int(time.time()*1000)
response = await call_next(request)
process_time = int(time.time()*1000) - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
if __name__ == '__main__':
uvicorn.run(app='main:app', host="0.0.0.0", port=7889, reload=True, debug=True)

1
middleware/__init__.py Normal file
View File

@ -0,0 +1 @@
from .casbin import CasbinMiddleware

71
middleware/casbin.py Normal file
View File

@ -0,0 +1,71 @@
from utils.casbin.enforcer import Enforcer
from fastapi import HTTPException
from starlette.authentication import BaseUser
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.status import HTTP_403_FORBIDDEN
from starlette.types import ASGIApp, Receive, Scope, Send
import schemas
class CasbinMiddleware:
"""
Middleware for Casbin
"""
def __init__(
self,
app: ASGIApp,
enforcer: Enforcer,
) -> None:
"""
Configure Casbin Middleware
:param app:Retain for ASGI.
:param enforcer:Casbin Enforcer, must be initialized before FastAPI start.
"""
self.app = app
self.enforcer = enforcer
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope["type"] not in ("http", "websocket"):
await self.app(scope, receive, send)
return
if await self._enforce(scope, receive):
await self.app(scope, receive, send)
return
else:
response = JSONResponse(
status_code=HTTP_403_FORBIDDEN,
content="没有操作权限"
)
await response(scope, receive, send)
return
async def _enforce(self, scope: Scope, receive: Receive) -> bool:
"""
Enforce a request
:param user: user will be sent to enforcer
:param request: ASGI Request
:return: Enforce Result
"""
request = Request(scope, receive)
path = request.url.path
method = request.method
if 'user' not in scope:
raise RuntimeError("Casbin Middleware must work with an Authentication Middleware")
assert isinstance(request.user, BaseUser)
user = request.user.display_name if request.user.is_authenticated else 'anonymous'
dom = request.query_params.get('game', '0')
print(user, dom, path, method)
return self.enforcer.enforce(user, dom, path, method)

0
models/__init__.py Normal file
View File

1616
models/behavior_analysis.py Normal file

File diff suppressed because it is too large Load Diff

223
models/user_analysis.py Normal file
View File

@ -0,0 +1,223 @@
from typing import Tuple
import arrow
import sqlalchemy as sa
import json
from fastapi import Depends
import pandas as pd
from sqlalchemy import func, or_, and_, not_
import crud
import schemas
from core.config import settings
from db import get_database
from db.redisdb import get_redis_pool, RedisDrive
class UserAnalysis:
def __init__(self, game: str, data_in: schemas.CkQuery, rdb: RedisDrive = Depends(get_redis_pool)):
self.game = game
self.rdb = rdb
self.user_tbl = None
self.event_view = data_in.eventView
self.events = data_in.events
self.zone_time: int = 0
self.data_in = data_in
self.global_filters = []
self.groupby = None
self.time_particle = None
self.date_range = None
self.unit_num = None
self.global_relation = 'and'
self.ext_filters = (self.data_in.ext_filter.get('filts', []), self.data_in.ext_filter.get('relation', 'and'))
async def init(self, *args, **kwargs):
if self.data_in.report_id:
db = get_database()
report = await crud.report.get(db, id=self.data_in.report_id)
self.event_view = report['query']['eventView']
self.events = report['query']['events']
else:
self.event_view = self.data_in.eventView
self.events = self.data_in.events
await self._init_table()
self.zone_time = self._get_zone_time()
self.time_particle = self._get_time_particle_size()
self.groupby = self._get_group_by()
self.unit_num = self._get_unit_num()
self.global_relation = self.event_view.get('relation', 'and')
# 用户自带过滤
if 'data_where' in kwargs:
self.global_filters.extend(kwargs['data_where'].get(self.game, []))
async def _init_table(self):
"""
从redis中取出表字段构建表结构
:return:
"""
res_json = await self.rdb.get(f'{self.game}_user')
columns = json.loads(res_json).keys()
metadata = sa.MetaData(schema=self.game)
self.user_tbl = sa.Table('user_view', metadata, *[sa.Column(column) for column in columns])
def _get_time_particle_size(self):
return self.event_view.get('timeParticleSize') or 'P1D'
def _get_unit_num(self):
return self.event_view.get('unitNum')
def _get_group_by(self):
return [getattr(self.user_tbl.c, item['columnName']) for item in self.event_view.get('groupBy', [])]
def _get_zone_time(self):
return int(self.event_view.get('zone_time', 8))
# def _get_filters(self, filters):
# tbl = self.user_tbl
# where = []
# for item in filters:
# col = getattr(tbl.c, item['columnName'])
#
# comparator = item['comparator']
# ftv = item['ftv']
# if comparator == '==':
# if len(ftv) > 1:
# where.append(or_(*[col == v for v in ftv]))
# else:
# where.append(col == ftv[0])
# elif comparator == '>=':
# where.append(col >= ftv[0])
# elif comparator == '<=':
# where.append(col <= ftv[0])
# elif comparator == '>':
# where.append(col > ftv[0])
# elif comparator == '<':
# where.append(col < ftv[0])
#
# elif comparator == 'is not null':
# where.append(col.isnot(None))
# elif comparator == 'is null':
# where.append(col.is_(None))
#
# elif comparator == '!=':
# where.append(col != ftv[0])
#
# elif comparator == 'like':
# where.append(col.like(f'%{ftv[0]}%'))
#
# elif comparator == 'not like':
# where.append(col.notlike(f'%{ftv[0]}%'))
#
# elif comparator == 'in':
# where.append(col.in_(ftv))
#
#
# return where
def handler_filts(self, *filters):
"""
:param filters: (filts:list,relation:str)
:param g_f:
:param relation:
:return:
"""
user_filters = []
for filter in filters:
filts = filter[0]
relation = filter[1]
user_filter = []
for item in filts:
where = user_filter
col = sa.Column(item['columnName'])
if item.get('data_type') == 'datetime':
col = func.addHours(col, self.zone_time)
comparator = item['comparator']
ftv = item['ftv']
if comparator == '==':
if len(ftv) > 1:
where.append(or_(*[col == v for v in ftv]))
else:
where.append(col == ftv[0])
elif comparator == '>=':
where.append(col >= ftv[0])
elif comparator == '<=':
where.append(col <= ftv[0])
elif comparator == '>':
where.append(col > ftv[0])
elif comparator == '<':
where.append(col < ftv[0])
elif comparator == 'is not null':
where.append(col.isnot(None))
elif comparator == 'is null':
where.append(col.is_(None))
elif comparator == 'like':
where.append(col.like(f'%{ftv[0]}%'))
elif comparator == 'not like':
where.append(col.notlike(f'%{ftv[0]}%'))
elif comparator == 'in':
where.append(col.in_(ftv))
elif comparator == '!=':
where.append(col != ftv[0])
if relation == 'and':
if user_filter:
user_filters.append(and_(*user_filter))
else:
if user_filter:
user_filters.append(or_(*user_filter))
return user_filters
def property_model(self):
event = self.events
selectd = getattr(self.user_tbl.c, event['quota'])
qry = sa.select(selectd)
account_id_col = getattr(self.user_tbl.c, '#account_id')
binduid_col = getattr(self.user_tbl.c, '#account_id')
# 聚合方式
analysis = event['analysis']
if analysis == 'trig_user_num':
selectd = [func.count().label('values')]
elif analysis == 'distinct_count':
selectd = [
func.count(sa.distinct(getattr(self.user_tbl.c, event['quota']))).label('values')]
else:
selectd = [
func.round(getattr(func, analysis)(getattr(self.user_tbl.c, event['quota'])), 2).label(
'values')]
where = self.handler_filts((event['filts'], event.get('relation')),
(self.global_filters, self.global_relation),
self.ext_filters
)
qry = sa.select((*self.groupby, *selectd)).where(*where)
qry = qry.group_by(*self.groupby)
qry = qry.order_by(sa.Column('values').desc())
qry = qry.limit(1000)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
print(sql)
result = {'sql': sql,
'groupby': [i.key for i in self.groupby],
'quota': event['quota']
}
return result

240
models/user_label.py Normal file
View File

@ -0,0 +1,240 @@
"""
本质查出符合条件的用户id
得到sql 查uid
"""
import re
from typing import Tuple
import arrow
import sqlalchemy as sa
import json
from fastapi import Depends
import pandas as pd
from sqlalchemy import func, or_, and_, not_
import crud
import schemas
from core.config import settings
from db import get_database
from db.redisdb import get_redis_pool, RedisDrive
class UserClusterDef:
def __init__(self, game: str, cluster_name: str, data_where: list = None, rdb: RedisDrive = get_redis_pool(),
**kwargs):
self.game = game
self.rdb = rdb
self.cluster_name = cluster_name
self.event_tbl = None
self.data_where = data_where or []
self.kwargs = kwargs
async def _init_tal(self):
res_json = await self.rdb.get(f'{self.game}_event')
columns = json.loads(res_json).keys()
metadata = sa.MetaData(schema=self.game)
self.event_tbl = sa.Table('event', metadata, *[sa.Column(column) for column in columns])
res_json = await self.rdb.get(f'{self.game}_user')
columns = json.loads(res_json).keys()
metadata = sa.MetaData(schema=self.game)
# self.user_tbl = sa.Table('user_view', metadata, *[sa.Column(column) for column in columns]) # 修改了这里,这是原本的
self.user_tbl = sa.Table('event', metadata, *[sa.Column(column) for column in columns])
self.u_account_id_col = getattr(self.user_tbl.c, '#account_id')
self.e_account_id_col = getattr(self.event_tbl.c, '#account_id')
self.account_id_col = sa.Column('#account_id')
async def init(self):
self.data_in = (
await crud.user_label.find_one(get_database(), {'cluster_name': self.cluster_name, 'game': self.game},
{'qp': 1})).get('qp')
await self._init_tal()
self.events = self.data_in['user_cluster_def']['events']
self.event_relation = self.data_in['user_cluster_def']['event_relation']
async def handler_filts(self, *filters):
"""
:param filters: (filts:list,relation:str)
:param g_f:
:param relation:
:return:
"""
user_filters = []
event_filters = []
for filter in filters:
filts = filter[0]
relation = filter[1]
user_filter = []
event_filter = []
for item in filts:
comparator = item['comparator']
if item['tableType'] == 'user':
where = user_filter
elif item['tableType'] == 'event':
where = event_filter
else:
continue
tbl = getattr(self, f'{item["tableType"]}_tbl')
col = getattr(tbl.c, item['columnName'])
ftv = item['ftv']
if comparator == '==':
if len(ftv) > 1:
where.append(or_(*[col == v for v in ftv]))
else:
where.append(col == ftv[0])
elif comparator == '>=':
where.append(col >= ftv[0])
elif comparator == '<=':
where.append(col <= ftv[0])
elif comparator == '>':
where.append(col > ftv[0])
elif comparator == '<':
where.append(col < ftv[0])
elif comparator == 'is not null':
where.append(col.isnot(None))
elif comparator == 'is null':
where.append(col.is_(None))
elif comparator == 'like':
where.append(col.like(f'%{ftv[0]}%'))
elif comparator == 'not like':
where.append(col.notlike(f'%{ftv[0]}%'))
elif comparator == 'in':
where.append(col.in_(ftv))
elif comparator == '!=':
where.append(col != ftv[0])
if relation == 'and':
if event_filter:
event_filters.append(and_(*event_filter))
if user_filter:
user_filters.append(and_(*user_filter)),
else:
if event_filter:
event_filters.append(or_(*event_filter))
if user_filter:
user_filters.append(or_(*user_filter))
return event_filters, user_filters
def to_sql_qry(self):
qry = None
for event in self.events:
event_name = event['event_name']
event_name_col = getattr(self.event_tbl.c, '#event_name')
analysis = event['prop_quota']['analysis']
quota = event['prop_quota']['quota']
num = event['num'].split(',')
date_type = event.get('date_type', 'dynamic')
e_days = event.get('e_days')
s_days = event.get('s_days')
is_touch = event.get('is_touch', True)
filts = event['filts']
zone = event.get('zone', 8)
# 账号数据过滤
data_where = []
filters = []
filters.extend(self.data_where)
for item in filters:
tmp = settings.CK_CALC_SYMBO[item['comparator']](sa.Column(item['columnName']), item['ftv'])
data_where.append(tmp)
event_time_col = func.addHours(getattr(self.event_tbl.c, '#event_time'), zone)
date_where = []
if date_type == 'static':
start_time = event['start_time']
end_time = event['end_time']
date_where.extend(
[settings.CK_CALC_SYMBO['>='](event_time_col, start_time),
settings.CK_CALC_SYMBO['<='](event_time_col, end_time)]
)
elif date_type == 'dynamic':
start_time = arrow.get().shift(days=-int(s_days)).strftime('%Y-%m-%d 00:00:00')
end_time = arrow.get().shift(days=-int(e_days)).strftime('%Y-%m-%d 23:59:59')
date_where.extend(
[settings.CK_CALC_SYMBO['>='](event_time_col, start_time),
settings.CK_CALC_SYMBO['<='](event_time_col, end_time)]
)
else:
# 所有时间
pass
uce_calcu_symbol = event['uce_calcu_symbol']
event_name_where = []
if event_name != '*':
# 任意事件
event_name_where.append(settings.CK_CALC_SYMBO['=='](event_name_col, event_name))
if quota != '*':
selectd = [self.account_id_col,
func.round(getattr(func, analysis)(getattr(self.event_tbl.c, quota)), 2).label(
'values')
]
if len(num) >1:#处理区间筛选的问题
qry_tmp = sa.select(self.account_id_col).select_from(
sa.select(selectd).where(*date_where, *event_name_where, *data_where).group_by(
self.e_account_id_col).having(sa.and_(sa.Column('values') > num[0],sa.Column('values') <= num[1])
))
else:
qry_tmp = sa.select(self.account_id_col).select_from(
sa.select(selectd).where(*date_where, *event_name_where, *data_where).group_by(
self.e_account_id_col).having(
settings.CK_CALC_SYMBO[uce_calcu_symbol](sa.Column('values'), *num)))
else:
selectd = [self.account_id_col]
qry_tmp = sa.select(self.account_id_col).select_from(
sa.select(selectd).where(*date_where, *event_name_where, *data_where))
if qry is None:
qry = qry_tmp
else:
if self.event_relation == 'and':
qry = sa.select(self.account_id_col).select_from(
sa.join(qry, qry_tmp, getattr(qry.c, '#account_id') == getattr(qry_tmp.c, '#account_id')))
elif self.event_relation == 'or':
qry = sa.select(sa.distinct(self.account_id_col)).select_from(sa.union_all(qry, qry_tmp))
# 处理没做过
if not is_touch:
qry = sa.select(self.u_account_id_col).where(self.u_account_id_col.notin_(qry))
return qry
def to_sql(self):
qry = self.to_sql_qry()
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
print(sql)
return sql
def cluster_user_list(self):
sub_qry = self.to_sql_qry()
page = self.kwargs.get('page') or 1
page -= 1
limit = self.kwargs.get('limit', 50)
qry = sa.select('*').where(self.u_account_id_col.in_(sub_qry)).order_by(sa.Column('#reg_time')) \
.offset(page * limit) \
.limit(limit)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
print(sql)
return sql
def cluster_user_count(self):
sub_qry = self.to_sql_qry()
qry = sa.select(func.count(self.account_id_col).label('values')).select_from(sub_qry)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
print(sql)
return sql

308
models/x_analysis.py Normal file
View File

@ -0,0 +1,308 @@
from typing import Tuple
import arrow
import sqlalchemy as sa
import json
from fastapi import Depends
import pandas as pd
from sqlalchemy import func, or_, and_, not_, MetaData
import crud
import schemas
from core.config import settings
from db import get_database
from models.user_label import UserClusterDef
from db.redisdb import get_redis_pool, RedisDrive
class XAnalysis:
def __init__(self, data_in: schemas.CkQuery, game: str):
self.data_in = data_in
self.game = game
self.event_view = dict()
self.events = []
self.zone_time: int = 0
self.global_filters = []
self.account_filters = []
self.global_relation = 'and'
self.date_range = []
self.ext_filters = (self.data_in.ext_filter.get('filts', []), self.data_in.ext_filter.get('relation', 'and'))
def _get_global_filters(self):
_res = self.event_view.get('filts', [])
if _res:
for idx, item in enumerate(_res):
if item['data_type'] == 'user_label':
_res[idx].update({
'tableType': item['data_type'],
})
else:
_res[idx].update({
'tableType': item['table_type'],
})
return _res # 获取event_view字典里面filts的值或返回空列表
async def init(self, *args, **kwargs):
if self.data_in.report_id:
db = get_database()
report = await crud.report.get(db, id=self.data_in.report_id)
self.event_view = report['query']['eventView']
self.events = report['query']['events']
try:
e_days = self.event_view['e_days']
s_days = self.event_view['s_days']
except:
# 兼容以前的
e_days, s_days = self.event_view['recentDay'].split('-')
# self.event_view['endTime'] = arrow.get().shift(days=-int(e_days)+1).strftime('%Y-%m-%d 23:59:59')
# self.event_view['startTime'] = arrow.get().shift(days=-int(s_days)+1).strftime('%Y-%m-%d 00:00:00')
self.event_view['endTime'] = arrow.get().shift(days=-int(e_days)).strftime('%Y-%m-%d 23:59:59')
self.event_view['startTime'] = arrow.get().shift(days=-int(s_days)).strftime('%Y-%m-%d 00:00:00')
else:
self.event_view = self.data_in.eventView
self.events = self.data_in.events
for d in pd.date_range(self.event_view['startTime'], self.event_view['endTime'], freq='D', tz='UTC'):
self.date_range.append(d.date())
self.global_filters = self._get_global_filters()
self.global_relation = self.event_view.get('relation', 'and')
# 用户自带过滤
if 'data_where' in kwargs:
self.account_filters = kwargs['data_where'].get(self.game, [])
# def handler_filts(self, *filters):
# """
# :param filters: (filts:list,relation:str)
# :param g_f:
# :param relation:
# :return:
# """
#
# event_filters = []
# for filter in filters:
# filts = filter[0]
# relation = filter[1]
# event_filter = []
# for item in filts:
#
# where = event_filter
#
# col = sa.Column(item['columnName'])
#
# comparator = item['comparator']
# ftv = item['ftv']
# if comparator == '==':
# if len(ftv) > 1:
# where.append(or_(*[col == v for v in ftv]))
# else:
# where.append(col == ftv[0])
# elif comparator == '>=':
# where.append(col >= ftv[0])
# elif comparator == '<=':
# where.append(col <= ftv[0])
# elif comparator == '>':
# where.append(col > ftv[0])
# elif comparator == '<':
# where.append(col < ftv[0])
#
# elif comparator == 'is not null':
# where.append(col.isnot(None))
# elif comparator == 'is null':
# where.append(col.is_(None))
#
# elif comparator == 'like':
# where.append(col.like(f'%{ftv[0]}%'))
#
# elif comparator == 'not like':
# where.append(col.notlike(f'%{ftv[0]}%'))
#
# elif comparator == 'in':
# where.append(col.in_(ftv))
#
# elif comparator == '!=':
# where.append(col != ftv[0])
# if relation == 'and':
# if event_filter:
# event_filters.append(and_(*event_filter))
# else:
# if event_filter:
# event_filters.append(or_(*event_filter))
#
# return event_filters
async def handler_filts(self, *filters):
"""
:param filters: (filts:list,relation:str)
:param g_f:
:param relation:
:return:
"""
event_filters = []
for filter in filters:
filts = filter[0]
relation = filter[1]
user_filter = []
event_filter = []
for item in filts:
comparator = item['comparator']
if item['tableType'] == 'user':
where = user_filter
elif item['tableType'] == 'event':
where = event_filter
elif item['tableType'] == 'user_label':
user_cluster_def = UserClusterDef(self.game, item['columnName'], self.account_filters)
await user_cluster_def.init()
sub_qry = user_cluster_def.to_sql_qry()
if comparator == 'in':
event_filter.append(sa.Column('#account_id').in_(sub_qry))
else:
event_filter.append(sa.Column('#account_id').notin_(sub_qry))
continue
else:
continue
col = sa.Column(item['columnName'])
comparator = item['comparator']
ftv = item['ftv']
if comparator == '==':
if len(ftv) > 1:
where.append(or_(*[col == v for v in ftv]))
else:
where.append(col == ftv[0])
elif comparator == '>=':
where.append(col >= ftv[0])
elif comparator == '<=':
where.append(col <= ftv[0])
elif comparator == '>':
where.append(col > ftv[0])
elif comparator == '<':
where.append(col < ftv[0])
elif comparator == 'is not null':
where.append(col.isnot(None))
elif comparator == 'is null':
where.append(col.is_(None))
elif comparator == 'like':
where.append(col.like(f'%{ftv[0]}%'))
elif comparator == 'not like':
where.append(col.notlike(f'%{ftv[0]}%'))
elif comparator == 'in':
where.append(col.in_(ftv))
elif comparator == '!=':
where.append(col != ftv[0])
if relation == 'and':
if event_filter:
event_filters.append(and_(*event_filter))
else:
if event_filter:
event_filters.append(or_(*event_filter))
return event_filters
async def ltv_model_sql(self):
days = (arrow.get(self.event_view['endTime']).date() - arrow.get(self.event_view['startTime']).date()).days
quota = self.event_view['quota']
select_ltv = []
sumpay = []
sum_money = []
# for i in range(1, days + 2):
ltv_n = [*[k for k in range(1, 61)], 70, 75, 80, 85, 90, 95, 100, 110, 120, 150, 180, 210, 240, 270, 300, 360]
for i in ltv_n:
# select_ltv.append(func.round(sa.Column(f'sumpay_{i}') / sa.Column('cnt1'), 2).label(f'LTV{i}'))
select_ltv.append(
f"if(dateDiff('day', reg.date, now())<{i - 1}, '-',toString(round(sumpay_{i} / cnt1, 2))) AS LTV{i}")
sumpay.append(f"sum(if(dateDiff('day', a.date, b.date) < {i}, money, 0)) as sumpay_{i}")
sum_money.append(f"sumpay_{i}")
# qry = sa.select(*select_ltv)
# select_ltv_str = str(qry.compile(compile_kwargs={"literal_binds": True}))
# select_ltv_str = select_ltv_str.split('SELECT ')[1]
sumpay_str = ','.join(sumpay)
select_ltv_str = ','.join(select_ltv)
sum_money_str = ','.join(sum_money)
where = [
sa.Column('date') >= self.event_view['startTime'].split(' ')[0],
sa.Column('date') <= self.event_view['endTime'].split(' ')[0]
]
if quota == '#distinct_id':
where.append(sa.Column('is_new_device') == 1)
qry = sa.select().where(*where)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
where_str = sql.split('WHERE ')[1]
where_order = await self.handler_filts((self.global_filters, self.global_relation)) # global_relation就是 and
where_order_str = 1
if where_order:
qry = sa.select().where(*where_order)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
where_order_str = 'WHERE '.join(sql.split('WHERE ')[1:])
# where_account = await self.handler_filts((self.account_filters, 'and'), self.ext_filters)
where_account = where_order
where_account_str = 1
if where_account:
qry = sa.select().where(*where_account)
sql = str(qry.compile(compile_kwargs={"literal_binds": True}))
where_account_str = sql.split('WHERE ')[1]
if "AND" in where_account_str:
where_account_str = where_account_str.split('AND')[1]
else:
if "orderid" in where_account_str:
where_account_str = "1=1"
if self.game == 'huixie' and quota == '#distinct_id':
event_n='new_device'
elif self.game == 'yxwd_h5':
event_n = 'role_create'
else:
event_n = 'create_account'
if 'is_new_device = 1' in where_str:
timed=where_str.replace('AND is_new_device = 1','',1)
else:
timed=where_str
sql = f"""SELECT reg.date as date,
cnt1,
{select_ltv_str},
{sum_money_str}
FROM (SELECT toDate(addHours(`#event_time`, `#zone_offset`)) as date, uniqExact(`{quota}`) cnt1
FROM {self.game}.event
where `#event_name` = '{event_n}'
AND {where_str} AND {where_account_str}
GROUP BY toDate(addHours(`#event_time`, `#zone_offset`))) as reg
left join
(select a.date,
{sumpay_str}
from (SELECT toDate(addHours(`#event_time`, `#zone_offset`)) as date, `{quota}`
FROM {self.game}.event
where `#event_name` = '{event_n}'
AND {where_str} AND {where_account_str} ) as a
left join (select `{quota}`, unitPrice/100 as money, toDate(addHours(`#event_time`, `#zone_offset`)) as date
from {self.game}.event
where `#event_name` = 'pay' and {where_order_str} AND {where_account_str}) b
on a.`{quota}` = b.`{quota}`
group by a.date) log on reg.date = log.date
order by date
"""
#{timed} and 计算LTV时所选时间区间只是为了划分注册人群截止时间应该按照当前时间执行
print(sql)
return {'sql': sql, 'quota': quota,
'start_date': self.event_view['startTime'][:10],
'end_date': self.event_view['endTime'][:10],
'date_range': self.date_range,
'ltv_n': ltv_n
}

14
rbac_model.conf Normal file
View File

@ -0,0 +1,14 @@
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || g(r.sub, p.sub, r.dom) || keyMatch(r.sub, p.sub)) && (p.dom=="*" || r.dom == p.dom) && ( p.obj=="*" || r.obj == p.obj) && (p.act=="*" || r.act == p.act) || r.sub=="root"

7
rbac_policy.csv Normal file
View File

@ -0,0 +1,7 @@
p, *, /api/v1/user/login, *
p, *, /api/v1/project/, *
p, *, /docs, *
p, *, /openapi.json, *
g, cathy, dataset1_admin
1 p, *, /api/v1/user/login, *
2 p, *, /api/v1/project/, *
3 p, *, /docs, *
4 p, *, /openapi.json, *
5 g, cathy, dataset1_admin

21
rbac_policy.py Normal file
View File

@ -0,0 +1,21 @@
import casbin
from core.config import settings
from pymongo import MongoClient
from utils import *
client = MongoClient(settings.DATABASE_URI)
db = client[settings.MDB_DB]
collection = db[settings.CASBIN_COLL]
# casbin_model.add_policy('g', 'g', ['root', 'superAdmin', ])
# casbin_model.add_policy('g', 'g', ['legu', 'admin'])
# casbin_enforcer.add_role_for_user('user', 'role')
res = casbin_enforcer.delete_user('user')
print(res)
casbin_adapter.save_policy(casbin_model)

View File

@ -4,3 +4,25 @@ from .project import *
from .folder import * from .folder import *
from .space import * from .space import *
from .dashboard import * from .dashboard import *
from .report import *
from .authotity import *
from .table_struct import *
from .data_auth import *
from .data_attr import *
from .sql import *
from .api_log import *
from .event_mana import *
from .xquery import *
from .api_list import *
from .role import *
from .check_data import *
from .userlabel import *
from .select_map import *
from .project_number import *
from .proid_map import *
from .api_board import *
from .url_list import *
from .user_url import *
from .api_module import *
from .event_list import *
from .event_point import *

12
schemas/api_board.py Normal file
View File

@ -0,0 +1,12 @@
from typing import Any, List, Union
from pydantic import BaseModel, Field
from schemas import DBBase
from typing import Optional
class Api_board(BaseModel):
api_path: str = None
api_name: str = None
name: str

37
schemas/api_list.py Normal file
View File

@ -0,0 +1,37 @@
from typing import Any, List, Union
from pydantic import BaseModel, Field
from schemas import DBBase
from typing import Optional
class ApiBase(BaseModel):
path: str = None
name: str = None
desc: str = None
class AddApi(ApiBase):
path: str
name: str
desc: str = None
class UpdateApi(BaseModel):
path: str
name: str
class AddApiDB(DBBase, AddApi):
pass
class DelApi(BaseModel):
ids: List[str] = Field(..., description='要删除的id')
class EditApi(BaseModel):
id: str = Field(..., description='要编辑的id')
name: str
desc: str

9
schemas/api_log.py Normal file
View File

@ -0,0 +1,9 @@
from typing import Any
from pydantic import BaseModel
class ApiLogInsert(BaseModel):
api: str
ms: int
user_id: str

18
schemas/api_module.py Normal file
View File

@ -0,0 +1,18 @@
from typing import Any, List, Union
from pydantic import BaseModel, Field
from schemas import DBBase
from typing import Optional
class Url_module(BaseModel):
auth_id: str = None
path_name: str = None
api_list: List[str] = None
api_name: List[str] = None
state: List[bool] = None
class Add_module(BaseModel):
auth_id: str
url:str

82
schemas/authotity.py Normal file
View File

@ -0,0 +1,82 @@
from enum import Enum
from typing import List
from pydantic import BaseModel
class AddRoleForUserInDomain(BaseModel):
username: str
role_id: str
game: str
auth_id: str
class AddRoleForUsersInDomain(BaseModel):
data: List[AddRoleForUserInDomain]
class GetPermissionsForUserInDomain(BaseModel):
role_id: str
game: str
class DeleteRolesForUserInDomain(BaseModel):
username: str
role_id: str
game: str
class Policy(BaseModel):
role_id: str
game: str
path: str
act: str = '*'
class AddPolicy(BaseModel):
path_list: List[str]
role_id: str
game: str
act: str = '*'
class DelPolicy(Policy):
pass
class Ptype(str, Enum):
p = 'p'
g = 'g'
class CasbinRoleCreate(BaseModel):
role_name: str
role_api: List[str]
class CasbinDB(BaseModel):
ptype: Ptype
v0: str
v1: str
v2: str
class AccountCreate(BaseModel):
username: str
role_name: str
# nickname: str
data_auth_id: str
class AccountsCreate(BaseModel):
accounts: List[AccountCreate]
project_id: str
class AccountDeleteUser(BaseModel):
name: str
class AccountSetRole(BaseModel):
name: str
role_name: str

View File

@ -1,7 +1,9 @@
import uuid
from typing import Optional, Union from typing import Optional, Union
from bson import ObjectId from bson import ObjectId
from pydantic import BaseModel, Field from pydantic import BaseModel, Field, validator
from utils import *
# # mongodb _id 类型 # # mongodb _id 类型
@ -20,3 +22,7 @@ from pydantic import BaseModel, Field
class DBBase(BaseModel): class DBBase(BaseModel):
id: str = Field(None, alias='_id') id: str = Field(None, alias='_id')
@validator('id', pre=True, always=True)
def default_id(cls, v):
return v or get_uid()

20
schemas/check_data.py Normal file
View File

@ -0,0 +1,20 @@
from pydantic import BaseModel
class CheckData(BaseModel):
db_name: str
event_name: str
is_unique: bool
props: dict
default_field: dict = dict()
where: dict = dict()
game:str
class AddTemplate(BaseModel):
check: CheckData
title: str
class DelTemplate(BaseModel):
title: str

View File

@ -1,7 +1,7 @@
import uuid import uuid
from datetime import datetime from datetime import datetime
from enum import Enum from enum import Enum
from typing import List from typing import List, Dict
from pydantic import BaseModel from pydantic import BaseModel
@ -19,9 +19,80 @@ class DashboardCreate(DashboardBase):
# cat: str # cat: str
pid: str pid: str
class ReadDashboard(BaseModel):
id: str
class DashboardDelete(BaseModel):
ids: List[str]
class Report(BaseModel):
name: str = None
report_id: str = None
graph_type: str = None
ascending: bool = None
model: str = None
graph_size: str = None
sort: int = None
modelswitch: bool = None
avesumdata: bool = True
daydata: bool = True
reverseorder: bool = True
class EditShowReport(BaseModel):
dashboard_id: str
config: Report
class Category(str, Enum): class Category(str, Enum):
project = 'kanban' project = 'kanban'
space = 'space' space = 'space'
class EditDashboard(BaseModel):
dashboard_id: str
new_name: str
class DashboardMove(BaseModel):
source_ids: List[str]
dest_pid: str
cat: Category
class Sort(BaseModel):
dashboard_id: str
sort: int
class DashboardSort(BaseModel):
sort: List[Sort]
class DashboardCopy(BaseModel):
source_ids: List[str]
dest_project_id: str
class DashboardCopyToSpace(BaseModel):
source_ids: List[str]
project_id: str
dest_space_id: str
class AddReport(DBBase):
report_ids: List[Report]
class DelReport(DBBase):
report_id: str
class EditReport(DBBase):
report: Report
# -------------------------------------------------------------- # --------------------------------------------------------------
# 数据库模型 # 数据库模型
class DashboardDB(DBBase): class DashboardDB(DBBase):
@ -29,5 +100,6 @@ class DashboardDB(DBBase):
user_id: str user_id: str
project_id: str project_id: str
# cat: Category # cat: Category
reports: List[str] = []
pid: str pid: str
create_date: datetime = datetime.now() create_date: datetime = datetime.now()

14
schemas/data_attr.py Normal file
View File

@ -0,0 +1,14 @@
from pydantic import BaseModel
class DataAttrEdit(BaseModel):
name: str
show_name: str
is_show: bool
cat: str
class Add_attr(BaseModel):
cat: str
new_attribute: str
state: str
data_type: str

24
schemas/data_auth.py Normal file
View File

@ -0,0 +1,24 @@
from typing import List
from pydantic import BaseModel
class DataAuthCreate(BaseModel):
title: str
data: List[str] = []
class DataAuthEdit(BaseModel):
data_auth_id: str
title: str
data: List[str] = []
class DataAuthSet(BaseModel):
username: str
data_auth_id: str
class LoadProQuotas(BaseModel):
event_name: str
model: str = None

10
schemas/event_list.py Normal file
View File

@ -0,0 +1,10 @@
from typing import List, Dict
from pydantic import BaseModel
class Event_list(BaseModel):
game:str
details:List[Dict]
class Details(BaseModel):
event:str
event_name:str

9
schemas/event_mana.py Normal file
View File

@ -0,0 +1,9 @@
from pydantic import BaseModel
class EventMateEdit(BaseModel):
event_name: str
show_name: str
is_show: bool
desc: str
label_id:str

8
schemas/event_point.py Normal file
View File

@ -0,0 +1,8 @@
from pydantic import BaseModel
from typing import List
class Eventpoint(BaseModel):
game: str # 游戏名
event_name: str # 事件名
event_attr: List[str] # 事件属性

View File

@ -20,6 +20,10 @@ class FolderCreate(FolderBase):
pid: str pid: str
class FolderDelete(DBBase):
pass
class Category(str, Enum): class Category(str, Enum):
project = 'kanban' project = 'kanban'
space = 'space' space = 'space'

View File

@ -6,4 +6,4 @@ from pydantic import BaseModel
class Msg(BaseModel): class Msg(BaseModel):
code: int code: int
msg: str msg: str
detail: Any data: Any

0
schemas/proid_map.py Normal file
View File

View File

@ -2,7 +2,7 @@ import uuid
from datetime import datetime from datetime import datetime
from typing import List, Optional from typing import List, Optional
from pydantic import BaseModel from pydantic import BaseModel, Field
from schemas import DBBase from schemas import DBBase
@ -11,10 +11,50 @@ class ProjectBase(BaseModel):
name: str = None name: str = None
class MemberRole(BaseModel):
username: str
user_id: str
role_name: str
data_auth_id: str
class ProjectAddMember(BaseModel):
members: List[MemberRole]
project_id: str
class ProjectMember(BaseModel):
members: List[str]
project_id: str
class ProjectDetail(BaseModel):
project_id: str
class ProjectClean(BaseModel):
project_id: str
class Import_project(BaseModel):
game: str
games: str
class ProjectRename(BaseModel):
project_id: str
rename: str
class ProjectDelMember(BaseModel):
project_id: str
role: str
username: str
# 解析请求json 创建项目 # 解析请求json 创建项目
class ProjectCreate(ProjectBase): class ProjectCreate(ProjectBase):
name: str name: str = Field(..., title='项目名')
game: str = Field(..., title='游戏代号')
#qudao:str = Field(...,title='渠道')
# 查询某个项目看板 # 查询某个项目看板
class ProjectKanban(DBBase): class ProjectKanban(DBBase):
@ -25,6 +65,7 @@ class ProjectKanban(DBBase):
# 数据库模型 # 数据库模型
class ProjectDB(DBBase): class ProjectDB(DBBase):
name: str name: str
game: str
user_id: str user_id: str
members: List[str] = [] members: List[str] = []
create_date: datetime = datetime.now() create_date: datetime = datetime.now()

17
schemas/project_number.py Normal file
View File

@ -0,0 +1,17 @@
from pydantic import BaseModel
from typing import List
class ProjectnumberList(BaseModel):
main_channel: str
ditch: str
class ProjectnumberInsert(BaseModel):
game: str
ditch: List[ProjectnumberList]
name: str
class AddProjectnumber(BaseModel):
game: str
ditch: List[ProjectnumberInsert]

57
schemas/report.py Normal file
View File

@ -0,0 +1,57 @@
import json
import uuid
from datetime import datetime
from enum import Enum
from typing import List
from pydantic import BaseModel, validator, Json
from schemas import DBBase
class ReportBase(BaseModel):
name: str = None
query: str = None
project_id: str = None
class ReportCreate(ReportBase):
name: str
desc: str
project_id: str
query: dict
cat: str
class ReportEdit(BaseModel):
report_id: str
query: dict
name: str
desc: str
class ReportCopy(BaseModel):
report_ids: List[str]
dest_project_id: str
class ReportDelete(DBBase):
pass
class ReportRead(BaseModel):
project_id: str
report_id: List = []
dashboard_id: str = None
# --------------------------------------------------------------
# 数据库模型
class ReportDB(DBBase):
name: str
user_id: str
project_id: str
desc: str
query: dict
cat: str
create_date: datetime = datetime.now()

37
schemas/role.py Normal file
View File

@ -0,0 +1,37 @@
from typing import List
from pydantic import Field
from pydantic.main import BaseModel
from schemas import DBBase
class RoleBase(BaseModel):
game: str = None
name: str = None
desc: str = None
class AddRole(BaseModel):
game: str
name: str
desc: str
class AddRoleDB(DBBase, AddRole):
pass
class DelRole(BaseModel):
ids: List[str] = Field(..., description='要删除的id')
class EditRole(BaseModel):
role_id: str = Field(..., description='要编辑的id')
name: str = None
desc: str = None
class OwnerList(BaseModel):
owners: list
account_name: str

13
schemas/select_map.py Normal file
View File

@ -0,0 +1,13 @@
from typing import Any, List, Union, Dict
from pydantic import BaseModel, Field
class SelectMap(BaseModel):
game: str
attr_name: str
map_: List[Dict]
class SelectAttr(BaseModel):
attr_name: str

View File

@ -12,10 +12,41 @@ class SpaceBase(BaseModel):
name: str = None name: str = None
class Authority(str, Enum):
rw = 'rw'
r = 'r'
class Member(BaseModel):
user_id: str
authority: Authority
# 解析请求json 创建项目 # 解析请求json 创建项目
class SpaceCreate(SpaceBase): class SpaceCreate(SpaceBase):
name: str name: str
project_id: str project_id: str
members: List[Member] = []
is_all_member: bool = False
authority: Authority = 'r'
class SpaceDelete(DBBase):
pass
class SpaceDetail(BaseModel):
space_id: str
class SpaceRename(BaseModel):
space_id: str
new_name: str
class AddSpaceMembers(BaseModel):
space_id: str
members: List[Member]
# -------------------------------------------------------------- # --------------------------------------------------------------
@ -24,6 +55,5 @@ class SpaceDB(DBBase):
name: str name: str
user_id: str user_id: str
project_id: str project_id: str
rw_members: List[str] = [] members: List[Member] = []
r_members: List[str] = []
create_date: datetime = datetime.now() create_date: datetime = datetime.now()

38
schemas/sql.py Normal file
View File

@ -0,0 +1,38 @@
from typing import List, Union, Dict
from pydantic import BaseModel
from typing import Optional
class Sql(BaseModel):
sql: str
class CkQuery(BaseModel):
eventView: dict = None
events: Union[List[dict], dict] = None
report_id: str = None
ext_filter: dict = dict()
time : str = None
class Ck_seek_user(BaseModel):
user_arrt_title: str # 用户属性
user_arrt_id: str # 用户属性id
user_arrt_type: str # 用户属性type
comparator_title: str # 筛选条件
comparator_id: str # 筛选条件id
condition: str # 手动输入条件,区间用~符号隔开如0~10
start_time: str # 开始时间
end_time: str # 结束时间
pages: int = 1 # 分页的当前页
class Ck_solo_user(BaseModel):
account_id : str # #account_id
start_time: str # 开始时间 例2022-04-02
end_time: str # 结束时间
event_list: List[Dict] =None#事件名
class Times(BaseModel):
start_time: str # 开始时间 例2022-04-02 00:00:00
end_time: str # 结束时间

Some files were not shown because too many files have changed in this diff Show More