Compare commits

..

197 Commits

Author SHA1 Message Date
jasder duan f65014267b FIX 同一处理db脚本:添加判断条件,避免因表或者表字段存在而报错 2026-04-22 15:48:28 +08:00
jasder duan c9abdc2876 FIX 同一处理db脚本:添加判断条件,避免因表或者表字段存在而报错 2026-04-22 15:43:45 +08:00
jasder duan 3acd63b7c7 FIX 同一处理db脚本:添加判断条件,避免因表或者表字段存在而报错 2026-04-22 15:36:51 +08:00
jasder duan 1086b6dfba FIX 同一处理db脚本:添加判断条件,避免因表或者表字段存在而报错 2026-04-22 15:31:34 +08:00
jasder duan 1e915cbfbc FIX 同一处理db脚本:添加判断条件,避免因表或者表字段存在而报错 2026-04-22 15:28:15 +08:00
jasder duan 52872805c3 FIX 版本库中zip包下载地址问题 2025-06-23 19:02:29 +08:00
zhongdejun 7fc46e3964 同步dev_educoder_v2的网络钩子 2025-06-23 18:13:56 +08:00
zhongdejun 34676d61f9 同步dev_educoder_v2的网络钩子 2025-06-23 18:13:53 +08:00
zhongdejun 4e610f331e 同步dev_educoder_v2的网络钩子 2025-06-23 18:13:50 +08:00
zhongdejun 8facb6a46d 同步dev_educoder_v2的网络钩子 2025-06-23 18:13:46 +08:00
jasder duan f0b7de4225 FIX 仓库基本设置报错 2025-06-23 15:24:34 +08:00
jasder duan 3f5dd8d6bc FIX 设置默认分支 2025-06-23 15:19:58 +08:00
jasder duan 67a3c5a88c FIX 设置默认分支 2025-06-23 15:14:40 +08:00
jasder duan 8e463971b7 FIX 设置默认分支 2025-06-23 15:08:15 +08:00
jasder duan 0033bc190b FIX bug 2025-06-23 15:02:37 +08:00
zhongdejun cc881eb96c 同步dev_educoder_v2的网络钩子 2025-06-23 14:49:13 +08:00
zhongdejun bef327abf3 fix 创建issue时 结束时间不能小于开始日期 2025-06-20 15:28:29 +08:00
jasder duan 1145b1c467 FIX 解决版本库缺少‘仓库设置’菜单的问题 2025-04-30 17:45:50 +08:00
jasder duan cf8d4e88fd FIX 解决删除版本库报错问题 2025-04-30 17:01:54 +08:00
jasder 939dea22fc Merge pull request 'fix bug staff_id没有定义的问题' (#340) from dev_edu_local_zdj into dev_edu_local 2025-04-24 10:26:36 +08:00
zhongdejun 6b88b65ad8 fix bug staff_id没有定义的问题 2025-04-23 21:15:42 +08:00
jasder duan 7ea4da99d6 FIX 解决项目创建者缺少‘仓库设置’菜单的问题 2025-04-18 14:41:57 +08:00
jasder duan 6324fc982e FIX 创建项目报错: 同步dev_educoder_v2 版本代码 2025-04-18 14:24:52 +08:00
jasder duan 229c31146c FIX 创建项目报错: 同步dev_educoder_v2 版本代码 2025-04-18 14:18:51 +08:00
jasder duan 2e7cff4148 FIX 创建项目报错: 同步dev_educoder_v2 版本代码 2025-04-18 11:12:26 +08:00
jasder duan 9e898f2c12 FIX 创建项目报错: 同步dev_educoder_v2 版本代码 2025-04-18 11:10:57 +08:00
jasder duan 4b8751410c FIX 创建项目报错: 同步dev_educoder_v2 版本代码 2025-04-18 11:07:30 +08:00
zsx 7c413fe192 fixed 代码质量分析 菜单 2025-04-15 17:34:16 +08:00
xiaoxiaoqiong 4a8a77bae3 fixed 代码质量语言不明时-其他 2025-04-15 17:02:44 +08:00
xiaoxiaoqiong 0555cf6c8c fixed 代码质量分析 菜单 2025-04-15 17:02:41 +08:00
xiaoxiaoqiong d9016916b5 fixed 代码质量分析api utf-8 2025-04-15 17:01:03 +08:00
xiaoxiaoqiong 3ab55cb342 fixed 代码质量分析api utf-8 2025-04-15 17:01:00 +08:00
xiaoxiaoqiong ce557eff42 fixed 代码质量分析api 2025-04-15 17:00:57 +08:00
xiaoxiaoqiong bfe94bb57a fixed 代码质量分析api 2025-04-15 17:00:55 +08:00
xiaoxiaoqiong e8fb796cce fixed 代码质量分析api 2025-04-15 17:00:53 +08:00
xiaoxiaoqiong 589b8af48d fixed 代码质量分析api 2025-04-15 17:00:51 +08:00
xiaoxiaoqiong 4e1baf1b42 fixed 代码质量分析api 2025-04-15 17:00:49 +08:00
xiaoxiaoqiong 15915c9779 fixed 代码质量分析api 2025-04-15 17:00:47 +08:00
xiaoxiaoqiong 0ff0abe1af 代码质量分析api 2025-04-15 17:00:45 +08:00
xiaoxiaoqiong bacaa0aea5 fixed 接入sonar代码质量分析 2025-04-15 16:59:18 +08:00
xiaoxiaoqiong b162eaecc4 接入sonar代码质量分析 2025-04-15 16:59:17 +08:00
xiaoxiaoqiong 09fab2e962 接入sonar代码质量分析 2025-04-15 16:59:14 +08:00
zhongdejun 1374d561cc fix 首次进入协同开发弹框绑定邮箱问题 2025-03-14 19:50:13 +08:00
jasder 1beac4b921 Merge pull request 'fix 首次进入协同开发弹框绑定邮箱问题' (#335) from dev_edu_local_zdj into dev_edu_local 2025-03-14 19:48:17 +08:00
jasder 31095f5b0d Merge pull request '【苏州大学大数据】项目托管/协同开发新增申请加入审核功能(#10197)' (#334) from dev_edu_local_zdj into dev_edu_local 2025-03-13 10:04:14 +08:00
zhongdejun 2e8ca4ee9a 【苏州大学大数据】项目托管/协同开发新增申请加入审核功能(#10197) 2025-03-13 09:52:41 +08:00
jasder duan a71c834fda ADD 右上角登录按钮是否为sso单独登录按钮 2024-12-10 10:47:12 +08:00
jasder duan 1c6357b9ce FIX 主动同步头歌账号到gitea平台,防止前端进行弹框 2024-12-06 16:25:33 +08:00
jasder duan c7d99d14f8 FIX 主动同步头歌账号到gitea平台,防止前端进行弹框 2024-12-06 15:23:36 +08:00
jasder duan 5c3ebb9946 FIX 导航栏logo跳转链接问题 2023-11-21 16:26:38 +08:00
jasder duan 47c47f364d FIX 导航栏logo跳转链接问题 2023-11-21 16:21:30 +08:00
jasder duan aca5c9a162 FIX 激活流水线 激活问题 2023-11-17 22:03:08 +08:00
jasder duan c02b600547 FIX 激活流水线 repo信息不全问题 2023-11-17 21:44:22 +08:00
jasder duan 92b6b5de47 FIX 激活流水线创建webhook信息错误的问题 2023-11-17 20:36:52 +08:00
jasder duan 9a191847e4 FIX 激活流水线创建webhook信息错误的问题 2023-11-17 20:27:20 +08:00
jasder duan f7ce263d81 FIX 激活流水线创建webhook信息错误的问题 2023-11-17 20:21:07 +08:00
jasder duan bbc9f23eb5 ADD 日志 2023-11-17 20:10:36 +08:00
jasder duan 97cda03c23 FIX code review 2023-11-17 19:47:34 +08:00
jasder duan f2a073239c FIX 新建流水线创建ci repo没有生成临时秘钥问题 2023-11-17 16:40:18 +08:00
jasder duan c371b1c2e1 FIX 激活cicd时,没有绑定webhook的bug 2023-11-17 15:42:40 +08:00
jasder duan 3586f6cf20 FIX 添加日志 2023-11-16 19:47:02 +08:00
jasder duan e20102292d FIX 添加日志 2023-11-16 19:38:20 +08:00
jasder duan cead9e297b FIX 添加日志 2023-11-16 19:33:47 +08:00
xxq250 4135552311 fixed 项目分类统计数量实时统计,不统计私有 2023-09-20 17:22:11 +08:00
xxq250 d3e847e7dc fixed 项目分类统计数量实时统计,不统计私有 2023-09-20 17:08:16 +08:00
jasder duan 348bf5eb0f FIX 解决后台管理删除用户后,未删除对应项目,导致项目列表报错问题 2023-05-24 11:33:25 +08:00
“xxq250” 79ea003046 fixed 查询用户方法报错 2022-08-16 17:46:34 +08:00
xiaoxiaoqiong 7d46448121 fixed 同步gitea密码状态is_sync_pwd 2022-07-06 14:56:08 +08:00
xiaoxiaoqiong 3a16e7cf47 fixed 同步gitea密码状态 2022-07-06 14:37:58 +08:00
xiaoxiaoqiong f0798834e2 fix初始化统计数据 2022-05-11 11:27:25 +08:00
xiaoxiaoqiong 196a547fdd fix初始化统计数据 2022-05-11 10:06:13 +08:00
xiaoxiaoqiong cfc6e4f48a fix类型删除 2022-05-11 09:37:08 +08:00
xiaoxiaoqiong 435ce59320 重复建表 2022-04-15 15:58:39 +08:00
xiaoxiaoqiong 7c9a2505d9 去掉工程认证菜单 2022-04-14 18:13:10 +08:00
xiaoxiaoqiong d6b46dd093 log 2022-04-13 11:19:31 +08:00
xiaoxiaoqiong 746a5b091e log 2022-04-13 11:17:12 +08:00
xiaoxiaoqiong e3556a4aac log 2022-04-13 11:06:52 +08:00
xiaoxiaoqiong 12324d8c43 绑定email 2022-04-13 10:58:35 +08:00
xiaoxiaoqiong 63109147d1 屏蔽甘特图和质量分析 2022-04-13 10:17:59 +08:00
xiaoxiaoqiong 4de05dba70 db 2022-04-13 09:54:01 +08:00
xiaoxiaoqiong 30cd73406c db 2022-04-13 09:52:34 +08:00
xiaoxiaoqiong 1c22c8b5ea letter_avatar Gem 2022-04-13 09:47:28 +08:00
xiaoxiaoqiong 50f0c5cffa 删除多的文件 2022-04-13 09:42:30 +08:00
jasder 4494cbe3a9 fix 更新创建版本库条件 2021-07-16 10:24:27 +08:00
viletyy a1b18c07df Merge branch 'dev_educoder' into dev_edu_local 2021-07-14 11:49:33 +08:00
jasder 32ac61d889 FIX 更改默认链接 2021-07-13 16:05:26 +08:00
jasder 229885f42c ADD sonar[bug with percentage] 2021-07-13 15:53:05 +08:00
jasder 263636126b ADD sonar[bug] 2021-07-13 15:48:19 +08:00
jasder 35e11bf375 ADD sonar 2021-07-13 15:31:40 +08:00
jasder 69efc69e2d Merge branch 'dev_edu_local' of https://git.trustie.net/jasder/forgeplus into dev_edu_local 2021-07-13 10:12:28 +08:00
viletyy ace13abe92 fix: 合并请求对比代码返回合并信息 2021-07-12 18:45:35 +08:00
jasder e8da6364d8 Merge branch 'develop' into dev_educoder 2021-07-12 16:16:59 +08:00
jasder a7e20dcae2 FIX 解决用户同步问题 2021-07-09 17:53:14 +08:00
jasder 06e24a8ea4 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-07-09 16:58:04 +08:00
jasder 070df3c9dd FIX 解决私有版本库库不能访问、下载图片的问题 2021-07-09 16:57:37 +08:00
jasder 0bb45c7359 FIX 去掉密码修改功能权限控制 2021-07-08 17:47:11 +08:00
jasder 6aa7a3a3b2 ADD 工程认证导航栏 2021-07-08 17:46:37 +08:00
viletyy 7c0bc5d444 add: create project owner login 2021-07-07 15:51:05 +08:00
viletyy 334c0c2c09 add: create project owner login 2021-07-07 15:42:00 +08:00
jasder 113f8ded36 FIX [调整样式]去掉后台管理多余的功能 2021-07-07 14:44:16 +08:00
jasder 0178c8b913 FIX 去掉后台管理多余的功能 2021-07-07 14:40:33 +08:00
jasder dc07042e83 ADD sonar and gantt tab 2021-07-07 13:12:43 +08:00
jasder 6ebab1be66 FIX delete gantt、sonar tab 2021-07-07 09:13:40 +08:00
jasder 27f510e6c9 ADD loger info for create gitea user method 2021-07-07 00:07:01 +08:00
jasder d9a27b7728 ADD gantt, sonar menu for menu_list api 2021-07-06 15:49:26 +08:00
jasder 68f1d7f7f6 ADD 项目tab中添加 甘特图和质量分析/检测标识 2021-07-06 15:41:18 +08:00
jasder 7e3517d873 FIX show realname for create project 2021-07-06 11:04:25 +08:00
jasder 877ef54b24 FIX bug 2021-07-06 10:43:55 +08:00
jasder 133eed6afe FIX 合并代码、重构优化gitea 用户注册api 2021-07-05 16:19:23 +08:00
jasder eba2df5a2d Merge branch 'educoder_server' into dev_educoder 2021-07-05 15:21:23 +08:00
jasder 85a37fdbcc Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 10:05:01 +08:00
jasder 01341d4389 FIX pull、 gitea pull model relation bug 2021-06-28 10:04:48 +08:00
jasder a62b29a263 Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 10:00:10 +08:00
jasder 3a475a4674 FIX get conflict files bug with create pr api 2021-06-28 09:59:47 +08:00
jasder 0eccafcb69 Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 09:39:39 +08:00
jasder 0dbed862a7 Merge branch 'develop' into dev_educoder 2021-06-27 21:46:35 +08:00
jasder dfc998a9cc Merge branch 'develop' into dev_educoder 2021-06-18 17:47:59 +08:00
jasder 8be4bc823c Merge branch 'develop' into dev_educoder 2021-06-17 17:31:17 +08:00
jasder 7af6d8d754 FIX merge flick 2021-06-17 17:10:16 +08:00
jasder 5a8dc9d5e7 ADD merge develop branch 2021-06-17 14:09:59 +08:00
jasder ecdb79ee48 fix code bug 2021-06-11 17:40:55 +08:00
jasder 50e0ad9804 Merge branch 'dev_educoder' into educoder_server 2021-06-11 17:36:53 +08:00
jasder 953d6790d0 FIX create gitea user bug 2021-06-11 17:35:27 +08:00
jasder 136d1c1abd Merge branch 'educoder_server' of https://git.trustie.net/jasder/forgeplus into educoder_server 2021-06-11 16:51:30 +08:00
jasder e085ef374b Merge branch 'develop' into dev_educoder 2021-05-24 10:41:05 +08:00
jasder a557139ad0 Merge branch 'develop' into dev_educoder 2021-05-17 17:15:08 +08:00
jasder 6d0ac60d5a ADD phone query params for get list users api 2021-05-17 16:58:42 +08:00
jasder dda1868a72 Merge branch 'develop' into dev_educoder 2021-05-17 16:57:57 +08:00
jasder 93a1a08393 FIX merge develop branch adn fix confict 2021-05-17 16:26:51 +08:00
yystopf 4d4d8d1369 项目模块项目id重定向
项目模块项目id重定向
2021-05-03 19:50:21 +08:00
vilet.yy ab42fb7476 add: projects redirect to 2021-05-03 19:40:30 +08:00
jasder 11ac2f9c9d FIX delete log 2021-04-30 16:16:08 +08:00
jasder 8a9c3df2e5 Merge branch 'educoder_server' into dev_educoder 2021-04-30 16:09:40 +08:00
jasder e90f80255e FIX 完善项目添加成员流程 2021-04-30 16:09:02 +08:00
jasder 1b6c082480 fix merge develop 2021-04-07 11:40:29 +08:00
jasder ce1152cd4f Merge branch 'educoder_server' into dev_educoder 2021-04-02 15:54:07 +08:00
jasder c8a9094ad0 Merge branch 'develop' into dev_educoder 2021-04-02 15:53:48 +08:00
jasder 569088d846 Merge branch 'dev_educoder' into educoder_server 2021-04-01 21:00:41 +08:00
jasder 6159cda155 Merge branch 'develop' into dev_educoder 2021-04-01 21:00:22 +08:00
jasder d738ea432b Merge branch 'dev_educoder' into educoder_server 2021-04-01 15:08:32 +08:00
jasder 4a30e8c83f FIX conflict 2021-04-01 15:08:29 +08:00
jasder b3288937c9 fix merge 2021-04-01 15:07:12 +08:00
jasder 7520fa03c2 Merge branch 'develop' into dev_educoder 2021-03-28 20:05:52 +08:00
jasder f282d971e3 FIX get branches api bug and project menu list bug 2021-03-28 19:56:11 +08:00
jasder 56f01801ae Merge branch 'dev_educoder' into educoder_server 2021-03-28 19:45:24 +08:00
jasder 45e70367d5 Merge branch 'develop' into dev_educoder 2021-03-28 19:45:07 +08:00
jasder a0b376e70a Merge branch 'dev_educoder' into educoder_server 2021-03-27 23:55:11 +08:00
jasder d62d757c42 Merge branch 'develop' into dev_educoder 2021-03-27 23:54:55 +08:00
jasder 033c2607e2 Merge branch 'dev_educoder' into educoder_server 2021-03-25 21:30:46 +08:00
vilet.yy 0d6abdf7d0 fix: setting common arr 2021-03-25 20:59:24 +08:00
jasder 22c68f4c70 FIX bug 2021-03-25 20:29:36 +08:00
jasder fcd86fb01b Merge branch 'dev_educoder' into educoder_server 2021-03-25 19:58:28 +08:00
jasder faecb99136 Merge branch 'develop' into dev_educoder 2021-03-25 19:58:03 +08:00
jasder 15a002f601 Update defalut laboratory setting url 2021-03-23 16:36:35 +08:00
jasder 206d7bc159 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:58:47 +08:00
jasder 5e0006a830 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:47:13 +08:00
jasder 3abf993463 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:43:08 +08:00
jasder efbf6d627d FIX merge 2021-03-23 11:43:24 +08:00
jasder 6836907146 FIX code bug 2021-03-23 10:26:20 +08:00
jasder 6c4058cde5 Merge branch 'educoder_server' into dev_educoder 2021-03-23 10:22:12 +08:00
jasder 5a2e17abe2 FIX project and project_info aasion 2021-03-23 09:34:20 +08:00
jasder 9a8b89bcd8 FIX 解决实训作业关联项目的问题 2021-03-23 09:28:40 +08:00
jasder 4856da1607 Merge branch 'dev_educoder' into educoder_server 2021-03-22 21:02:56 +08:00
jasder 883a5f7e38 Merge branch 'develop' into dev_educoder 2021-03-22 21:02:35 +08:00
jasder 1658c1b923 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-22 17:58:29 +08:00
jasder 74f6a54d29 FIX update setting api for nav bar url 2021-03-22 17:58:15 +08:00
vilet.yy adb315521e fix 2021-03-22 14:20:03 +08:00
vilet.yy 01cad866b8 fix: laboratory 500
fix

fix
2021-03-22 14:17:03 +08:00
jasder 3447b17cdf FIX change password bug 2021-03-22 14:13:25 +08:00
jasder 0079255e98 Merge branch 'develop' into dev_educoder 2021-03-21 11:25:57 +08:00
vilet.yy 490bff5ded fix: form error 2021-03-19 16:18:09 +08:00
vilet.yy 008b8ac709 Merge branch 'develop' into dev_educoder 2021-03-19 15:07:34 +08:00
vilet.yy d0532a8f70 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-19 11:54:10 +08:00
vilet.yy a8c4cde350 add: user info sync_pwd 2021-03-19 11:50:35 +08:00
jasder 5de5974102 FIX remove email for gitea_register api 2021-03-19 10:54:56 +08:00
jasder 3d3e778078 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-19 10:31:12 +08:00
jasder f5ea8dc4a2 FIX change password api 2021-03-19 10:31:06 +08:00
vilet.yy c4b942a5f2 fix 2021-03-18 18:22:07 +08:00
jasder 13391b189a FIX conflict 2021-03-18 18:17:41 +08:00
jasder b116a72ce7 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 18:15:22 +08:00
jasder f01aec94d6 FIX 2021-03-18 18:15:08 +08:00
jasder cc97f85a1e ADD has_ansenty 2021-03-18 18:11:06 +08:00
vilet.yy 133995080a add: user info email 2021-03-18 18:11:06 +08:00
vilet.yy 27304c35dc add: user info mark 2021-03-18 18:11:06 +08:00
vilet.yy d6bf85ef73 add: user gitea register 2021-03-18 18:11:06 +08:00
jasder be9c01bf1d ADD educoder api 2021-03-18 18:11:06 +08:00
jasder edeaaa5db7 FIX sync user for educoder 2021-03-18 18:11:06 +08:00
jasder 0e41b6cc9b FIX 整理表结构 2021-03-18 18:11:03 +08:00
jasder 5f3946f187 ADD has_ansenty 2021-03-18 18:07:56 +08:00
jasder b7be00f3ec Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 17:28:20 +08:00
jasder 9b21e29426 ADD educoder api 2021-03-18 17:27:18 +08:00
vilet.yy f37fccfdb3 add: user info email 2021-03-18 17:22:59 +08:00
vilet.yy 810d2dbac6 add: user info mark 2021-03-18 16:00:05 +08:00
vilet.yy 6af97d865f Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 15:28:09 +08:00
vilet.yy efba4b2b4f add: user gitea register 2021-03-18 15:28:03 +08:00
jasder aaf1f43cc2 FIX sync user for educoder 2021-03-18 13:46:19 +08:00
jasder 823c99bd71 FIX 整理表结构 2021-03-15 16:02:59 +08:00
873 changed files with 12949 additions and 45353 deletions

2
.gitignore vendored
View File

@ -74,7 +74,6 @@ vendor/bundle/
/log
/public/admin
/mysql_data
/public/repo/
.generators
@ -86,4 +85,3 @@ redis_data/
Dockerfile
dump.rdb
.tags*
ceshi_user.xlsx

529
.merge_file_a17580 Normal file
View File

@ -0,0 +1,529 @@
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import {LocaleProvider} from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl';
import Trialapplicationysl from './modules/login/Trialapplicationysl';
import Trialapplicationreview from './modules/user/Trialapplicationreview';
import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from"./modules/user/AccountProfile";
import Trialapplication from './modules/login/Trialapplication'
import NotFoundPage from './NotFoundPage'
import Loading from './Loading'
import Loadable from 'react-loadable';
import moment from 'moment'
import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
// import './AppConfig'
import history from './history';
import {SnackbarHOC} from 'educoder'
import {initAxiosInterceptors} from './AppConfig'
// tpi需要这个来加载css
import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC';
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: {main: '#4CACFF'}, // #11cb5f This is just green.A700 as hex.
},
});
//
// const Trialapplication= Loadable({
// loader: () =>import('./modules/login/Trialapplication'),
// loading:Loading,
// })
//登入
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
const TestIndex = Loadable({
loader: () => import('./modules/test'),
loading: Loading,
})
const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'),
loading: Loading,
})
const CommentComponent = Loadable({
loader: () => import('./modules/comment/CommentContainer'),
loading: Loading,
})
const TestMaterialDesignComponent = Loadable({
loader: () => import('./modules/test/md/TestMaterialDesign'),
loading: Loading,
})
const TestCodeMirrorComponent = Loadable({
loader: () => import('./modules/test/codemirror/TestCodeMirror'),
loading: Loading,
})
const TestComponent = Loadable({
loader: () => import('./modules/test/TestRC'),
loading: Loading,
})
const TestUrlQueryComponent = Loadable({
loader: () => import('./modules/test/urlquery/TestUrlQuery'),
loading: Loading,
})
const TPMIndexComponent = Loadable({
loader: () => import('./modules/tpm/TPMIndex'),
loading: Loading,
})
const TPMShixunsIndexComponent = Loadable({
loader: () => import('./modules/tpm/shixuns/ShixunsIndex'),
loading: Loading,
})
//实训课程(原实训路径)
const ShixunPaths = Loadable({
loader: () => import('./modules/paths/Index'),
loading: Loading,
})
//在线课堂
const CoursesIndex = Loadable({
loader: () => import('./modules/courses/Index'),
loading: Loading,
})
const SearchPage = Loadable({
loader: () => import('./search/SearchPage'),
loading: Loading,
})
//教学案例
const MoopCases = Loadable({
loader: () => import('./modules/moop_cases/index'),
loading: Loading,
})
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
// loading:Loading,
// })
// //课堂普通作业&分组作业
// const CoursesWorkIndex = Loadable({
// loader: () => import('./modules/courses/busyWork/Index'),
// loading:Loading,
// })
//
// const TPMShixunchildIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
// loading: Loading,
// })
// const TPMshixunfork_listIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
// loading: Loading,
// })
const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading,
})
// trustie plus forum
// const TPForumsIndexComponent = Loadable({
// loader: () => import('./modules/tp-forums/TPForumsIndex'),
// loading: Loading,
// })
// const TestPageComponent = Loadable({
// loader: () => import('./modules/page/Index'),
// loading: Loading,
// })
//新建实训
const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
loading: Loading,
})
//实训首页
const ShixunsHome = Loadable({
loader: () => import('./modules/home/shixunsHome'),
loading: Loading,
})
const CompatibilityPageLoadable = Loadable({
loader: () => import('./modules/common/CompatibilityPage'),
loading: Loading,
})
//403页面
const Shixunauthority = Loadable({
loader: () => import('./modules/403/Shixunauthority'),
loading: Loading,
})
//404页面
const Shixunnopage = Loadable({
loader: () => import('./modules/404/Shixunnopage'),
loading: Loading,
})
//500页面
const http500 = Loadable({
loader: () => import('./modules/500/http500'),
loading: Loading,
})
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'),
loading: Loading,
})
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
//众包创新
const ProjectPackages=Loadable({
loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
loading: Loading,
})
class App extends Component {
constructor(props) {
super(props)
// this.state = {
// isRenders:false,
// }
}
componentDidMount() {
// force an update if the URL changes
history.listen(() => {
this.forceUpdate()
const $ = window.$
// https://www.trustie.net/issues/21919 可能会有问题
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props)
//
// axios.interceptors.response.use((response) => {
// // console.log("response"+response);
// if(response!=undefined)
// // console.log("response"+response.data.statu);
// if (response&&response.data.status === 407) {
// this.setState({
// isRenders: true,
// })
// }
// return response;
// }, (error) => {
// //TODO 这里如果样式变了会出现css不加载的情况
// });
}
//修改登录方法
Modifyloginvalue=()=>{
this.setState({
isRender:false,
})
}
render() {
return (
<LocaleProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
<Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl>
<Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview>
<Addcourses {...this.props} {...this.state}/>
<AccountProfile {...this.props} {...this.state}/>
{/*{*/}
{/* isRender === true?*/}
{/* <LoginDialog></LoginDialog> : ""*/}
{/*}*/}
{/*{*/}
{/* isRenders === true?*/}
{/*<Trialapplication></Trialapplication>*/}
{/*:""*/}
{/*}*/}
<Router>
<Switch>
{/*<Route path="/login" component={LoginRegisterPage}/>*/}
{/*众包创新*/}
<Route path={"/crowdsourcings"} component={ProjectPackages}/>
{/*认证*/}
<Route path="/account" component={AccountPage}/>
{/*403*/}
<Route path="/403" component={Shixunauthority}/>
<Route path="/500" component={http500}/>
{/*404*/}
<Route path="/nopage" component={Shixunnopage}/>
<Route path="/compatibility" component={CompatibilityPageLoadable}/>
<Route
path="/login" component={EducoderLogin}
/>
<Route
path="/register" component={EducoderLogin}
/>
<Route path="/users/:username"
render={
(props) => (<UsersInfo {...this.props} {...props} {...this.state} />)
}></Route>
{/*<Route*/}
{/* path="/trialapplication" component={Trialapplication}*/}
{/*/>*/}
<Route
path="/changepassword" component={EducoderLogin}
/>
<Route
path="/interesse" component={Interestpage}
/>
<Route path="/shixuns/new" component={Newshixuns}>
</Route>
<Route path="/tasks/:stageId" component={IndexWrapperComponent}/>
<Route path="/shixuns/:shixunId" component={TPMIndexComponent}>
</Route>
{/*列表页*/}
<Route path="/shixuns" component={TPMShixunsIndexComponent}/>
{/* <Route path="/shixunchild" component={TPMShixunchildIndexComponent}>
</Route>
<Route path="/fork_list" component={TPMshixunfork_listIndexComponent}>
</Route> */}
{/*<Route path="/forums" component={ForumsIndexComponent}>*/}
{/*</Route>*/}
{/*实训课程(原实训路径)*/}
<Route path="/paths" component={ShixunPaths}></Route>
<Route path="/search"
render={
(props)=>(<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
}
></Route>
{/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props}></Route>
{/* 课堂讨论 */}
{/* <Route path="/board" component = {BoardIndex} {...this.props}></Route> */}
{/* <Route path="/tpforums" component={TPForumsIndexComponent}>
</Route> */}
{/* <Route path="/myshixuns/:shixunId/stages/:stageId" component={Index}/> */}
{/* 兴趣页面*/}
{/*<Route path="/interest" component={Interestpage}/>*/}
<Route path="/comment" component={CommentComponent}/>
<Route path="/testMaterial" component={TestMaterialDesignComponent}/>
<Route path="/test" component={TestIndex}/>
<Route path="/testCodeMirror" component={TestCodeMirrorComponent}/>
<Route path="/testRCComponent" component={TestComponent}/>
<Route path="/testUrlQuery" component={TestUrlQueryComponent}/>
{/* 教学案例 */}
<Route path="/moop_cases"render={
(props) => (<MoopCases {...this.props} {...props} {...this.state} />)
}/>
{/* <Route component={NotFoundPage}/> */}
{/*列表页*/}
{/*<Route component={TPMShixunsIndexComponent}/>*/}
{/*首页*/}
<Route exact path="/" component={ShixunsHome}/>
<Route component={Shixunnopage}/>
{/*<Route component={ShixunsHome}/>*/}
</Switch>
</Router>
</MuiThemeProvider>
</LocaleProvider>
);
}
}
// moment国际化设置为中文
moment.defineLocale('zh-cn', {
months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
longDateFormat: {
LT: 'Ah点mm分',
LTS: 'Ah点m分s秒',
L: 'YYYY-MM-DD',
LL: 'YYYY年MMMD日',
LLL: 'YYYY年MMMD日Ah点mm分',
LLLL: 'YYYY年MMMD日ddddAh点mm分',
l: 'YYYY-MM-DD',
ll: 'YYYY年MMMD日',
lll: 'YYYY年MMMD日Ah点mm分',
llll: 'YYYY年MMMD日ddddAh点mm分'
},
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
meridiemHour: function (hour, meridiem) {
if (hour === 12) {
hour = 0;
}
if (meridiem === '凌晨' || meridiem === '早上' ||
meridiem === '上午') {
return hour;
} else if (meridiem === '下午' || meridiem === '晚上') {
return hour + 12;
} else {
// '中午'
return hour >= 11 ? hour : hour + 12;
}
},
meridiem: function (hour, minute, isLower) {
var hm = hour * 100 + minute;
if (hm < 600) {
return '凌晨';
} else if (hm < 900) {
return '早上';
} else if (hm < 1130) {
return '上午';
} else if (hm < 1230) {
return '中午';
} else if (hm < 1800) {
return '下午';
} else {
return '晚上';
}
},
calendar: {
sameDay: function () {
return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
},
nextDay: function () {
return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
},
lastDay: function () {
return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
},
nextWeek: function () {
var startOfWeek, prefix;
startOfWeek = moment().startOf('week');
prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]';
return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
},
lastWeek: function () {
var startOfWeek, prefix;
startOfWeek = moment().startOf('week');
prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]';
return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
},
sameElse: 'LL'
},
ordinalParse: /\d{1,2}(日|月|周)/,
ordinal: function (number, period) {
switch (period) {
case 'd':
case 'D':
case 'DDD':
return number + '日';
case 'M':
return number + '月';
case 'w':
case 'W':
return number + '周';
default:
return number;
}
},
relativeTime: {
future: '%s内',
past: '%s前',
s: '几秒',
m: '1分钟',
mm: '%d分钟',
h: '1小时',
hh: '%d小时',
d: '1天',
dd: '%d天',
M: '1个月',
MM: '%d个月',
y: '1年',
yy: '%d年'
},
week: {
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
dow: 1, // Monday is the first day of the week.
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
export default SnackbarHOC()(App);

View File

@ -1,35 +1,4 @@
# Changelog
## [v3.2.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-06-09
### ENHANCEMENTS
* ADD 集成邮件和平台站内信等通知系统
* Fix 代码库二级页面-优化文件子目录浏览功能(#50388)
* Fix 代码库二级页面-优化commit提交详情页页面排版及数据显示(#50372)
* Fix 代码库二级页面-优化commit提交信息列表页加载方式和数据排序功能(#50348)
* Fix 代码库二级页面-优化创建发行版功能(#50346)
* Fix 代码库二级页面-优化标签列表页功能(#50344)
* Fix 代码库二级页面-优化发行版本列表页功能(#50345)
* Fix 代码库二级页面-优化分支列表页功能(#50343)
* Fix 其他问题优化(#51581) (#51343) (#51108)
---
### BUGFIXES
* Fix 发行版—标签跳转链接错误(#51666)
* Fix 文件预览报错(#51660)
* Fix 标签创建时间显示错误(#51658)
* Fix 分支列表中头像显示问题(#51656)
* Fix 文本信息过长(#51630) (#51626)
* Fix 版本库中附件下载400(#51625)
* Fix loading页面优化(#51588)
* Fix 提交详情页面优化(#51577)
* Fix 修复易修复制功能(#51569)
* Fix 修复新建发行版用户信息显示错误的问题(#51665)
* Fix 修复查看文件详细信息报错的问题(#51561)
* Fix 修复提交记录中时间显示格式问题(#51526)
* Fix 组织下项目更加更新时间倒序排序(#50833)
## [v3.1.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-06-09
* ENHANCEMENTS

262
Gemfile
View File

@ -1,130 +1,132 @@
source 'https://gems.ruby-china.com'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
# gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'groupdate', '~> 4.1.0'
gem 'chartkick'
gem 'grape-entity', '~> 0.7.1'
gem 'kaminari', '~> 1.1', '>= 1.1.1'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'chinese_pinyin'
gem 'rack-cors'
gem 'redis-rails'
gem 'roo-xls'
gem 'simple_xlsx_reader'
gem 'rubyzip'
gem 'spreadsheet'
gem 'ruby-ole'
# 导出为xlsx
gem 'axlsx', '~> 3.0.0.pre'
gem 'axlsx_rails', '~> 0.5.2'
gem 'oauth2'
#导出为pdf
gem 'pdfkit'
gem 'wkhtmltopdf-binary'
# gem 'request_store'
#gem 'iconv'
# markdown 转html
gem 'redcarpet', '~> 3.4'
gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png'
gem 'acts-as-taggable-on', '~> 6.0'
# a tree structure
gem 'ancestry'
gem 'acts_as_list'
gem 'omniauth-cas'
# profiler Middleware
gem 'rack-mini-profiler'
# object-based searching
gem 'ransack'
group :development, :test do
gem 'rspec-rails', '~> 3.8'
end
group :development do
gem 'prettier'
gem 'rubocop', '~> 0.52.0'
gem 'solargraph', '~> 0.38.0'
gem 'awesome_print'
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0"
end
group :test do
gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver'
gem 'chromedriver-helper'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
#编码检测
gem 'rchardet', '~> 1.8'
# http client
gem 'faraday', '~> 0.15.4'
# view
gem 'active_decorator'
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
gem 'simple_form'
gem 'font-awesome-sass', '4.7.0'
# i18n
gem 'rails-i18n', '~> 5.1'
# job
gem 'sidekiq'
gem 'sinatra'
gem "sidekiq-cron", "~> 1.1"
# batch insert
gem 'bulk_insert'
# elasticsearch
gem 'searchkick'
gem 'aasm'
gem 'enumerize'
gem 'diffy'
gem 'deep_cloneable', '~> 3.0.0'
# oauth2
gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'
# global var
gem 'request_store'
# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar'
source 'https://gems.ruby-china.com'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
# gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'groupdate', '~> 4.1.0'
gem 'chartkick'
gem 'grape-entity', '~> 0.7.1'
gem 'kaminari', '~> 1.1', '>= 1.1.1'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'chinese_pinyin'
gem 'rack-cors'
gem 'redis-rails'
gem 'roo-xls'
gem 'simple_xlsx_reader'
gem 'rubyzip'
gem 'spreadsheet'
gem 'ruby-ole'
# 导出为xlsx
gem 'axlsx', '~> 3.0.0.pre'
gem 'axlsx_rails', '~> 0.5.2'
gem 'oauth2'
#导出为pdf
gem 'pdfkit'
gem 'wkhtmltopdf-binary'
# gem 'request_store'
#gem 'iconv'
# markdown 转html
gem 'redcarpet', '~> 3.4'
gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png'
gem 'acts-as-taggable-on', '~> 6.0'
# a tree structure
gem 'ancestry'
gem 'acts_as_list'
gem 'omniauth-cas'
# profiler Middleware
gem 'rack-mini-profiler'
# object-based searching
gem 'ransack'
group :development, :test do
gem 'rspec-rails', '~> 3.8'
end
group :development do
gem 'prettier'
gem 'rubocop', '~> 0.52.0'
gem 'solargraph', '~> 0.38.0'
gem 'awesome_print'
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0"
end
group :test do
gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver'
gem 'chromedriver-helper'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
#编码检测
gem 'rchardet', '~> 1.8'
# http client
gem 'faraday', '~> 0.15.4'
# view
gem 'active_decorator'
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
gem 'simple_form'
gem 'font-awesome-sass', '4.7.0'
# i18n
gem 'rails-i18n', '~> 5.1'
# job
gem 'sidekiq'
gem 'sinatra'
gem "sidekiq-cron", "~> 1.1"
# batch insert
gem 'bulk_insert'
# elasticsearch
gem 'searchkick'
gem 'aasm'
gem 'enumerize'
gem 'diffy'
gem 'deep_cloneable', '~> 3.0.0'
# oauth2
gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'
# global var
gem 'request_store'
# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar'
gem 'cd'

View File

@ -51,51 +51,6 @@ http://localhost:3000/api/accounts/remote_register | jq
|-- token |string|用户token|
返回值
```json
{
"status": 0,
"message": "success",
"user": {
"id": 36400,
"token": "8c87a80d9cfacc92fcb2451845104f35119eda96"
}
}
```
---
#### 独立注册接口
```
POST accounts/register
```
*示例*
```bash
curl -X POST \
-d "login=2456233122@qq.com" \
-d "password=djs_D_00001" \
-d "namespace=16895620" \
-d "code=forge" \
http://localhost:3000/api/accounts/remote_register | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
|-|-|-|-|
|login |是|string |邮箱或者手机号 |
|namespace |是|string |登录名 |
|password |是|string |密码 |
|code |是|string |验证码 |
*返回参数说明:*
|参数名|类型|说明|
|-|-|-|
|user|json object |返回数据|
|-- id |int |用户id |
|-- token |string|用户token|
返回值
```json
{
@ -383,10 +338,10 @@ http://localhost:3000/api/projects/ | jq
|-|-|-|-|
|user_id |是|int |用户id或者组织id |
|name |是|string |项目名称 |
|description ||string |项目描述 |
|description ||string |项目描述 |
|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
|project_category_id||int |项目类别id |
|project_language_id||int |项目语言id |
|project_category_id||int |项目类别id |
|project_language_id||int |项目语言id |
|ignore_id |否|int |gitignore相关id |
|license_id |否|int |开源许可证id |
|private |否|boolean|项目是否私有, true为私有false: 公开,默认为公开 |
@ -419,7 +374,9 @@ curl -X POST \
-d "user_id=36408" \
-d "clone_addr=https://gitea.com/mx8090alex/golden.git" \
-d "name=golden_mirror1" \
-d "repository_name=golden_mirror1" \
-d "description=golden_mirror" \
-d "project_category_id=1" \
-d "project_language_id=2" \
http://localhost:3000/api/projects/migrate.json | jq
```
*请求参数说明:*
@ -431,8 +388,8 @@ http://localhost:3000/api/projects/migrate.json | jq
|clone_addr |是|string |镜像项目clone地址 |
|description |否|string |项目描述 |
|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
|project_category_id||int |项目类别id |
|project_language_id||int |项目语言id |
|project_category_id||int |项目类别id |
|project_language_id||int |项目语言id |
|is_mirror |否|boolean|是否设置为镜像, true false默认为否 |
|auth_username |否|string|镜像源仓库的登录用户名 |
|auth_password |否|string|镜像源仓库的登录秘密 |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -99,38 +99,3 @@ $(document).on("turbolinks:before-cache", function () {
$(function () {
});
$(document).on('turbolinks:load', function() {
$('.logo-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
})

View File

@ -1,7 +1,7 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-courses-index-page').length > 0) {
var searchContainer = $(".course-list-form");
var searchForm = $("form.search-form",searchContainer);
let searchContainer = $(".course-list-form");
let searchForm = $("form.search-form",searchContainer);
searchContainer.on('change', '.course-homepage-show', function(){
searchForm.find('input[type="submit"]').trigger('click');

View File

@ -1,141 +0,0 @@
/*
* @Description: Do not edit
* @Date: 2021-08-31 11:16:45
* @LastEditors: viletyy
* @Author: viletyy
* @LastEditTime: 2021-08-31 14:19:46
* @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
*/
$(document).on('turbolinks:load', function(){
var showSuccessNotify = function() {
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
// close user
$('.project-list-container').on('click', '.recommend-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unrecommend-action');
var $editAction = $closeAction.siblings('.edit-recommend-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认将该项目设置为推荐项目吗?',
ok: function(){
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
recommend: true,
recommend_index: 1
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$editAction.show();
$(".project-item-"+keywordID).children('td').eq(5).text("√")
}
});
}
});
});
// unclose user
$('.project-list-container').on('click', '.unrecommend-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.recommend-action');
var $editAction = $closeAction.siblings('.edit-recommend-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认取消该推荐项目吗?',
ok: function () {
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
recommend: false,
recommend_index: 0
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$editAction.hide();
$(".project-item-"+keywordID).children('td').eq(5).text("")
}
});
}
})
});
// close user
$('.project-list-container').on('click', '.pinned-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unpinned-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认将该项目设置为精选项目吗?',
ok: function(){
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
is_pinned: true,
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$(".project-item-"+keywordID).children('td').eq(4).text("√")
}
});
}
});
});
// unclose user
$('.project-list-container').on('click', '.unpinned-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.pinned-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认取消该精选项目吗?',
ok: function () {
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
is_pinned: false,
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$(".project-item-"+keywordID).children('td').eq(4).text("")
}
});
}
})
});
})

View File

@ -1,76 +0,0 @@
/*
* @Description: Do not edit
* @Date: 2021-08-31 11:16:45
* @LastEditors: viletyy
* @Author: viletyy
* @LastEditTime: 2021-08-31 14:19:46
* @FilePath: /forgeplus/app/assets/javascripts/admins/reversed_keywords/index.js
*/
$(document).on('turbolinks:load', function(){
var showSuccessNotify = function() {
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
// close user
$('.reversed-keyword-list-container').on('click', '.close-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unclose-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认关闭限制吗?',
ok: function(){
$.ajax({
url: '/admins/reversed_keywords/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
reversed_keyword: {
closed: true
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$(".reversed-keyword-item-"+keywordID).children('td').eq(3).text("")
}
});
}
});
});
// unclose user
$('.reversed-keyword-list-container').on('click', '.unclose-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.close-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认开启限制吗?',
ok: function () {
$.ajax({
url: '/admins/reversed_keywords/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
reversed_keyword: {
closed: false
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$(".reversed-keyword-item-"+keywordID).children('td').eq(3).text("√")
}
});
}
})
});
})

View File

@ -1,15 +1,7 @@
/*
* @Description: Do not edit
* @Date: 2021-07-16 11:58:16
* @LastEditors: viletyy
* @Author: viletyy
* @LastEditTime: 2021-08-31 14:48:59
* @FilePath: /forgeplus/app/assets/javascripts/admins/shixun_settings/index.js
*/
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
var searchContainer = $(".shixun-settings-list-form");
var searchForm = $("form.search-form",searchContainer);
let searchContainer = $(".shixun-settings-list-form");
let searchForm = $("form.search-form",searchContainer);
searchContainer.on('change', '.shixun-settings-select', function(){
searchForm.find('input[type="submit"]').trigger('click');

View File

@ -1,76 +0,0 @@
/*
* @Description: Do not edit
* @Date: 2021-08-31 11:16:45
* @LastEditors: viletyy
* @Author: viletyy
* @LastEditTime: 2021-08-31 14:19:46
* @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
*/
$(document).on('turbolinks:load', function(){
var showSuccessNotify = function() {
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
// close user
$('.system-notification-list-container').on('click', '.close-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unclose-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认取消置顶吗?',
ok: function(){
$.ajax({
url: '/admins/system_notifications/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
system_notification: {
is_top: false
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$(".system-notification-item-"+keywordID).children('td').eq(3).text("")
}
});
}
});
});
// unclose user
$('.system-notification-list-container').on('click', '.unclose-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.close-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认置顶吗?',
ok: function () {
$.ajax({
url: '/admins/system_notifications/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
system_notification: {
is_top: true
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$(".system-notification-item-"+keywordID).children('td').eq(3).text("√")
}
});
}
})
});
})

View File

@ -58,149 +58,3 @@ input.form-control {
position: absolute;
}
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #e9ecef;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #e9ecef;
border: 1px solid #ced4da;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #495057;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #495057;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 0.8rem;
}
&-title {
color: #23272B;
font-size: 1rem;
}
}
.attachment-item {
display: flex;
&-img {
display: block;
width: 160px;
height: 160px;
background: #e9ecef;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 160px;
height: 160px;
background: #e9ecef;
border: 1px solid #ced4da;
&::before {
content: '';
position: absolute;
top: 54px;
left: 78px;
width: 2px;
height: 52px;
background: #495057;
}
&::after {
content: '';
position: absolute;
top: 78px;
left: 54px;
width: 52px;
height: 2px;
background: #495057;
}
}
&-left {
position: relative;
width: 160px;
height: 160px;
&.has-img {
.attachment-item-upload {
display: none;
}
&:hover {
.attachment-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
padding-top: 100px;
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 0.8rem;
}
&-title {
color: #23272B;
font-size: 1rem;
}
}

View File

@ -1,5 +1,4 @@
class AccountsController < ApplicationController
include ApplicationHelper
#skip_before_action :check_account, :only => [:logout]
@ -7,10 +6,23 @@ class AccountsController < ApplicationController
render json: session
end
# 为了同步平台上未注册gitea的用户
def gitea_register
user = User.find_by(login: sync_gitea_params[:login])
Users::SyncGiteaForm.new(sync_gitea_params.merge(user: user)).validate!
return render_error("该用户已同步协作平台") if user.gitea_token.present? && user.gitea_uid.present?
result = create_gitea_user!(user, sync_gitea_params[:login], sync_gitea_params[:email], sync_gitea_params[:password])
result[:user] ? render_ok : render_error(result[:message])
rescue Exception => e
uid_logger_error(e.message)
tip_exception(-1, e.message)
end
# 其他平台同步注册的用户
def remote_register
username = params[:username]&.gsub(/\s+/, "")
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
email = params[:email]&.gsub(/\s+/, "")
password = params[:password]
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
@ -110,46 +122,60 @@ class AccountsController < ApplicationController
# 用户注册
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
# params[:login] 邮箱或者手机号
# params[:namespace] 登录名
# params[:code] 验证码
# code_type 1注册手机验证码 8邮箱注册验证码
# 本地forge注册入口需要重新更改逻辑
# 本地forge注册入口
def register
# type只可能是1或者8
user = nil
begin
Register::Form.new(register_params).validate!
# 查询验证码是否正确;type只可能是1或者8
type = phone_mail_type(params[:login].strip)
# code = params[:code].strip
user = Users::RegisterService.call(register_params)
password = register_params[:password].strip
if type == 1
uid_logger("start register by phone: type is #{type}")
pre = 'p'
email = nil
phone = params[:login]
# verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
# TODO: 暂时限定邮箱注册
return normal_status(-1, '只支持邮箱注册')
else
uid_logger("start register by email: type is #{type}")
pre = 'm'
email = params[:login]
phone = nil
return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login])
return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL
# verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
end
# uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
# check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
# todo 上线前请删除万能验证码"513231"
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD
# gitea用户注册, email, username, password
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
code = generate_identifier User, 8, pre
login = pre + code
@user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User")
@user.password = params[:password]
# 现在因为是验证码,所以在注册的时候就可以激活
@user.activate
# 必须要用save操作密码的保存是在users中
interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]})
if interactor.success?
gitea_user = interactor.result
result = Gitea::User::GenerateTokenService.call(user.login, password)
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
if user.save!
UserExtension.create!(user_id: user.id)
successful_authentication(user)
render_ok
result = Gitea::User::GenerateTokenService.new(login, params[:password]).call
@user.gitea_token = result['sha1']
@user.gitea_uid = gitea_user[:body]['id']
if @user.save!
UserExtension.create!(user_id: @user.id)
successful_authentication(@user)
normal_status("注册成功")
end
else
tip_exception(-1, interactor.error)
end
rescue Register::BaseForm::EmailError => e
render_error(-2, e.message)
rescue Register::BaseForm::LoginError => e
render_error(-3, e.message)
rescue Register::BaseForm::PhoneError => e
render_error(-4, e.message)
rescue Register::BaseForm::PasswordFormatError => e
render_error(-5, e.message)
rescue Register::BaseForm::VerifiCodeError => e
render_error(-6, e.message)
rescue Exception => e
Gitea::User::DeleteService.call(user.login) unless user.nil?
uid_logger_error(e.message)
tip_exception(-1, e.message)
end
@ -284,7 +310,7 @@ class AccountsController < ApplicationController
# 发送验证码
# params[:login] 手机号或者邮箱号
# params[:type]为事件通知类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# params[:type]为事件通知类型 1用户注册注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效
def get_verification_code
@ -298,22 +324,19 @@ class AccountsController < ApplicationController
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
tip_exception(501, "请求不合理") if sign != params[:smscode]
logger.info "########### 验证码:#{verification_code}"
logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ")
# 记录验证码
check_verification_code(verification_code, send_type, value)
render_ok
sucess_status
end
# check user's login or email or phone is used
# params[:value] 手机号或者邮箱号或者登录名
# params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号)
def check
Register::CheckColumnsForm.new(check_params).validate!
render_ok
# 1 手机类型0 邮箱类型
# 注意新版的login是自动名生成的
def phone_mail_type value
value =~ /^1\d{10}$/ ? 1 : 0
end
private
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
@ -352,6 +375,10 @@ class AccountsController < ApplicationController
{ login: pre + code, email: email, phone: phone }
end
def sync_gitea_params
params.permit(:login, :email, :password)
end
def user_params
params.require(:user).permit(:login, :email, :phone)
end
@ -359,13 +386,4 @@ class AccountsController < ApplicationController
def account_params
params.require(:account).permit(:login, :password)
end
def check_params
params.permit(:type, :value)
end
def register_params
params.permit(:login, :namespace, :password, :code)
end
end

View File

@ -1,55 +0,0 @@
class Admins::EduSettingsController < Admins::BaseController
before_action :find_setting, only: [:edit,:update, :destroy]
def index
default_sort('id', 'desc')
edu_settings = Admins::EduSettingQuery.call(params)
@edu_settings = paginate edu_settings
end
def new
@edu_setting = EduSetting.new
end
def edit
end
def create
@edu_setting = EduSetting.new(edu_setting_params)
if @edu_setting.save
redirect_to admins_edu_settings_path
flash[:success] = '创建成功'
else
redirect_to admins_edu_settings_path
flash[:danger] = @edu_setting.errors.full_messages.join(",")
end
end
def update
if @edu_setting.update!(edu_setting_params)
flash[:success] = '更新成功'
else
flash[:danger] = @edu_setting.errors.full_messages.join(",")
end
redirect_to admins_edu_settings_path
end
def destroy
if @edu_setting.destroy!
flash[:success] = '删除成功'
else
lash[:danger] = '删除失败'
end
redirect_to admins_edu_settings_path
end
private
def find_setting
@edu_setting ||= EduSetting.find(params[:id])
end
def edu_setting_params
params.require(:edu_setting).permit(:name, :value, :description)
end
end

View File

@ -1,44 +0,0 @@
class Admins::MessageTemplatesController < Admins::BaseController
before_action :get_template, only: [:edit, :update, :destroy]
def index
message_templates = MessageTemplate.group(:type).count.keys
@message_templates = kaminari_array_paginate(message_templates)
end
def edit
end
def update
if @message_template.update_attributes(message_template_params)
redirect_to admins_message_templates_path
flash[:success] = '消息模版更新成功'
else
redirect_to admins_message_templates_path
flash[:danger] = @message_template.errors.full_messages.join(",")
end
end
def init_data
if MessageTemplate.build_init_data
redirect_to admins_message_templates_path
flash[:success] = '消息模版初始化成功'
else
redirect_to admins_message_templates_path
flash[:danger] = '消息模版初始化失败'
end
end
private
def message_template_params
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
end
def get_template
@message_template = MessageTemplate.find_by(id: params[:id])
unless @message_template.present?
redirect_to admins_message_templates_path
flash[:danger] = "消息模版不存在"
end
end
end

View File

@ -22,7 +22,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
max_position_items = ProjectCategory.select(:id, :position).pluck(:position).reject!(&:blank?)
max_position = max_position_items.present? ? max_position_items.max.to_i : 0
@project_category = ProjectCategory.new(name: @name,position: max_position, pinned_index: params[:project_category][:pinned_index].to_i)
@project_category = ProjectCategory.new(name: @name,position: max_position)
if @project_category.save
redirect_to admins_project_categories_path
flash[:success] = '创建成功'
@ -33,18 +33,17 @@ class Admins::ProjectCategoriesController < Admins::BaseController
end
def update
if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i})
save_image_file(params[:logo], 'logo')
if @project_category.update_attribute(:name, @name)
redirect_to admins_project_categories_path
flash[:success] = '更新成功'
else
redirect_to admins_project_categories_path
flash[:danger] = '更新失败'
flash[:success] = '更新失败'
end
end
def destroy
if @project_category.destroy
if @project_category.destroy
redirect_to admins_project_categories_path
flash[:success] = "删除成功"
else
@ -81,12 +80,4 @@ class Admins::ProjectCategoriesController < Admins::BaseController
flash[:danger] = '分类已存在'
end
end
def save_image_file(file, type)
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
file_path = Util::FileManage.source_disk_filename(@project_category, type)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(file, file_path)
end
end

View File

@ -1,5 +1,4 @@
class Admins::ProjectsController < Admins::BaseController
before_action :find_project, only: [:edit, :update]
def index
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
@ -9,26 +8,6 @@ class Admins::ProjectsController < Admins::BaseController
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
end
def edit ;end
def update
respond_to do |format|
if @project.update_attributes(project_update_params)
format.html do
redirect_to admins_projects_path
flash[:sucess] = "更新成功"
end
format.js {render_ok}
else
format.html do
redirect_to admins_projects_path
flash[:danger] = "更新失败"
end
format.js {render_js_error}
end
end
end
def destroy
project = Project.find_by!(id: params[:id])
ActiveRecord::Base.transaction do
@ -42,13 +21,4 @@ class Admins::ProjectsController < Admins::BaseController
redirect_to admins_projects_path
flash[:danger] = "删除失败"
end
private
def find_project
@project = Project.find_by_id(params[:id])
end
def project_update_params
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
end
end

View File

@ -1,84 +0,0 @@
class Admins::ReversedKeywordsController < Admins::BaseController
before_action :get_keyword, only: [:edit,:update, :destroy]
# before_action :validate_identifer, only: [:create, :update]
def index
sort_by = ReversedKeyword.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
q = ReversedKeyword.ransack(identifier_cont: params[:search])
keywords = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
@keywords = paginate(keywords)
end
def new
@keyword = ReversedKeyword.new
end
def edit
end
def create
@keyword = ReversedKeyword.new(keyword_params)
if @keyword.save
redirect_to admins_reversed_keywords_path
flash[:success] = '系统保留关键词创建成功'
else
redirect_to admins_reversed_keywords_path
flash[:danger] = @keyword.errors.full_messages.join(",")
end
end
def update
respond_to do |format|
if @keyword.update_attributes(keyword_params)
format.html do
redirect_to admins_reversed_keywords_path
flash[:success] = '系统保留关键词更新成功'
end
format.js {render_ok}
else
format.html do
redirect_to admins_reversed_keywords_path
flash[:danger] = @keyword.errors.full_messages.join(",")
end
format.js {render_js_error}
end
end
end
def destroy
if @keyword.destroy
redirect_to admins_reversed_keywords_path
flash[:success] = "系统保留关键词删除成功"
else
redirect_to admins_reversed_keywords_path
flash[:danger] = "系统保留关键词删除失败"
end
end
private
def keyword_params
params.require(:reversed_keyword).permit!
end
def get_keyword
@keyword = ReversedKeyword.find_by(id: params[:id])
unless @keyword.present?
redirect_to admins_reversed_keywords_path
flash[:danger] = "系统保留关键词不存在"
end
end
def validate_identifer
identifer = keyword_params[:identifier].to_s.downcase
if identifer.blank?
redirect_to admins_reversed_keywords_path
flash[:danger] = '系统保留关键词标识不能为空'
elsif ProjectLanguage.exists?(name: identifer)
redirect_to admins_reversed_keywords_path
flash[:danger] = '系统保留关键词已存在'
end
end
end

View File

@ -1,56 +0,0 @@
class Admins::SitesController < Admins::BaseController
before_action :find_site, only: [:edit,:update, :destroy]
def index
default_sort('id', 'desc')
sites = Admins::SiteQuery.call(params)
@sites = paginate sites
end
def new
@site = Site.new
end
def edit
end
def create
@site = Site.new(site_params)
if @site.save
redirect_to admins_sites_path
flash[:success] = '创建成功'
else
redirect_to admins_sites_path
flash[:danger] = @site.errors.full_messages.join(",")
end
end
def update
if @site.update!(site_params)
flash[:success] = '更新成功'
else
flash[:danger] = @site.errors.full_messages.join(",")
end
redirect_to admins_sites_path
end
def destroy
if @site.destroy!
flash[:success] = '删除成功'
else
lash[:danger] = '删除失败'
end
redirect_to admins_sites_path
end
private
def find_site
@site ||= Site.find(params[:id])
end
def site_params
params.require(:site).permit(:name, :url, :key, :site_type)
end
end

View File

@ -1,75 +0,0 @@
class Admins::SystemNotificationsController < Admins::BaseController
before_action :get_notification, only: [:history, :edit,:update, :destroy]
# before_action :validate_identifer, only: [:create, :update]
def index
sort_by = SystemNotification.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
q = SystemNotification.ransack(subject_cont: params[:search])
notifications = q.result(distinct: true).reorder("#{sort_by} #{sort_direction},created_at desc")
@notifications = paginate(notifications)
end
def history
@users = @notification.users
end
def new
@notification = SystemNotification.new
end
def edit
end
def create
@notification = SystemNotification.new(notification_params)
if @notification.save
redirect_to admins_system_notifications_path
flash[:success] = '系统消息创建成功'
else
redirect_to admins_system_notifications_path
flash[:danger] = @notification.errors.full_messages.join(",")
end
end
def update
respond_to do |format|
if @notification.update_attributes(notification_params)
format.html do
redirect_to admins_system_notifications_path
flash[:success] = '系统消息更新成功'
end
format.js {render_ok}
else
format.html do
redirect_to admins_system_notifications_path
flash[:danger] = @notification.errors.full_messages.join(",")
end
format.js {render_js_error}
end
end
end
def destroy
if @notification.destroy
redirect_to admins_system_notifications_path
flash[:success] = "系统消息删除成功"
else
redirect_to admins_system_notifications_path
flash[:danger] = "系统消息删除失败"
end
end
private
def notification_params
params.require(:system_notification).permit!
end
def get_notification
@notification = SystemNotification.find_by(id: params[:id])
unless @notification.present?
redirect_to admins_system_notifications_path
flash[:danger] = "系统消息不存在"
end
end
end

View File

@ -1,6 +1,4 @@
class Admins::UsersController < Admins::BaseController
before_action :finder_user, except: [:index]
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
@ -10,9 +8,12 @@ class Admins::UsersController < Admins::BaseController
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
Admins::UpdateUserService.call(@user, update_params)
flash[:success] = '保存成功'
redirect_to edit_admins_user_path(@user)
@ -25,47 +26,43 @@ class Admins::UsersController < Admins::BaseController
end
def destroy
@user.destroy!
Gitea::User::DeleteService.call(@user.login)
User.find(params[:id]).destroy!
render_delete_success
end
def lock
@user.lock!
User.find(params[:id]).lock!
render_ok
end
def unlock
@user.activate!
User.find(params[:id]).activate!
render_ok
end
def reward_grade
user = User.find(params[:user_id])
return render_unprocessable_entity('金币数量必须大于0') if params[:grade].to_i <= 0
RewardGradeService.call(@user, container_id: @user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
RewardGradeService.call(user, container_id: user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
render_ok(grade: @user.grade)
render_ok(grade: user.grade)
end
def reset_login_times
@user.reset_login_times!
User.find(params[:id]).reset_login_times!
render_ok
end
private
def finder_user
@user = User.find(params[:id])
end
def update_params
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
mail phone location location_city school_id department_id admin business is_test
password professional_certification authentication login])
password professional_certification authentication])
end
end

View File

@ -16,6 +16,7 @@ class ApplicationController < ActionController::Base
before_action :check_sign
before_action :user_setup
#before_action :check_account
before_action :check_gitea_account
# TODO
# check sql query time
@ -28,7 +29,7 @@ class ApplicationController < ActionController::Base
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
OPENKEY = "79e33abd4b6588941ab7622aed1e67e8"
helper_method :current_user, :base_url
helper_method :current_user, :base_url, :judge_file_type_by_suffix
# 所有请求必须合法签名
def check_sign
@ -70,11 +71,49 @@ class ApplicationController < ActionController::Base
(current_user.professional_certification && (ue.teacher? || ue.professional?))
end
def shixun_marker
unless current_user.is_shixun_marker? || current_user.admin_or_business?
tip_exception(403, "..")
end
end
# 实训的访问权限
def shixun_access_allowed
if !current_user.shixun_permission(@shixun)
tip_exception(403, "..")
end
end
def admin_or_business?
User.current.admin? || User.current.business?
end
# 访问课堂时没权限直接弹加入课堂的弹框 409
def user_course_identity
@user_course_identity = current_user.course_identity(@course)
if @user_course_identity > Course::STUDENT && @course.is_public == 0
tip_exception(401, "..") unless User.current.logged?
check_account
tip_exception(@course.excellent ? 410 : 409, "您没有权限进入")
end
if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id
# 实名认证和职业认证的身份判断
tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication &&
@course.professional_certification && (!current_user.authentication && !current_user.professional_certification)
tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication
tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification
end
uid_logger("###############user_course_identity:#{@user_course_identity}")
end
# 题库的访问权限
def bank_visit_auth
tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? ||
(current_user.certification_teacher? && @bank.is_public)
end
# 判断用户的邮箱或者手机是否可用
# params[:type] 1: 注册2忘记密码3绑定
def check_mail_and_phone_valid login, type
@ -82,16 +121,16 @@ class ApplicationController < ActionController::Base
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
tip_exception(-2, "请输入正确的手机号或邮箱")
end
user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
if user_exist && type.to_i == 1
# 考虑到安全参数问题多一次查询去掉Union
user = User.where(phone: login).first || User.where(mail: login).first
if type.to_i == 1 && !user.nil?
tip_exception(-2, "该手机号码或邮箱已被注册")
elsif type.to_i == 2 && !user_exist
elsif type.to_i == 2 && user.nil?
tip_exception(-2, "该手机号码或邮箱未注册")
elsif type.to_i == 3 && user_exist
elsif type.to_i == 3 && user.present?
tip_exception(-2, "该手机号码或邮箱已绑定")
end
render_ok
sucess_status
end
# 发送及记录激活码
@ -102,7 +141,7 @@ class ApplicationController < ActionController::Base
when 1, 2, 4, 9
# 手机类型的发送
sigle_para = {phone: value}
status = Gitlink::Sms.send(mobile: value, code: code)
status = Educoder::Sms.send(mobile: value, code: code)
tip_exception(-2, code_msg(status)) if status != 0
when 8, 3, 5
# 邮箱类型的发送
@ -148,6 +187,26 @@ class ApplicationController < ActionController::Base
end
end
def find_course
return normal_status(2, '缺少course_id参数') if params[:course_id].blank?
@course = Course.find(params[:course_id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
rescue Exception => e
tip_exception(e.message)
end
def course_manager
return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR
end
def find_board
return normal_status(2, "缺少board_id参数") if params[:board_id].blank?
@board = Board.find(params[:board_id])
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def validate_type(object_type)
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
end
@ -157,6 +216,21 @@ class ApplicationController < ActionController::Base
@page_size = params[:page_size] || 15
end
# 课堂教师权限
def teacher_allowed
logger.info("#####identity: #{current_user.course_identity(@course)}")
unless current_user.course_identity(@course) < Course::STUDENT
normal_status(403, "")
end
end
# 课堂教师、课堂管理员、超级管理员的权限(不包含助教)
def teacher_or_admin_allowed
unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR
normal_status(403, "")
end
end
def require_admin
normal_status(403, "") unless User.current.admin?
end
@ -173,17 +247,9 @@ class ApplicationController < ActionController::Base
tip_exception(401, "请登录后再操作") unless User.current.logged?
end
def require_profile_completed
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
end
def require_user_profile_completed(user)
tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
end
# 异常提醒
def tip_exception(status = -1, message)
raise Gitlink::TipException.new(status, message)
raise Educoder::TipException.new(status, message)
end
def missing_template
@ -192,7 +258,7 @@ class ApplicationController < ActionController::Base
# 弹框提醒
def tip_show_exception(status = -2, message)
raise Gitlink::TipException.new(status, message)
raise Educoder::TipException.new(status, message)
end
def normal_status(status = 0, message)
@ -207,12 +273,48 @@ class ApplicationController < ActionController::Base
# 资料是否完善
def check_account
if !current_user. profile_is_completed?
if !current_user.profile_completed?
#info_url = '/account/profile'
tip_exception(402, nil)
end
end
# TODO
# 临时处理弹框同步gitea账号问题
def check_gitea_account
return unless current_user.logged?
if !current_user.has_gitea_user? || (current_user.has_gitea_user? && !current_user.is_sync_pwd)
begin
email = current_user.mail
if email.blank?
user_extension = current_user.user_extension
email_identifier =
if user_extension
if user_extension.identity == 'student'
current_user.student_id
elsif user_extension.identity == 'teacher'
current_user.staff_id
else
nil
end
else
nil
end
email = email_identifier.blank? ? "#{current_user.login}@qq.com" : "#{email_identifier}@qq.com"
current_user.update_column(:mail, email)
end
create_gitea_user!(current_user, current_user.login, email, 'zq123456')
rescue => e
Rails.logger.info "@@主动检测并同步gitea账号错误: #{e.message}"
return
end
end
end
# 系统全局认证(暂时隐藏试用申请的判断)
def check_auth
# day_cer = UserDayCertification.find_by(user_id: current_user.id)
@ -272,18 +374,18 @@ class ApplicationController < ActionController::Base
# 测试版前端需求
logger.info("subdomain:#{request.subdomain}")
# if request.subdomain != "www"
# if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
# User.current = User.find 81403
# elsif params[:debug] == 'student'
# User.current = User.find 8686
# elsif params[:debug] == 'admin'
# logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
# user = User.find 36480
# User.current = user
# cookies.signed[:user_id] = user.id
# end
# end
if request.subdomain != "www"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
user = User.find 36480
User.current = user
cookies.signed[:user_id] = user.id
end
end
# User.current = User.find 81403
end
@ -373,7 +475,7 @@ class ApplicationController < ActionController::Base
JSON.parse(res)
rescue Exception => e
uid_logger_error("--uri_exec: exception #{e.message}")
raise Gitlink::TipException.new("实训平台繁忙繁忙等级84")
raise Educoder::TipException.new("实训平台繁忙繁忙等级84")
end
end
@ -392,7 +494,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Gitlink::TipException.new(message)
raise Educoder::TipException.new(message)
end
end
@ -416,7 +518,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Gitlink::TipException.new("服务器繁忙")
raise Educoder::TipException.new("服务器繁忙")
end
end
@ -588,8 +690,8 @@ class ApplicationController < ActionController::Base
# 获取Oauth Client
def get_client(site)
client_id = Rails.configuration.Gitlink['client_id']
client_secret = Rails.configuration.Gitlink['client_secret']
client_id = Rails.configuration.educoder['client_id']
client_secret = Rails.configuration.educoder['client_secret']
OAuth2::Client.new(client_id, client_secret, site: site)
end
@ -689,10 +791,10 @@ class ApplicationController < ActionController::Base
if @project and current_user.can_read_project?(@project)
logger.info "########### has project and can read project"
@project
# elsif @project && current_user.is_a?(AnonymousUser)
# logger.info "###########This is AnonymousUser"
# @project = nil if !@project.is_public?
# render_forbidden and return
elsif @project && current_user.is_a?(AnonymousUser)
logger.info "###########This is AnonymousUser"
@project = nil if !@project.is_public?
render_forbidden and return
else
logger.info "###########project not found"
@project = nil
@ -710,8 +812,7 @@ class ApplicationController < ActionController::Base
end
def convert_image!
@image = params[:image]
@image = @image.nil? && params[:user].present? ? params[:user][:image] : @image
@image = params[:image] || user_params[:image]
return unless @image.present?
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
if @image.class == ActionDispatch::Http::UploadedFile
@ -782,8 +883,28 @@ class ApplicationController < ActionController::Base
HotSearchKeyword.add(keyword)
end
def find_atme_receivers
@atme_receivers = User.where(login: params[:receivers_login])
end
# 根据文件后缀判断文件类型,默认使用文本打开渲染
def judge_file_type_by_suffix filename
return "other" if filename.blank?
suffix = File.basename(filename).split(".").last
return "other" if suffix.blank?
case suffix.downcase
when "py", "h", "c", "cpp", "cc", "java", "php", "html", "css", "scss", "go", "r", "graphql", "swift", "xml", "yaml", "json", "lua",
"scheme", "less", "ini", "coffee", "litcoffee", "js", "cs", "kt", "md", "sql", "m", "mm", "pas", "perl", "perl", "ejs",
"pl", "rb", "rs", "rust", "sh", "makefile", "circ", "readme", "yml", "sml", "thy", "conf", "txt", "gitignore", "in", "cu",
"gemfile", "scala", "m", "net", "l", "v", "config", "properties", "log", "htm", "cnf", "hex", "bat", "asm", "hex", "bash",
"ts", "tsx", "sass", "jsx", "jsp", "gitkeep", "sv", "hql", "y", "jj", "pls", "sol", "ignore", "ctrl", "vue", "tex", "bib",
"cls", "bst", "log", "toc", "sty", "g4", "sy", "cfg", "s", "ll", "mml", "hpp","api", "vhdl", "lex" then "txt"
when "jpg", "jpeg", "png", "gif", "webp", "bmp" then "image"
when "avi", "mp4", "mov" then "video"
when "mp3", "wav", "ogg" then "audio"
when "pptm", "pptx", "ppt", "pot", "pps", "ppa", "potx", "ppsx", "ppam", "pptm", "potm", "ppsm", "doc", "docx",
"dot", "dotx", "docm", "dotm", "xls", "xlsx", "xlt", "xla", "xltx", "xlsm", "xltm", "xlam", "xlsb" then "office"
when "tex" then "latex"
when "pdf" then "pdf"
else
"other"
end
end
end

View File

@ -2,12 +2,58 @@ class AppliedProjectsController < ApplicationController
before_action :require_login
def create
@applied_project = Projects::ApplyJoinService.call(current_user, applied_params)
if @applied_project.class.to_s != "AppliedProject"
render_ok({data: @applied_project})
end
rescue Projects::ApplyJoinService::Error => ex
render_error(ex.message)
end
#审核列表
def index
project = Project.find_by(identifier: params[:project_identifier])
tip_exception(-1, "该项目不存在~") if project.blank?
status = params[:status] || 1
if status.to_i == 1
status = ["common"]
elsif status.to_i == 2
status = ["accepted", "refused"]
end
applied_projects = project.applied_projects
if status.present?
applied_projects = applied_projects.where(status: status)
end
keyword = params[:keyword].to_s.strip
if keyword.present?
applied_projects = applied_projects.joins(user: :user_extension).where("CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.phone LIKE :keyword", keyword: "%#{params[:keyword].to_s.strip}%")
end
@count = applied_projects.size
@applied_projects = paginate applied_projects.order(updated_at: :DESC)
end
#审核
def verify
tip_exception(-1, "参数值有误") if !["agree","reject"].include?(params[:verify_status])
applied_project = AppliedProject.find_by(id: params[:id])
tip_exception(-1, '该数据不存在') if applied_project.blank?
tip_exception(-1, '该数据已审核,请勿重复操作') if applied_project.status != "common"
begin
ActiveRecord::Base.transaction do
if params[:verify_status] == "agree"
Projects::VerifyService.new(applied_project, current_user, params).agree
elsif params[:verify_status] == "reject"
Projects::VerifyService.new(applied_project, current_user, params).reject
end
render_ok
end
rescue => e
uid_logger_error(e.message)
tip_exception("审核失败:#{e.message}")
end
end
private
def applied_params
params.require(:applied_project).permit(:code, :role)
params.require(:applied_project).permit(:code, :role, :alert_remarks, :remarks, :attachment_id)
end
end

View File

@ -32,17 +32,8 @@ class AttachmentsController < ApplicationController
def get_file
normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
if url.starts_with?(base_url)
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
response = Faraday.get(request_url)
filename = url.to_s.split("/").pop()
else
response = Faraday.get(url)
filename = params[:download_url].to_s.split("/").pop()
end
response = Faraday.get(url)
filename = params[:download_url].to_s.split("/").pop()
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
end
@ -196,7 +187,7 @@ class AttachmentsController < ApplicationController
end
def file_save_to_ucloud(path, file, content_type)
ufile = Gitlink::Ufile.new(
ufile = Educoder::Ufile.new(
ucloud_public_key: edu_setting('public_key'),
ucloud_private_key: edu_setting('private_key'),
ucloud_public_read: true,

View File

@ -45,8 +45,10 @@ class Ci::CloudAccountsController < Ci::BaseController
end
result = bind_hook!(current_user, @cloud_account, @repo)
Rails.logger.info "########## result: #{result}"
@project.update_columns(open_devops: true, gitea_webhook_id: result['id'])
@cloud_account.update_column(:ci_user_id, @ci_user.user_id)
Rails.logger.info "########## @cloud_account: #{@cloud_account.to_json} --- @repo: #{@repo.to_json} --- @project: #{@project}"
end
render_ok
rescue Exception => ex

View File

@ -40,18 +40,49 @@ class Ci::ProjectsController < Ci::BaseController
begin
ActiveRecord::Base.transaction do
if @repo
Rails.logger.info "==========> @repo已经存在 直接激活: #{@repo.to_json}"
Rails.logger.info "==========> @repo.repo_signer: #{@repo.repo_signer} ==> @repo.repo_secret: #{@repo.repo_secret}"
if @repo.repo_signer.blank? && @repo.repo_secret.blank?
@repo.update_columns(
repo_user_id: @ci_user.user_id,
repo_namespace: @project.owner.login,
repo_name: @project.identifier,
repo_slug: "#{@project.owner.login}/#{@project.identifier}",
repo_scm: "git",
repo_ssh_url: "",
repo_html_url: "",
repo_clone_url: @project.repository.url,
repo_active: 0,
repo_private: true,
repo_visibility: 'private',
repo_branch: 'master',
repo_counter: 0,
repo_trusted: false,
repo_protected: false,
repo_synced: 0,
repo_version: 1,
repo_timeout: 60,
repo_config: '.trustie-pipeline.yml',
repo_signer: Ci::Repo.generate_code!,
repo_secret: Ci::Repo.generate_code!
)
end
Rails.logger.info "==========> 更新后的repo: #{@repo.to_json}"
return render_error('该项目已经激活') if @repo.repo_active?
@repo.activate!(@project)
return render_ok
else
Rails.logger.info "==========> 没有@repo, 进行创建..."
@repo = Ci::Repo.auto_create!(@ci_user, @project)
@ci_user.update_column(:user_syncing, false)
end
result = bind_hook!(current_user, @cloud_account, @repo)
@project.update_columns(open_devops: true, gitea_webhook_id: result['id'])
@project.increment!(:open_devops_count)
@cloud_account.update_column(:ci_user_id, @ci_user.user_id)
if @project.gitea_webhook_id.blank?
result = bind_hook!(current_user, @cloud_account, @repo)
Rails.logger.info "########## result: #{result}"
@project.update_columns(open_devops: true, gitea_webhook_id: result['id'])
@project.increment!(:open_devops_count)
@cloud_account.update_column(:ci_user_id, @ci_user.user_id)
Rails.logger.info "########## @cloud_account: #{@cloud_account.to_json} --- @repo: #{@repo.to_json} --- @project: #{@project.to_json}"
end
end
render_ok
rescue Exception => ex

View File

@ -24,7 +24,7 @@ class CompareController < ApplicationController
@exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take
end
if @exist_pullrequest.present?
return -2, "在这些分支之间的合并请求已存在:<a href='/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}'>#{@exist_pullrequest.try(:title)}</a>"
return -2, "在这些分支之间的合并请求已存在:<a href='/projects/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}/Messagecount'>#{@exist_pullrequest.try(:title)}</a>"
else
if @compare_result["Commits"].blank? && @compare_result["Diff"].blank?
return -2, "分支内容相同,无需创建合并请求"
@ -48,6 +48,6 @@ class CompareController < ApplicationController
end
def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head)
end
end

View File

@ -116,6 +116,9 @@ module Ci::CloudAccountManageable
},
type: "gitea"
}
Rails.logger.info "============> hook_params: #{hook_params}"
Rails.logger.info "============> user.gitea_token: #{user.gitea_token}"
result = Gitea::Hooks::CreateService.call(user.gitea_token, user.login, repo.repo_name, hook_params)
result[:status].present? ? nil : result

View File

@ -20,7 +20,7 @@ module ControllerRescueHandler
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from Gitlink::TipException, with: :tip_show
rescue_from Educoder::TipException, with: :tip_show
rescue_from ::ActionView::MissingTemplate, with: :missing_template
rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from ActionController::ParameterMissing, with: :render_parameter_missing

View File

@ -36,10 +36,10 @@ module GitCommon
begin
@commits = GitService.commits(repo_path: @repo_path)
logger.info("git first commit is #{@commits.try(:first)}")
raise Gitlink::TipException.new("请先创建版本库") if @commits.nil?
raise Educoder::TipException.new("请先创建版本库") if @commits.nil?
rescue Exception => e
uid_logger_error(e.message)
raise Gitlink::TipException.new("提交记录异常")
raise Educoder::TipException.new("提交记录异常")
end
end

View File

@ -34,7 +34,7 @@ module GitHelper
rescue Exception => e
Rails.logger.error(e.message)
raise Gitlink::TipException.new("文档内容获取异常")
raise Educoder::TipException.new("文档内容获取异常")
end
end
@ -64,7 +64,7 @@ module GitHelper
# 版本库Fork功能
def project_fork(container, original_rep_path, username)
raise Gitlink::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
# 将要生成的仓库名字
new_repo_name = "#{username.try(:strip)}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}"
# uid_logger("start fork container: repo_name is #{new_repo_name}")

View File

@ -35,15 +35,16 @@ module LaboratoryHelper
# my_projects: "/users/#{current_user.try(:login)}/projects",
# my_projects: "https://www.trustie.net/users/#{current_user.try(:login)}/user_projectlist",
{
new_syllabuses: "https://www.trustie.net/syllabuses/new",
new_course: "https://www.trustie.net/courses/new",
edit_account: "https://www.trustie.net/my/account",
my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
new_syllabuses: "https://forge.educoder.net/syllabuses/new",
new_course: "https://forge.educoder.net/courses/new",
edit_account: "https://forge.educoder.net/my/account",
my_courses: "https://forge.educoder.net/users/#{current_user.try(:login)}/user_courselist",
my_projects: "/users/#{current_user.try(:login)}/projects",
my_organ: "https://www.trustie.net/users/#{current_user.try(:login)}/user_organizations",
default_url: Rails.application.config_for(:configuration)['platform_url'],
tiding_url: "https://www.trustie.net/users/#{current_user.try(:login)}/user_messages",
register_url: "https://www.trustie.net/login?login=false"
my_organ: "https://forge.educoder.net/users/#{current_user.try(:login)}/user_organizations",
default_url: EduSetting.get("host_name"),
forge_url: "http://106.75.178.228:81",
tiding_url: "https://www.educoder.net/users/#{current_user.try(:login)}/user_tidings",
register_url: "https://www.educoder.net/user/register"
}
end
end

View File

@ -112,6 +112,7 @@ module LoginHelper
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
user.update_column(:is_sync_pwd, true)
true
else
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"

View File

@ -2,8 +2,6 @@ module RegisterHelper
extend ActiveSupport::Concern
def autologin_register(username, email, password, platform= 'forge')
result = {message: nil, user: nil}
user = User.new(admin: false, login: username, mail: email, type: "User")
user.password = password
user.platform = platform
@ -11,20 +9,36 @@ module RegisterHelper
return unless user.valid?
create_gitea_user!(user, username, email, password)
end
def create_gitea_user!(forge_user, username, email, password=random_password)
result = {message: nil, user: nil}
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
if interactor.success?
gitea_user = interactor.result
result = Gitea::User::GenerateTokenService.call(username, password)
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
if user.save!
UserExtension.create!(user_id: user.id)
result[:user] = {id: user.id, token: user.gitea_token}
if interactor.success? || interactor.error.to_s.include?("已被注册")
gitea_user = interactor.error.to_s.include?("已被注册") ? Gitea::User::GetService.call(username) : interactor.result
Rails.logger.info "##### [gitea] create_gitea_user result: #{gitea_user}"
if gitea_user[:body].present?
result = Gitea::User::GenerateTokenService.call(username, password)
forge_user.gitea_token = result['sha1']
forge_user.gitea_uid = gitea_user[:body]['id'] if gitea_user[:body].present? && gitea_user[:body]['id'] !=0
forge_user.mail = email
if forge_user.save
UserExtension.create!(user_id: forge_user.id) if forge_user.user_extension.blank?
result[:user] = {id: forge_user.id, token: forge_user.gitea_token}
end
else
result[:message] = interactor.error
end
else
Rails.logger.info "##### [gitea] create_gitea_user result: #{interactor.error}"
result[:message] = interactor.error
end
result
end
def random_password
"#{Random.rand(11111111)}"
end
end

View File

@ -3,8 +3,8 @@ module RenderHelper
render json: { status: 0, message: 'success' }.merge(data)
end
def render_error(status = -1, message = '')
render json: { status: status, message: message }
def render_error(message = '')
render json: { status: -1, message: message }
end
def render_not_acceptable(message = '请求已拒绝')

View File

@ -29,8 +29,10 @@ class EduSettingsController < ApplicationController
respond_to do |format|
if @edu_setting.save
format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully created.' }
format.json { render :show, status: :created, location: @edu_setting }
else
format.html { render :new }
format.json { render json: @edu_setting.errors, status: :unprocessable_entity }
end
end
@ -41,8 +43,10 @@ class EduSettingsController < ApplicationController
def update
respond_to do |format|
if @edu_setting.update(edu_setting_params)
format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully updated.' }
format.json { render :show, status: :ok, location: @edu_setting }
else
format.html { render :edit }
format.json { render json: @edu_setting.errors, status: :unprocessable_entity }
end
end
@ -53,6 +57,7 @@ class EduSettingsController < ApplicationController
def destroy
@edu_setting.destroy
respond_to do |format|
format.html { redirect_to edu_settings_url, notice: 'Edu setting was successfully destroyed.' }
format.json { head :no_content }
end
end

View File

@ -1,11 +1,18 @@
class ForksController < ApplicationController
before_action :require_login
before_action :require_profile_completed, only: [:create]
before_action :load_project
before_action :authenticate_project!, :authenticate_user!
def create
@new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call
# TODO: fix Educoder shixun
if @new_project.persisted?
ProjectScore.create(:project_id => @new_project.id, :score => 0) if @new_project.project_score.nil?
project_info = ProjectInfo.new(:user_id => current_user.id, :project_id => @new_project.id)
@project.project_infos << project_info
end
end
private

View File

@ -7,7 +7,7 @@ class IssueTagsController < ApplicationController
def index
issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}")
issue_tags = @project.issue_tags.order("#{order_name} #{order_type}")
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
@page = params[:page] || 1
@limit = params[:limit] || 15

View File

@ -1,21 +1,20 @@
class IssuesController < ApplicationController
before_action :require_login, except: [:index, :show, :index_chosen]
before_action :require_profile_completed, only: [:create]
before_action :load_project
before_action :set_user
before_action :check_menu_authorize, except: [:index_chosen]
before_action :check_issue_permission
before_action :operate_issue_permission, only:[:create, :update, :destroy, :clean, :series_update, :copy]
before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue]
before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue]
before_action :check_token_enough, :find_atme_receivers, only: [:create, :update]
before_action :check_token_enough, only: [:create, :update]
include ApplicationHelper
include TagChosenHelper
def index
@user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user) || @project.is_public?)
return render_not_found unless @project.has_menu_permission("issues")
@user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user))
issues = @project.issues.issue_issue.issue_index_includes
issues = issues.where(is_private: false) unless @user_admin_or_member
@ -108,11 +107,9 @@ class IssuesController < ApplicationController
def create
issue_params = issue_send_params(params)
Issues::CreateForm.new({subject:issue_params[:subject]}).validate!
Issues::CreateForm.new({subject:issue_params[:subject], start_date: issue_params[:start_date], due_date: issue_params[:due_date]}).validate!
@issue = Issue.new(issue_params)
if @issue.save!
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @issue&.id) if Site.has_notice_menu?
if params[:attachment_ids].present?
params[:attachment_ids].each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
@ -142,10 +139,6 @@ class IssuesController < ApplicationController
end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
render json: {status: 0, message: "创建成", id: @issue.id}
else
normal_status(-1, "创建失败")
@ -164,7 +157,6 @@ class IssuesController < ApplicationController
def update
last_token = @issue.token
last_status_id = @issue.status_id
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@ -207,28 +199,8 @@ class IssuesController < ApplicationController
normal_status(-1, "不允许修改为关闭状态")
else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate!
Issues::UpdateForm.new({subject:issue_params[:subject], start_date: issue_params[:start_date], due_date: issue_params[:due_date]}).validate!
if @issue.update_attributes(issue_params)
if @issue&.pull_request.present?
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
else
previous_changes = @issue.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name)
if @issue.previous_changes[:start_date].present?
previous_changes.merge!(start_date: [@issue.previous_changes[:start_date][0].to_s, @issue.previous_changes[:start_date][1].to_s])
end
if @issue.previous_changes[:due_date].present?
previous_changes.merge!(due_date: [@issue.previous_changes[:due_date][0].to_s, @issue.previous_changes[:due_date][1].to_s])
end
if @issue.previous_changes[:status_id].present? && @issue.previous_changes[:status_id][1] == 5
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE)
end
if @issue.previous_changes[:status_id].present? && @issue.previous_changes[:status_id][0] == 5
@issue.project_trends.where(action_type: ProjectTrend::CLOSE).destroy_all
end
SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, @issue&.id, previous_changes) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project!
@ -247,11 +219,7 @@ class IssuesController < ApplicationController
change_type = change_token > 0 ? "add" : "minus"
post_to_chain(change_type, change_token.abs, current_user.try(:login))
end
@issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) if @issue.previous_changes.present?
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
@issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id)
normal_status(0, "更新成功")
else
normal_status(-1, "更新失败")
@ -284,7 +252,6 @@ class IssuesController < ApplicationController
status_id = @issue.status_id
token = @issue.token
login = @issue.user.try(:login)
SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigned_to_id, @issue.author_id) if Site.has_notice_menu?
if @issue.destroy
if issue_type == "2" && status_id != 5
post_to_chain("add", token, login)
@ -304,12 +271,8 @@ class IssuesController < ApplicationController
def clean
#批量删除,暂时只能删除未悬赏的
issue_ids = params[:ids]
issues = Issue.where(id: issue_ids, issue_type: "1")
if issues.present?
issues.find_each do |i|
SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, i&.subject, i.assigned_to_id, i.author_id) if Site.has_notice_menu?
end
if issues.destroy_all
if issue_ids.present?
if Issue.where(id: issue_ids, issue_type: "1").destroy_all
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
@ -339,28 +302,9 @@ class IssuesController < ApplicationController
# update_hash = params[:issue]
issue_ids = params[:ids]
if issue_ids.present?
issues = Issue.where(id: issue_ids)
if update_hash.blank?
normal_status(-1, "请选择批量更新内容")
elsif issues&.update(update_hash)
issues.each do |i|
i.create_journal_detail(false, [], [], current_user&.id) if i.previous_changes.present?
previous_changes = i.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name)
if i.previous_changes[:start_date].present?
previous_changes.merge!(start_date: [i.previous_changes[:start_date][0].to_s, i.previous_changes[:start_date][1].to_s])
end
if i.previous_changes[:due_date].present?
previous_changes.merge!(due_date: [i.previous_changes[:due_date][0].to_s, i.previous_changes[:due_date][1].to_s])
end
if i.previous_changes[:status_id].present? && i.previous_changes[:status_id][1] == 5
i.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE)
end
if i.previous_changes[:status_id].present? && i.previous_changes[:status_id][0] == 5
i.project_trends.where(action_type: ProjectTrend::CLOSE).destroy_all
end
SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, i&.id, previous_changes) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, i&.id) if i.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
end
elsif Issue.where(id: issue_ids)&.update(update_hash)
normal_status(0, "批量更新成功")
else
normal_status(-1, "批量更新失败")
@ -374,8 +318,6 @@ class IssuesController < ApplicationController
@new_issue = @issue.dup
@new_issue.author_id = current_user.id
if @new_issue.save
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @new_issue&.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @new_issue&.id) if Site.has_notice_menu?
issue_tags = @issue.issue_tags.pluck(:id)
if issue_tags.present?
issue_tags.each do |tag|
@ -453,27 +395,27 @@ class IssuesController < ApplicationController
def check_project_public
unless @project.is_public || @project.member?(current_user) || current_user.admin? || (@project.user_id == current_user.id)
return render_forbidden
normal_status(-1, "您没有权限")
end
end
def set_issue
@issue = Issue.find_by_id(params[:id])
if @issue.blank?
return render_not_found
elsif !(@project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id))))
return render_forbidden
normal_status(-1, "标签不存在")
elsif @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?)
normal_status(-1, "您没有权限")
end
end
def check_issue_permission
unless @project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id)))
return render_forbidden
normal_status(-1, "您没有权限")
end
end
def operate_issue_permission
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || @project.is_public?)
return render_forbidden("您没有权限进行此操作.") unless current_user.admin? || @project.member?(current_user)
end
def export_issues(issues)
@ -555,8 +497,4 @@ class IssuesController < ApplicationController
return normal_status(-1, "您的token值不足") if JSON.parse(response.body)["balance"].to_i < params[:token].to_i
end
end
def check_menu_authorize
return render_not_found unless @project.has_menu_permission("issues")
end
end

View File

@ -1,6 +1,5 @@
class JournalsController < ApplicationController
before_action :require_login, except: [:index, :get_children_journals]
before_action :require_profile_completed, :find_atme_receivers, only: [:create]
before_action :set_issue
before_action :check_issue_permission
before_action :set_journal, only: [:destroy, :edit, :update]
@ -22,35 +21,32 @@ class JournalsController < ApplicationController
if notes.blank?
normal_status(-1, "评论内容不能为空")
else
ActiveRecord::Base.transaction do
journal_params = {
journalized_id: @issue.id ,
journalized_type: "Issue",
user_id: current_user.id ,
notes: notes.to_s.strip,
parent_id: params[:parent_id]
}
journal = Journal.new journal_params
if journal.save
if params[:attachment_ids].present?
params[:attachment_ids].each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
unless attachment.blank?
attachment.container = journal
attachment.author_id = current_user.id
attachment.description = ""
attachment.save
end
journal_params = {
journalized_id: @issue.id ,
journalized_type: "Issue",
user_id: current_user.id ,
notes: notes.to_s.strip,
parent_id: params[:parent_id]
}
journal = Journal.new journal_params
if journal.save
if params[:attachment_ids].present?
params[:attachment_ids].each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
unless attachment.blank?
attachment.container = journal
attachment.author_id = current_user.id
attachment.description = ""
attachment.save
end
end
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, journal) if @atme_receivers.size > 0
# @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "journal")
render :json => { status: 0, message: "评论成功", id: journal.id}
# normal_status(0, "评论成功")
else
normal_status(-1, "评论失败")
end
# @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "journal")
render :json => { status: 0, message: "评论成功", id: journal.id}
# normal_status(0, "评论成功")
else
normal_status(-1, "评论失败")
end
end
end

View File

@ -21,11 +21,19 @@ class MainController < ApplicationController
uid_logger("main start is #{cookies[:_educoder_session]}")
end
if params[:path] && params[:path].start_with?('projects/')
project_id = params[:path].split("/")[1]
project = Project.find_by_id(project_id)
if project.present?
return redirect_to("/projects/#{project.owner.login}/#{project.identifier}", status: 301)
end
end
# TODO: 这块之后需要整合者架构重新变化统一跳转到index后再路由分发
if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
render file: 'public/h5educoderbuild/index.html', :layout => false, :content_type=> 'text/html'
render file: 'public/h5educoderbuild/index.html', :layout => false
else
render file: 'public/react/build/index.html', :layout => false, :content_type=> 'text/html'
render file: 'public/react/build/index.html', :layout => false
end
end

View File

@ -2,15 +2,21 @@ class MembersController < ApplicationController
before_action :require_login
before_action :load_project
before_action :find_user_with_id, only: %i[create remove change_role]
before_action :check_user_profile_completed, only: [:create]
before_action :operate!, except: %i[index]
before_action :check_member_exists!, only: %i[create]
before_action :check_member_not_exists!, only: %i[remove change_role]
def create
if @user.gitea_token.blank?
result = Gitea::User::GetService.call(@user.login)
if result[:status] == :error
# gitea不存在用户@user,直接注册
user_result = create_gitea_user!(@user, @user.login, @user.mail)
return render_error(user_result[:message]) if user_result[:message]
end
end
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
SendTemplateMessageJob.perform_later('ProjectJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@ -30,8 +36,6 @@ class MembersController < ApplicationController
def remove
interactor = Projects::DeleteMemberInteractor.call(@project.owner, @project, @user)
SendTemplateMessageJob.perform_later('ProjectLeft', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@ -40,7 +44,6 @@ class MembersController < ApplicationController
def change_role
interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role])
SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@ -53,7 +56,7 @@ class MembersController < ApplicationController
end
def member_exists?
@project.members.exists?(user_id: params[:user_id])
@project.members.exists?(params[:user_id])
end
def operate!
@ -61,24 +64,10 @@ class MembersController < ApplicationController
end
def check_member_exists!
return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
return render_result(1, "user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
end
def check_member_not_exists!
return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
end
def check_user_profile_completed
require_user_profile_completed(@user)
end
def message_role_name
case params[:role]
when 'Manager' then '管理员'
when 'Developer' then '开发者'
when 'Reporter' then '报告者'
else
''
end
return render_result(1, "user_id为#{params[:user_id]}的用户还不是项目成员") unless @project.member?(params[:user_id])
end
end

View File

@ -1,6 +1,5 @@
class Organizations::OrganizationsController < Organizations::BaseController
before_action :require_login, except: [:index, :show, :recommend]
before_action :require_profile_completed, only: [:create]
before_action :convert_image!, only: [:create, :update]
before_action :load_organization, only: [:show, :update, :destroy]
before_action :check_user_can_edit_org, only: [:update, :destroy]
@ -22,12 +21,10 @@ class Organizations::OrganizationsController < Organizations::BaseController
@can_create_project = @organization.can_create_project?(current_user.id)
@is_admin = can_edit_org?
@is_member = @organization.is_member?(current_user.id)
Cache::V2::OwnerCommonService.new(@organization.id).read
end
def create
ActiveRecord::Base.transaction do
tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name])
Organizations::CreateForm.new(organization_params).validate!
@organization = Organizations::CreateService.call(current_user, organization_params)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
@ -44,8 +41,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
@organization.login = organization_params[:name] if organization_params[:name].present?
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
@organization.save!
sync_organization_extension!
@organization.organization_extension.update_attributes!(organization_params.except(:name, :nickname))
Gitea::Organization::UpdateService.call(@organization.gitea_token, login, @organization.reload)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
end
@ -69,7 +65,8 @@ class Organizations::OrganizationsController < Organizations::BaseController
def recommend
recommend = %W(xuos Huawei_Technology openatom_foundation pkecosystem TensorLayer)
@organizations = Organization.includes(:organization_extension).where(organization_extensions: {recommend: true}).to_a.each_slice(group_size).to_a
@organizations = Organization.with_visibility(%w(common))
.where(login: recommend).select(:id, :login, :firstname, :lastname, :nickname)
end
private
@ -80,10 +77,6 @@ class Organizations::OrganizationsController < Organizations::BaseController
:max_repo_creation, :nickname)
end
def group_size
params.fetch(:group_size, 4).to_i
end
def password
params.fetch(:password, "")
end
@ -102,18 +95,4 @@ class Organizations::OrganizationsController < Organizations::BaseController
%w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
end
def set_max_repo_creation
organization_params[:max_repo_creation].blank? ? -1 : organization_params[:max_repo_creation]
end
def organization_extension_params
organization_params
.except(:name, :nickname)
.merge(max_repo_creation: set_max_repo_creation)
end
def sync_organization_extension!
@organization.organization_extension.update_attributes!(organization_extension_params)
end
end

View File

@ -1,7 +1,6 @@
class Organizations::TeamUsersController < Organizations::BaseController
before_action :load_organization, :load_team
before_action :load_operate_user, only: [:create, :destroy]
before_action :check_user_profile_completed, only: [:create]
before_action :load_team_user, only: [:destroy]
before_action :check_user_can_edit_org, only: [:create, :destroy]
@ -18,7 +17,6 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user = TeamUser.build(@organization.id, @operate_user.id, @team.id)
@organization_user = OrganizationUser.build(@organization.id, @operate_user.id)
SendTemplateMessageJob.perform_later('OrganizationRole', @operate_user.id, @organization.id, @team.authorize_name) if Site.has_notice_menu?
Gitea::Organization::TeamUser::CreateService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
end
rescue Exception => e
@ -31,11 +29,6 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user.destroy!
Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
org_team_users = @organization.team_users.where(user_id: @operate_user.id)
unless org_team_users.present?
@organization.organization_users.find_by(user_id: @operate_user.id).destroy!
Gitea::Organization::OrganizationUser::DeleteService.call(@organization.gitea_token, @organization.login, @operate_user.login)
end
render_ok
end
rescue Exception => e
@ -50,11 +43,6 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user.destroy!
Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, current_user.login)
org_team_users = @organization.team_users.where(user_id: current_user.id)
unless org_team_users.present?
@organization.organization_users.find_by(user_id: current_user.id).destroy!
Gitea::Organization::OrganizationUser::DeleteService.call(@organization.gitea_token, @organization.login, current_user.login)
end
render_ok
end
rescue Exception => e
@ -85,8 +73,4 @@ class Organizations::TeamUsersController < Organizations::BaseController
tip_exception("组织团队成员不存在") if @team_user.nil?
end
def check_user_profile_completed
require_user_profile_completed(@operate_user)
end
end

View File

@ -1,5 +1,5 @@
class OwnersController < ApplicationController
before_action :require_login, only: [:index]
before_action :require_login
def index
@owners = []
@ -9,53 +9,4 @@ class OwnersController < ApplicationController
teams: {can_create_org_project: true})
.distinct
end
def show
@owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
return render_not_found unless @owner.present?
# 组织
if @owner.is_a?(Organization)
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition
@can_create_project = @owner.can_create_project?(current_user.id)
@is_admin = current_user.admin? || @owner.is_owner?(current_user.id)
@is_member = @owner.is_member?(current_user.id)
# 用户
else
#待办事项,现在未做
if User.current.admin? || User.current.login == @owner.login
@waiting_applied_messages = @owner.applied_messages.waiting
@common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @owner.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @owner.id}, teams: {authorize: %w(admin owner)} )).common
@common_applied_projects = AppliedProject.where(project_id: @owner.full_admin_projects).common
@undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size
else
@waiting_applied_messages = AppliedMessage.none
@common_applied_transfer_projects = AppliedTransferProject.none
@common_applied_projects = AppliedProject.none
@undo_events = 0
end
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 0
user_organizations = User.current.logged? ? @owner.organizations.with_visibility(%w(common limited)) + @owner.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @owner.organizations.with_visibility("common")
@user_org_count = user_organizations.size
normal_projects = Project.members_projects(@owner.id).to_sql
org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @owner.id}).to_sql
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
user_projects = User.current.logged? && (User.current.admin? || User.current.login == @owner.login) ? projects : projects.visible
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size
puts @owner.as_json
end
end
private
def org_limited_condition
@owner.organization_extension.limited? && !current_user.logged?
end
def org_privacy_condition
return false if current_user.admin?
@owner.organization_extension.privacy? && @owner.organization_users.where(user_id: current_user.id).blank?
end
end
end

View File

@ -1,6 +1,5 @@
class PraiseTreadController < ApplicationController
before_action :require_login, except: %i[index]
before_action :require_profile_completed, only: [:like]
before_action :find_project_with_id
def index

View File

@ -5,10 +5,6 @@ class ProjectCategoriesController < ApplicationController
@project_categories = q.result(distinct: true)
end
def pinned_index
@project_categories = ProjectCategory.where.not(pinned_index: 0).order(pinned_index: :desc)
end
def group_list
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
# projects = Project.no_anomory_projects.visible

View File

@ -1,26 +0,0 @@
class ProjectRankController < ApplicationController
# 根据时间获取热门项目
def index
$redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names)
deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
$redis_cache.zrem("recent-days-project-rank", deleted_data) unless deleted_data.blank?
@project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true)
rescue Exception => e
@project_rank = []
end
private
# 默认显示7天的
def time
params.fetch(:time, 7).to_i
end
def get_timeable_key_names
names_array = []
(0...time).to_a.each do |i|
date_time_string = (Date.today - i.days).to_s
names_array << "v2-project-rank-#{date_time_string}"
end
names_array
end
end

View File

@ -3,7 +3,7 @@ class ProjectTrendsController < ApplicationController
before_action :check_project_public
def index
project_trends = @project.project_trends.preload(:user, trend: :user)
project_trends = @project.project_trends.includes(:user, trend: :user)
check_time = params[:time] #时间的筛选
check_type = params[:type] #动态类型的筛选,目前已知的有 Issue, PullRequest, Version
@ -14,25 +14,20 @@ class ProjectTrendsController < ApplicationController
project_trends = project_trends.where("created_at between ? and ?",(Time.now.beginning_of_day - check_time.days), Time.now.end_of_day)
end
@project_open_issues_count = project_trends.where(trend_type: "Issue", action_type: "create").size
@project_close_issues_count = project_trends.where(trend_type: "Issue", action_type: "close").size
@project_issues_count = project_trends.where(trend_type: "Issue", action_type: "create").size
@project_open_issues_count = @project_issues_count - @project_close_issues_count
@project_issues_count = @project_open_issues_count + @project_close_issues_count
@project_pr_count = project_trends.where(trend_type: "PullRequest", action_type: "close").size
@project_new_pr_count = project_trends.where(trend_type: "PullRequest", action_type: "create").size
@project_pr_all_count = @project_pr_count + @project_new_pr_count
@project_pr_count = project_trends.where(trend_type: "PullRequest", action_type: ["close", "merge"]).size
@project_pr_all_count = project_trends.where(trend_type: "PullRequest", action_type: "create").size
@project_new_pr_count = @project_pr_all_count - @project_pr_count
if check_type.present?
project_trends = project_trends.where(trend_type: check_type.to_s.strip)
end
if check_status.present?
if check_status == "delay" || check_status == "close"
project_trends = project_trends.where(action_type: ["close", "merge"])
else
project_trends = project_trends.where(action_type: ["create"]).where.not(trend_id: project_trends.where(action_type: ["close", "merge"]).pluck(:trend_id))
end
else
project_trends = project_trends.where(action_type: "create")
project_trends = project_trends.where(action_type: check_status.to_s.strip)
end
project_trends = project_trends.order("created_at desc")

View File

@ -1,6 +1,5 @@
class Projects::AppliedTransferProjectsController < Projects::BaseController
before_action :check_auth
before_action :check_user_profile_completed, only: [:create]
def organizations
@organizations = Organization.includes(:organization_extension).joins(team_users: :team).where(team_users: {user_id: current_user.id}, teams: {authorize: %w(admin owner)})
@ -24,10 +23,4 @@ class Projects::AppliedTransferProjectsController < Projects::BaseController
def check_auth
return render_forbidden unless current_user.admin? ||@project.owner?(current_user)
end
def check_user_profile_completed
@owner = Owner.find_by(login: params[:owner_name])
return if @owner.is_a?(Organization)
require_user_profile_completed(@owner)
end
end

View File

@ -7,4 +7,5 @@ class Projects::BaseController < ApplicationController
def require_manager!
return render_forbidden('你没有权限操作') unless current_user.admin? || @project.manager?(current_user)
end
end

View File

@ -1,6 +0,0 @@
class Projects::MembersController < Projects::BaseController
def index
users = @project.all_collaborators.like(params[:search]).includes(:user_extension)
@users = kaminari_paginate(users)
end
end

View File

@ -1,5 +1,4 @@
class Projects::ProjectAppliesController < Projects::BaseController
before_action :require_profile_completed, only: [:create]
def create
project = Projects::ApplyJoinService.call(current_user, create_params)
render_ok(project_id: project.id)

View File

@ -6,8 +6,7 @@ class Projects::ProjectUnitsController < Projects::BaseController
def create
if current_user.admin? || @project.manager?(current_user)
ActiveRecord::Base.transaction do
before_units, after_units = ProjectUnit.update_by_unit_types!(@project, unit_types)
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, {navbar: true}) unless before_units.eql?(after_units) if Site.has_notice_menu?
ProjectUnit.update_by_unit_types!(@project, unit_types)
render_ok
end
else

View File

@ -14,7 +14,7 @@ class Projects::TeamsController < Projects::BaseController
def create
ActiveRecord::Base.transaction do
@team_project = TeamProject.build(@owner.id, @operate_team.id, @project.id)
Gitea::Organization::TeamProject::CreateService.call(current_user.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
Gitea::Organization::TeamProject::CreateService.call(@owner.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
render_ok
end
rescue Exception => e
@ -25,7 +25,7 @@ class Projects::TeamsController < Projects::BaseController
def destroy
ActiveRecord::Base.transaction do
@team_project.destroy!
Gitea::Organization::TeamProject::DeleteService.call(current_user.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
Gitea::Organization::TeamProject::DeleteService.call(@owner.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
render_ok
end
rescue Exception => e

View File

@ -9,7 +9,7 @@ class Projects::WebhooksController < Projects::BaseController
def create
ActiveRecord::Base.transaction do
return render_error("webhooks数量已到上限请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19
return render_error("webhooks数量已到上限请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
return render_error("参数错误.") unless webhook_params.present?
form = Projects::Webhooks::CreateForm.new(webhook_params)
return render json: {status: -1, message: form.errors} unless form.validate!
@ -22,6 +22,7 @@ class Projects::WebhooksController < Projects::BaseController
end
rescue Exception => e
uid_logger_error(e.message)
Rails.logger.error("异常堆栈=======#{e.backtrace}")
tip_exception(e.message)
end

View File

@ -4,9 +4,8 @@ class ProjectsController < ApplicationController
include ProjectsHelper
include Acceleratorable
before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list]
before_action :require_profile_completed, only: [:create, :migrate]
before_action :load_repository, except: %i[index group_type_list migrate create recommend banner_recommend]
before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list]
before_action :load_repository, except: %i[index group_type_list migrate create recommend]
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
@ -17,31 +16,35 @@ class ProjectsController < ApplicationController
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls")
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki")
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops")
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources")
menu.append(menu_hash_by_name("activity"))
menu.append(menu_hash_by_name("settings")) if current_user.admin? || @project.manager?(current_user)
# menu.append(menu_hash_by_name("gantt"))
# menu.append(menu_hash_by_name("sonar"))
# menu.append(menu_hash_by_name("setting")) if current_user.admin? || @project.manager?(current_user)
menu.append(menu_hash_by_name("sonar"))
menu.append(menu_hash_by_name("setting")) if current_user.admin? || @project.manager?(current_user)
menu.append(menu_hash_by_name("quit")) if !current_user.admin? && @project.member(current_user.id) && @project.forge?
render json: menu
end
def index
scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params)
scope = Projects::ListQuery.call(params, current_user)
@projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units))
# @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
category_id = params[:category_id]
@total_count =
if category_id.blank?
ps = ProjectStatistic.first
ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
else
cate = ProjectCategory.find_by(id: category_id)
cate&.projects_count || 0
end
# @projects = kaminari_paginate(scope)
@total_count = scope.size
@projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units, :applied_projects)
# category_id = params[:category_id]
# @total_count =
# if category_id.blank?
# ps = ProjectStatistic.first
# ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
# else
# cate = ProjectCategory.find_by(id: category_id)
# cate&.projects_count || 0
# end
end
def create
@ -49,6 +52,13 @@ class ProjectsController < ApplicationController
Projects::CreateForm.new(project_params).validate!
@project = Projects::CreateService.new(current_user, project_params).call
# TODO: fix Educoder shixun
if @project.persisted?
ProjectScore.create(:project_id => @project.id, :score => 0) if @project.project_score.nil?
project_info = ProjectInfo.new(:user_id => current_user.id, :project_id => @project.id)
@project.project_infos << project_info
end
end
rescue Exception => e
uid_logger_error(e.message)
@ -86,26 +96,19 @@ class ProjectsController < ApplicationController
@branches = result.is_a?(Hash) && result.key?(:status) ? [] : result
end
def branches_slice
return @branches = [] unless @project.forge?
slice_result = Gitea::Repository::Branches::ListSliceService.call(@owner, @project.identifier)
@branches_slice = slice_result.is_a?(Hash) && slice_result.key?(:status) ? [] : slice_result
end
def group_type_list
project_statics = ProjectStatistic.first
# project_statics = ProjectStatistic.first
@project_statics_list = [
{
project_type: 'common',
name: '开源托管项目',
projects_count: project_statics&.common_projects_count || 0
projects_count: Project.common.visible.size || 0
},
{
project_type: 'mirror',
name: '开源镜像项目',
projects_count: project_statics&.mirror_projects_count || 0
projects_count: Project.sync_mirror.visible.count + Project.mirror.visible.count || 0
}
]
@ -117,19 +120,26 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
# TODO:
# 临时特殊处理修改website、lesson_url操作方法
if project_params.has_key?("website")
@project.update(project_params)
elsif project_params.has_key?("default_branch")
if project_params.has_key?("website")
if params[:project_topic_names].is_a?(Array)
ProjectTopicRalate.where(project: @project).destroy_all
params[:project_topic_names].each do |name|
project_topic = ProjectTopic.find_or_create_by!(name: name.downcase)
project_topic.project_topic_ralates.find_or_create_by!(project: @project)
end
end
@project.update(project_params)
elsif project_params.has_key?("default_branch") && project_params[:default_branch].present?
@project.update(default_branch: project_params[:default_branch])
gitea_params = {
default_branch: @project.default_branch
}
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
else
validate_params = project_params.slice(:name, :description,
:project_category_id, :project_language_id, :private, :identifier)
:project_category_id, :project_language_id, :private, :join_project_need_verify)
Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier)).validate!
Projects::UpdateForm.new(validate_params).validate!
private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false
@ -139,13 +149,13 @@ class ProjectsController < ApplicationController
gitea_params = {
private: private,
default_branch: @project.default_branch,
website: @project.website,
name: @project.identifier
website: @project.website
}
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
@project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
if [true, false].include? private
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
@project.repository.update_column(:hidden, private)
end
end
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
end
rescue Exception => e
uid_logger_error(e.message)
@ -190,8 +200,6 @@ class ProjectsController < ApplicationController
end
def simple
# 为了缓存活跃项目的基本信息,后续删除
Cache::V2::ProjectCommonService.new(@project.id).read
json_response(@project, current_user)
end
@ -199,10 +207,6 @@ class ProjectsController < ApplicationController
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc)
end
def banner_recommend
@projects = Project.recommend.where.not(recommend_index: 0).includes(:project_category, :owner, :project_language).order(recommend_index: :desc)
end
def about
@project_detail = @project.project_detail
@attachments = Array(@project_detail&.attachments) if request.get?
@ -235,7 +239,7 @@ class ProjectsController < ApplicationController
private
def project_params
params.permit(:user_id, :name, :description, :repository_name, :website, :lesson_url, :default_branch, :identifier,
:project_category_id, :project_language_id, :license_id, :ignore_id, :private)
:project_category_id, :project_language_id, :license_id, :ignore_id, :private, :join_project_need_verify)
end
def mirror_params

View File

@ -1,64 +0,0 @@
class PublicKeysController < ApplicationController
before_action :require_login
before_action :find_public_key, only: [:destroy]
def index
@public_keys = current_user.public_keys
@public_keys = kaminari_paginate(@public_keys)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def create
return render_error("参数错误") if public_key_params.blank?
return render_ok({status: 10002, message: "请输入密钥"}) if public_key_params[:key].blank?
return render_ok({status: 10001, message: "请输入标题"}) if public_key_params[:title].blank?
@gitea_response = Gitea::User::Keys::CreateService.call(current_user.gitea_token, public_key_params)
if @gitea_response[0] == 201
@public_key = @gitea_response[2]
else
return render_error("创建ssh key失败") if @gitea_response[2].blank?
return render_ok({status: 10002, message: "密钥格式不正确"}) if @gitea_response[2]["message"].starts_with?("Invalid key content")
exist_public_key = Gitea::PublicKey.find_by(content: public_key_params[:key])
return render_ok({status: 10002, message: "密钥已被占用"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key") && exist_public_key.present? && exist_public_key&.owner_id != current_user.gitea_uid
return render_ok({status: 10002, message: "密钥已存在,请勿重复添加"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key")
@public_key = nil
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def destroy
return render_not_found unless @public_key.present?
result = Gitea::User::Keys::DeleteService.call(current_user.gitea_token, @public_key.id)
if result[0] == 204
render_ok
else
render_error
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def page
params[:page].to_i.zero? ? 1 : params[:page].to_i
end
def limit
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
end
def public_key_params
params.require(:public_key).permit(:key, :title)
end
def find_public_key
@public_key = current_user.public_keys.find_by_id(params[:id])
end
end

View File

@ -1,16 +1,14 @@
class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show, :files, :commits]
before_action :require_profile_completed, only: [:create]
before_action :load_repository
before_action :check_menu_authorize
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
before_action :load_pull_request, only: [:files, :commits]
before_action :find_atme_receivers, only: [:create, :update]
include TagChosenHelper
include ApplicationHelper
def index
return render_not_found unless @project.has_menu_permission("pulls")
# @issues = Gitea::PullRequest::ListService.new(@user,@repository.try(:identifier)).call #通过gitea获取
issues = @project.issues.issue_pull_request.issue_index_includes.includes(pull_request: :user)
issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user))
@ -21,7 +19,6 @@ class PullRequestsController < ApplicationController
@close_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::CLOSED})
@merged_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::MERGED})
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
@user_admin_or_developer = current_user.present? && (current_user.admin || @project.all_developers.include?(current_user))
scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "PullRequest")
@issues_size = scopes.size
@ -60,10 +57,7 @@ class PullRequestsController < ApplicationController
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id) if Site.has_notice_menu?
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @pull_request) if @atme_receivers.size > 0
render_ok
else
render_error("create pull request error: #{@gitea_pull_request[:status]}")
raise ActiveRecord::Rollback
@ -72,22 +66,21 @@ class PullRequestsController < ApplicationController
end
def edit
@fork_project_user_name = @pull_request&.fork_project&.owner.try(:show_real_name)
@fork_project_user = @pull_request&.fork_project&.owner.try(:login)
@fork_project_identifier = @pull_request&.fork_project&.repository.try(:identifier)
@fork_project_user_name = @project&.fork_project&.owner.try(:show_real_name)
@fork_project_user = @project&.fork_project&.owner.try(:login)
@fork_project_identifier = @project&.fork_project&.repository.try(:identifier)
end
def update
if params[:title].nil?
normal_status(-1, "名称不能为空")
elsif params[:issue_tag_ids].nil?
normal_status(-1, "不能为空")
normal_status(-1, "不能为空")
else
ActiveRecord::Base.transaction do
begin
merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@ -109,8 +102,6 @@ class PullRequestsController < ApplicationController
if params[:status_id].to_i == 5
@issue.issue_times.update_all(end_time: Time.now)
end
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @pull_request) if @atme_receivers.size > 0
normal_status(0, "PullRequest更新成功")
else
normal_status(-1, "PullRequest更新失败")
@ -123,8 +114,6 @@ class PullRequestsController < ApplicationController
normal_status(-1, e.message)
raise ActiveRecord::Rollback
end
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
end
end
@ -134,13 +123,7 @@ class PullRequestsController < ApplicationController
ActiveRecord::Base.transaction do
begin
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
if colsed === true
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
normal_status(1, "已拒绝")
else
normal_status(-1, '合并失败')
end
colsed === true ? normal_status(1, "已拒绝") : normal_status(-1, '合并失败')
rescue => e
normal_status(-1, e.message)
raise ActiveRecord::Rollback
@ -177,10 +160,8 @@ class PullRequestsController < ApplicationController
end
if success_condition && @pull_request.merge!
# @pull_request.project_trend_status!
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
@pull_request.project_trend_status!
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
normal_status(1, "合并成功")
else
normal_status(-1, result.message)
@ -207,7 +188,7 @@ class PullRequestsController < ApplicationController
if can_merge.present?
render json: {
status: -2,
message: "在这些分支之间的合并请求已存在:<a href='/#{@owner.login}/#{@project.identifier}/pulls/#{can_merge.first.id}''>#{can_merge.first.try(:title)}</a>",
message: "在这些分支之间的合并请求已存在:<a href='/projects/#{@owner.login}/#{@project.identifier}/pulls/#{can_merge.first.id}/Messagecount''>#{can_merge.first.try(:title)}</a>",
}
else
normal_status(0, "可以合并")
@ -278,8 +259,4 @@ class PullRequestsController < ApplicationController
status_id: 1,
}
end
def check_menu_authorize
return render_not_found unless @project.has_menu_permission("pulls")
end
end

View File

@ -1,358 +1,374 @@
class RepositoriesController < ApplicationController
include RepositoriesHelper
include ApplicationHelper
include OperateProjectAbilityAble
include Repository::LanguagesPercentagable
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
before_action :require_profile_completed, only: [:create_file]
before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]
def files
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
render json: result
end
# 新版项目详情
def detail
@user = current_user
@result = Repositories::DetailService.call(@owner, @repository, @user)
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@fork_project_user = @fork_project.owner
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show
@user = current_user
@repo = @project.repository
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@fork_project_user = @fork_project.owner
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def entries
@project.increment!(:visits)
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
if @project.educoder?
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
else
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
end
end
def top_counts
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
end
def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
if @project.educoder?
if params[:type] === 'file'
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
logger.info "######### sub_entries: #{@sub_entries}"
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
tmp_entries = [{
"content" => @sub_entries['data']['content'],
"type" => "blob"
}]
@sub_entries = {
"trees"=>tmp_entries,
"commits" => [{}]
}
else
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
end
else
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success?
result = interactor.result
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
else
render_error(interactor.error)
end
end
end
def commits
if params[:filepath].present?
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
@hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri,
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
else
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
end
end
def commits_slice
@hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier,
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token)
end
def commit
@sha = params[:sha]
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true})
end
def tags
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
end
def contributors
if params[:filepath].present?
@contributors = []
else
@contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
end
end
def edit
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
end
def create_file
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
if interactor.success?
@file = interactor.result
# create_new_pr(params)
#如果是更新流水线文件
if params[:pipeline_id]
update_pipeline(params[:pipeline_id])
end
else
render_error(interactor.error)
end
end
def update_pipeline(pipeline_id)
pipeline = Ci::Pipeline.find(pipeline_id)
if pipeline
pipeline.update!(sync: 1)
end
end
def update_file
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
# TODO: 是否创建pr
# create_new_pr(params)
render_result(1, "更新成功")
else
render_error(interactor.error)
end
end
def delete_file
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
render_result(1, "文件删除成功")
else
render_error(interactor.error)
end
end
def repo_hook
end
def sync_mirror
return render_error("正在镜像中..") if @repository.mirror.waiting?
@repository.sync_mirror!
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
render_ok
end
def readme
if params[:filepath].present?
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
else
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
end
@readme = result[:status] === :success ? result[:body] : nil
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref])
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha")
rescue
render json: nil
end
def languages
render json: languages_precentagable
end
def archive
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}"
file_path = [domain, api_url, archive_url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
return render_not_found if !request.format.zip? && !request.format.gzip?
redirect_to file_path
end
def raw
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{params[:filepath]}?ref=#{params[:ref]}"
file_path = [domain, api_url, url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") if @repository.hidden?
redirect_to URI.escape(file_path)
end
private
def find_project
@project = Project.find params[:id]
render_not_found("未找到相关的仓库") unless @project
end
def find_project_with_includes
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
end
def authorizate!
return if current_user && current_user.admin?
if @project.repository.hidden? && !@project.member?(current_user)
render_forbidden
end
end
# TODO 获取最新commit信息
def project_commits
if params[:filepath].present?
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri,
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
else
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
end
end
def get_statistics
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
end
def get_ref
@ref = params[:ref] || @project&.default_branch
end
def get_latest_commit
latest_commit = @project.educoder? ? nil : project_commits
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
end
def content_params
{
filepath: params[:filepath],
branch: params[:branch],
new_branch: params[:new_branch],
content: params[:content],
message: params[:message],
committer: {
email: current_user.mail,
name: current_user.login
},
identifier: @project.identifier
}
end
def hook_params(hook_type, params)
# if hook_type == "push"
# # TODO hook返回的记录中暂时没有文件代码数量的增减暂时根据 commits数量来计算
# uploadPushInfo = {
# "sha": params["commits"].present? ? params["commits"].last : "",
# "branch": params["ref"].to_s.split("/").last,
# "modification_lines": params["commits"].length
# }
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
# uploadPushInfo = {
# "branch": params["base"]["ref"].to_s.split("/").last,
# "sha": params["pull_request"]["merge_base"],
# "modification_lines": 1 #pull_request中没有commits数量
# }
# else
# uploadPushInfo = {}
# end
# uploadPushInfo
end
def create_new_pr(params)
if params[:new_branch].present? && params[:new_branch] != params[:branch]
local_params = {
title: params[:message], #标题
body: params[:content], #内容
head: params[:new_branch], #源分支
base: params[:branch], #目标分支
milestone: 0 #里程碑,未与本地的里程碑关联
}
requests_params = local_params.merge({
assignee: current_user.try(:login),
assignees: [],
labels: [],
due_date: Time.now
})
issue_params = {
author_id: current_user.id,
project_id: @project.id,
subject: params[:message],
description: params[:content],
assigned_to_id: nil,
fixed_version_id: nil,
issue_tags_value: nil,
issue_classify: "pull_request",
issue_type: "1",
tracker_id: 2,
status_id: 1,
priority_id: params[:priority_id] || "2"
}
@pull_issue = Issue.new(issue_params)
if @pull_issue.save!
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end
end
end
end
end
end
class RepositoriesController < ApplicationController
include ApplicationHelper
include OperateProjectAbilityAble
include Repository::LanguagesPercentagable
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]
def files
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
render json: result
end
# 新版项目详情
def detail
@user = current_user
@result = Repositories::DetailService.call(@owner, @repository, @user)
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@fork_project_user = @fork_project.owner
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show
@user = current_user
@repo = @project.repository
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@fork_project_user = @fork_project.owner
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def entries
Rails.logger.info("request.base_url=========#{request.base_url}")
puts "request.base_url=========#{request.base_url}"
@project.increment!(:visits)
if @project.educoder?
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
else
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
# TODO
# 临时处理readme文件问题
result = Gitea::Repository::Readme::GetService.call(@owner.login, @project.identifier, @ref, @owner&.gitea_token)
@readme =
if result[:status] == :success
result[:body]
else
{}
end
end
end
def top_counts
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
end
def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
if @project.educoder?
if params[:type] === 'file'
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
logger.info "######### sub_entries: #{@sub_entries}"
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
tmp_entries = [{
"content" => @sub_entries['data']['content'],
"type" => "blob"
}]
@sub_entries = {
"trees"=>tmp_entries,
"commits" => [{}]
}
else
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
end
else
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success?
result = interactor.result
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
else
render_error(interactor.error)
end
end
end
def commits
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
end
def commit
@sha = params[:sha]
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true})
end
def tags
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
end
def contributors
@contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
end
def edit
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
end
def create_file
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
if interactor.success?
@file = interactor.result
# create_new_pr(params)
#如果是更新流水线文件
if params[:pipeline_id]
update_pipeline(params[:pipeline_id])
end
else
render_error(interactor.error)
end
end
def update_pipeline(pipeline_id)
pipeline = Ci::Pipeline.find(pipeline_id)
if pipeline
pipeline.update!(sync: 1)
end
end
def update_file
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
# TODO: 是否创建pr
# create_new_pr(params)
render_result(1, "更新成功")
else
render_error(interactor.error)
end
end
def delete_file
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
render_result(1, "文件删除成功")
else
render_error(interactor.error)
end
end
def repo_hook
end
def sync_mirror
return render_error("正在镜像中..") if @repository.mirror.waiting?
@repository.sync_mirror!
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
render_ok
end
def readme
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
@readme = result[:status] === :success ? result[:body] : nil
render json: @readme
end
def languages
render json: languages_precentagable
end
def archive
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}"
file_path = [domain, api_url, archive_url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
Rails.logger.info("file_path======================#{file_path}")
return render_not_found if !request.format.zip? && !request.format.gzip?
redirect_to file_path
end
def sonarqube
@sonarqubes = @project.sonarqubes
branches = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
branches.each do |branch|
sonarqube = @sonarqubes.find_by(branch_name: branch['name'])
file_num = 0
entries = Gitea::Repository::Entries::ListService.call(@owner, @project.identifier, ref: branch['name'])
file_num += entries.size
entries.each do |entry|
file_path_uri = URI.parse(URI.encode(entry['path'].to_s.strip))
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: branch['name'])
if interactor.success?
result = interactor.result
while result.is_a?(Array)
file_num += result.size
result.each do |res|
file_path_uri = URI.parse(URI.encode(res['path'].to_s.strip))
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: branch['name'])
result = interactor.result
end
end
end
end
if sonarqube
sonarqube.update(bug_num: 0, loophole: 0, repetition_rate: 0, file_num: file_num, created_at: Time.now)
sleep 3.seconds
sonarqube.update_column(:updated_at, Time.now)
else
@project.sonarqubes.create!(
branch_name: branch['name'],
bug_num: 0,
loophole: 0,
repetition_rate: 0,
file_num: file_num
)
end
end
end
private
def find_project
@project = Project.find params[:id]
render_not_found("未找到相关的仓库") unless @project
end
def find_project_with_includes
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
end
def authorizate!
return if current_user && current_user.admin?
if @project.repository.hidden? && !@project.member?(current_user)
render_forbidden
end
end
# TODO 获取最新commit信息
def project_commits
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
end
def get_statistics
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
end
def get_ref
@ref = params[:ref] || @project&.default_branch
end
def get_latest_commit
latest_commit = @project.educoder? ? nil : project_commits
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
end
def content_params
{
filepath: params[:filepath],
branch: params[:branch],
new_branch: params[:new_branch],
content: params[:content],
message: params[:message],
committer: {
email: current_user.mail,
name: current_user.login
},
identifier: @project.identifier
}
end
def hook_params(hook_type, params)
# if hook_type == "push"
# # TODO hook返回的记录中暂时没有文件代码数量的增减暂时根据 commits数量来计算
# uploadPushInfo = {
# "sha": params["commits"].present? ? params["commits"].last : "",
# "branch": params["ref"].to_s.split("/").last,
# "modification_lines": params["commits"].length
# }
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
# uploadPushInfo = {
# "branch": params["base"]["ref"].to_s.split("/").last,
# "sha": params["pull_request"]["merge_base"],
# "modification_lines": 1 #pull_request中没有commits数量
# }
# else
# uploadPushInfo = {}
# end
# uploadPushInfo
end
def create_new_pr(params)
if params[:new_branch].present? && params[:new_branch] != params[:branch]
local_params = {
title: params[:message], #标题
body: params[:content], #内容
head: params[:new_branch], #源分支
base: params[:branch], #目标分支
milestone: 0 #里程碑,未与本地的里程碑关联
}
requests_params = local_params.merge({
assignee: current_user.try(:login),
assignees: [],
labels: [],
due_date: Time.now
})
issue_params = {
author_id: current_user.id,
project_id: @project.id,
subject: params[:message],
description: params[:content],
assigned_to_id: nil,
fixed_version_id: nil,
issue_tags_value: nil,
issue_classify: "pull_request",
issue_type: "1",
tracker_id: 2,
status_id: 1,
priority_id: params[:priority_id] || "2"
}
@pull_issue = Issue.new(issue_params)
if @pull_issue.save!
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
if gitea_request[:status] == :success && local_requests.update_attributes(gitea_number: gitea_request["body"]["number"])
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end
end
end
end
end
end

View File

@ -4,7 +4,7 @@ class SettingsController < ApplicationController
get_add_menu
get_common_menu
get_personal_menu
get_top_system_notification
end
private
@ -40,10 +40,6 @@ class SettingsController < ApplicationController
end
end
def get_top_system_notification
@top_system_notification = SystemNotification.is_top.first
end
def get_site_url(key, value)
key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value)
end

View File

@ -0,0 +1,33 @@
class SonarTasksController < ApplicationController
before_action :require_login
before_action :load_project
before_action :authenticate_user!
def index
@sonar_task = SonarTask.find_by(project_id: @project.id)
normal_status(-1, "未检测") if @sonar_task.blank?
end
def create
Sonar::ApiService.call(@project.id)
render_ok
end
def type_detail
service = Sonar::ApiService.new(@project.id)
@data = service.type_detail(params[:task_id], params[:type])
end
def code_source
service = Sonar::ApiService.new(@project.id)
@data = service.source_code(params[:task_id], params[:component])
Rails.logger.info "data=======#{@data}"
end
private
def authenticate_user!
return if @project.member?(current_user) || current_user.admin?
render_forbidden('你没有权限操作')
end
end

View File

@ -1,8 +0,0 @@
class TemplateMessageSettingsController < ApplicationController
before_action :require_login
def index
@group_settings = TemplateMessageSetting.group(:type).count
end
end

View File

@ -1,24 +0,0 @@
class UserRankController < ApplicationController
# 根据时间获取热门开发者
def index
$redis_cache.zunionstore("recent-days-user-rank", get_timeable_key_names)
@user_rank = $redis_cache.zrevrange("recent-days-user-rank", 0, 3, withscores: true)
rescue Exception => e
@user_rank = []
end
private
# 默认显示7天的
def time
params.fetch(:time, 7).to_i
end
def get_timeable_key_names
names_array = []
(0...time).to_a.each do |i|
date_time_string = (Date.today - i.days).to_s
names_array << "v2-user-rank-#{date_time_string}"
end
names_array
end
end

View File

@ -5,7 +5,7 @@ class Users::BaseController < ApplicationController
helper_method :observed_logged_user?, :observed_user
def observed_user
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
@_observed_user ||= (User.find_by_id(params[:user_id]) || User.find_by_login(params[:user_id]))
end
def observed_logged_user?

View File

@ -1,7 +1,7 @@
class Users::HeadmapsController < Users::BaseController
def index
result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp)
@headmaps = result[2].blank? ? [] : result[2]
@headmaps = result[2]
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)

View File

@ -1,96 +0,0 @@
class Users::MessagesController < Users::BaseController
before_action :private_user_resources!
before_action :find_receivers, only: [:create]
def index
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
result = Notice::Read::ListService.call(observed_user.id, message_type, message_status, page, limit)
return render_error if result.nil?
@data = result[2]
end
def create
return render_forbidden unless %w(atme).include?(params[:type])
case params[:type]
when 'atme'
Notice::Write::CreateAtmeForm.new(atme_params).validate!
case atme_params[:atmeable_type]
when 'Issue'
SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
when 'PullRequest'
SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
when 'Journal'
journal = Journal.find_by_id(atme_params[:atmeable_id])
if journal.present?
if journal&.issue&.pull_request.present?
SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
else
SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
end
end
end
end
render_ok
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def delete
return render_forbidden unless %w(atme).include?(params[:type])
result = Notice::Write::DeleteService.call(params[:ids], observed_user.id, message_type)
return render_error if result.nil?
render_ok
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def read
return render_forbidden unless %w(notification atme).include?(params[:type])
result = Notice::Write::ChangeStatusService.call(params[:ids], observed_user.id, message_type)
if result.nil?
render_error
else
render_ok
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def message_type
@message_type = begin
case params[:type]
when "notification" then 1
when "atme" then 2
else
-1
end
end
end
def message_status
@message_status = begin
case params[:status]
when "1" then 1
when "2" then 2
else
-1
end
end
end
def atme_params
params.permit(:atmeable_type, :atmeable_id, receivers_login: [])
end
def find_receivers
@receivers = User.where(login: params[:receivers_login])
return render_not_found if @receivers.size == 0
end
end

View File

@ -14,7 +14,7 @@ class Users::StatisticsController < Users::BaseController
@date_data << date.strftime("%Y.%m.%d")
@issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size
@pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size
date_commit_data = commit_data.blank? ? nil : commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
@commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i)
end
render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data}
@ -188,32 +188,30 @@ class Users::StatisticsController < Users::BaseController
@project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count
@platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count
else
@platform_result = Cache::V2::PlatformStatisticService.new.read
@user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
# 用户被follow数量
@follow_count = @user_result["follow-count"].to_i
@platform_follow_count = @platform_result["follow-count"].to_i
@follow_count = Cache::UserFollowCountService.call(observed_user)
@platform_follow_count = Cache::PlatformFollowCountService.call
# 用户pr数量
@pullrequest_count = @user_result["pullrequest-count"].to_i
@platform_pullrequest_count = @platform_result["pullrequest-count"].to_i
@pullrequest_count = Cache::UserPullrequestCountService.call(observed_user)
@platform_pullrequest_count = Cache::PlatformPullrequestCountService.call
# 用户issue数量
@issues_count = @user_result["issue-count"].to_i
@platform_issues_count = @platform_result["issue-count"].to_i
@issues_count = Cache::UserIssueCountService.call(observed_user)
@platform_issues_count = Cache::PlatformIssueCountService.call
# 用户总项目数
@project_count = @user_result["project-count"].to_i
@platform_project_count = @platform_result["project-count"].to_i
@project_count = Cache::UserProjectCountService.call(observed_user)
@platform_project_count = Cache::PlatformProjectCountService.call
# 用户项目被fork数量
@fork_count = @user_result["fork-count"].to_i
@platform_fork_count = @platform_result["fork-count"].to_i
@fork_count = Cache::UserProjectForkCountService.call(observed_user)
@platform_fork_count = Cache::PlatformProjectForkCountService.call
# 用户项目关注数
@project_watchers_count = @user_result["project-watcher-count"].to_i
@platform_project_watchers_count = @platform_result["project-watcher-count"].to_i
@project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user)
@platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call
# 用户项目点赞数
@project_praises_count = @user_result["project-praise-count"].to_i
@platform_project_praises_count = @platform_result["project-praise-count"].to_i
@project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user)
@platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call
# 用户不同语言项目数量
@project_languages_count = JSON.parse(@user_result["project-language"])
@platform_project_languages_count = JSON.parse(@platform_result["project-language"])
@project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user)
@platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call
end
end
end

View File

@ -1,15 +0,0 @@
class Users::SystemNotificationHistoriesController < Users::BaseController
before_action :private_user_resources!, only: [:create]
def create
@history = observed_user.system_notification_histories.new(system_notification_id: params[:system_notification_id])
if @history.save
render_ok
else
Rails.logger.info @history.errors.as_json
render_error(@history.errors.full_messages.join(","))
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end

View File

@ -1,36 +0,0 @@
class Users::TemplateMessageSettingsController < Users::BaseController
before_action :check_auth
before_action :get_current_setting
def current_setting
end
def update_setting
Rails.logger.info setting_params[:notification_body]
Rails.logger.info setting_params[:email_body]
@current_setting.notification_body = setting_params[:notification_body].to_hash
@current_setting.email_body = setting_params[:email_body].to_hash
return render_error("保存失败") unless @current_setting.save!
end
private
def check_auth
return render_forbidden unless current_user.admin? || observed_logged_user?
end
def get_current_setting
@current_setting = @_observed_user.user_template_message_setting
@current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil?
end
def setting_params
params.require(:setting).permit(notification_body: {}, email_body: {})
end
def valid_setting_params
setting_params[:notification_body].keys.equal?(UserTemplateMessageSetting.init_notification_body.keys) && setting_params[:email_body].keys.equal?(UserTemplateMessageSetting.init_email_body)
end
end

View File

@ -4,7 +4,7 @@ class UsersController < ApplicationController
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me list sync_user_info]
before_action :require_login, only: %i[me list]
before_action :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update]
skip_before_action :check_sign, only: [:attachment_show]
@ -51,8 +51,6 @@ class UsersController < ApplicationController
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size
# 为了缓存活跃用户的基本信息,后续删除
Cache::V2::OwnerCommonService.new(@user.id).read
end
def watch_users
@ -76,7 +74,7 @@ class UsersController < ApplicationController
end
def update
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
Util.write_file(@image, avatar_path(@user)) if user_params[:image].present?
@user.attributes = user_params.except(:image)
@ -93,12 +91,6 @@ class UsersController < ApplicationController
def get_user_info
begin
@user = current_user
begin
result = Notice::Read::CountService.call(current_user.id)
@message_unread_total = result.nil? ? 0 : result[2]["unread_notification"]
rescue
@message_unread_total = 0
end
# TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
rescue Exception => e
@ -193,7 +185,7 @@ class UsersController < ApplicationController
def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = []
domain_url = EduSetting.get('host_name')
domain_url = EduSetting.get('host_name') + '/projects'
if projects.present?
projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}"
@ -262,23 +254,58 @@ class UsersController < ApplicationController
render_ok
end
def sync_user_info
# TODO: For Educoder
def change_password
user = User.find_by_login params[:login]
return render_forbidden unless user === current_user
form_params= {
login: params[:login],
email: user&.mail,
password: params[:password],
user: user
}
Gitea::User::ChangePasswordForm.new(form_params).validate!
sync_params = {
email: params[:email],
email: user&.mail,
password: params[:password]
}
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate!
if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(password: params[:password], is_sync_pwd: true)
render_ok
else
render_error(interactor.error)
end
end
end
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO)
render_ok
else
render_error(interactor.error)
# TODO: For Educoder
def change_email
user = User.find_by_login params[:login]
form_params= {
login: params[:login],
email: user&.mail,
user: user
}
Gitea::User::ChangeEmailForm.new(form_params).validate!
sync_params = {
email: params[:email]
}
if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(mail: params[:email])
render_ok
else
render_error(interactor.error)
end
end
end

View File

@ -1,14 +1,14 @@
class VersionReleasesController < ApplicationController
before_action :load_repository
before_action :set_user
before_action :require_login, except: [:index, :show]
before_action :check_release_authorize, except: [:index, :show]
before_action :find_version , only: [:show, :edit, :update, :destroy]
before_action :require_login, except: [:index]
before_action :find_version , only: [:edit, :update, :destroy]
def index
@version_releases = kaminari_paginate(@repository.version_releases.order(created_at: :desc))
@user_permission = current_user.present? && (@repository.project.all_developers.include?(current_user) || current_user.admin?)
@user_admin_permission = current_user.present? && (@repository.project.all_managers.include?(current_user) || current_user.admin?)
version_releases = Gitea::Versions::ListService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier)).call
@version_releases = version_releases
@user_permission = current_user.present? && (current_user == @user || current_user.admin?)
@forge_releases = @repository.version_releases.select(:id,:version_gid, :created_at).includes(:attachments)
end
def new
@ -22,10 +22,6 @@ class VersionReleasesController < ApplicationController
end
end
def show
# @release = Gitea::Versions::GetService.call(current_user.gitea_token, @user&.login, @repository&.identifier, @version&.version_gid)
end
def create
if params[:name].nil?
normal_status(-1, "名称不能为空")
@ -41,14 +37,13 @@ class VersionReleasesController < ApplicationController
version_params = releases_params
version_release = VersionRelease.new(version_params.merge(user_id: current_user.id, repository_id: @repository.id))
if version_release.save!
git_version_release = Gitea::Versions::CreateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params).call
git_version_release = Gitea::Versions::CreateService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params).call
if git_version_release
update_params = {
tarball_url: git_version_release["tarball_url"],
zipball_url: git_version_release["zipball_url"],
url: git_version_release["url"],
version_gid: git_version_release["id"],
sha: git_version_release["sha"]
}
version_release.update_attributes!(update_params)
version_release.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
@ -86,7 +81,7 @@ class VersionReleasesController < ApplicationController
if @version.update_attributes!(version_params)
create_attachments(params[:attachment_ids], @version) if params[:attachment_ids].present?
git_version_release = Gitea::Versions::UpdateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call
git_version_release = Gitea::Versions::UpdateService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call
unless git_version_release
raise Error, "更新失败"
end
@ -107,7 +102,7 @@ class VersionReleasesController < ApplicationController
ActiveRecord::Base.transaction do
begin
if @version.destroy
git_version_release = Gitea::Versions::DeleteService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), @version.try(:version_gid)).call
git_version_release = Gitea::Versions::DeleteService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), @version.try(:version_gid)).call
if git_version_release.status == 204
normal_status(0, "删除成功")
@ -162,8 +157,4 @@ class VersionReleasesController < ApplicationController
end
end
def check_release_authorize
return render_forbidden("您没有权限进行此操作.") unless current_user.admin? || @project.manager?(current_user)
end
end

View File

@ -1,12 +1,11 @@
class VersionsController < ApplicationController
before_action :require_login, except: [:index, :show]
before_action :require_profile_completed, only: [:create]
before_action :load_repository
before_action :check_menu_authorize
before_action :check_issue_permission, except: [:show, :index]
before_action :set_version, only: [:edit, :update, :destroy, :show,:update_status]
def index
return render_not_found unless @project.has_menu_permission("versions")
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
status = params[:status]
versions = @project.versions.version_includes
@ -183,8 +182,4 @@ class VersionsController < ApplicationController
%w(desc asc).include?(params[:order_type]) ? params[:order_type] : 'desc'
end
def check_menu_authorize
return render_not_found unless @project.has_menu_permission("versions")
end
end

View File

@ -1,6 +1,5 @@
class WatchersController < ApplicationController
before_action :require_login, except: %i[index]
before_action :require_profile_completed, only: [:follow]
# before_action :find_project_with_id
before_action :get_target

View File

@ -0,0 +1,5 @@
module CourseDecorator
def can_visited?
is_public == 1 || User.current.admin_or_business? || User.current.member_of_course?(self)
end
end

View File

@ -0,0 +1,2 @@
module EcCourseTargetDecorator
end

View File

@ -0,0 +1,16 @@
module ExperienceDecorator
def container_type_text
I18n.t("experience.container_type.#{container_type.to_s.underscore}")
end
def content
case container_type.to_s.underscore
when 'game' then
game = Game.find_by(id: container_id)
game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
when 'shixun_publish' then
shixun = Shixun.find_by(id: container_id)
shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
end
end
end

View File

@ -0,0 +1,39 @@
module GradeDecorator
def container_type_text
I18n.t("grade.container_type.#{container_type.to_s.underscore}")
end
def content
case container_type.to_s.underscore
when 'avatar' then '用户首次上传头像获得的奖励'
when 'phone' then '用户首次绑定手机号码获得的奖励'
when 'mail' then '用户首次绑定邮箱获得的奖励'
when 'attendance' then '用户每天签到获得的奖励'
when 'account' then '新用户首次填写基本资料获得的奖励'
when 'memo' then '发布的评论或者帖子获得平台奖励'
when 'discusses' then '发布的评论获得平台奖励'
when 'star' then '用户给实训评分获得的随机奖励'
when 'feedback' then '反馈的问题获得平台奖励'
when 'authentication' then '用户首次完成实名认证获得的奖励'
when 'professional' then '用户首次完成职业认证获得的奖励'
when 'answer' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的参考答案消耗的金币" : ''
when 'game' then
game = Game.find_by(id: container_id)
game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
when 'test_set' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关的隐藏测试集消耗的金币" : ''
when 'shixun_publish' then
shixun = Shixun.find_by(id: container_id)
shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
when 'check_ta_answer' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : ''
when 'hack' then
hack = Hack.find_by(id: container_id)
hack.present? ? "完成了题目解答“#{hack.name}”,获得金币奖励:#{hack.score}" : ''
end
end
end

View File

@ -0,0 +1,5 @@
module LibraryDecorator
extend ApplicationDecorator
display_time_method :published_at, :created_at, :updated_at
end

View File

@ -0,0 +1,5 @@
module ShixunDecorator
def human_status
I18n.t("shixun.status.#{status}")
end
end

View File

@ -0,0 +1,5 @@
module SubjectDecorator
def can_visited?
published? || User.current.admin? || member?(User.current)
end
end

View File

@ -0,0 +1,5 @@
module VideoDecorator
extend ApplicationDecorator
display_time_method :published_at, :created_at, :updated_at
end

View File

@ -1,2 +0,0 @@
build/
.github/

View File

@ -1,18 +0,0 @@
# EditorConfig is awesome: https://EditorConfig.org
# Top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.rb]
charset = utf-8
[*.md]
trim_trailing_whitespace = false

View File

@ -1 +0,0 @@
source/javascripts/lib/* linguist-vendored

View File

@ -1,22 +0,0 @@
---
name: Report a Bug
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Bug Description**
A clear and concise description of what the bug is and how to reproduce it.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Browser (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Last upstream Slate commit (run `git log --author="Robert Lord" | head -n 1`):**
Put the commit hash here

View File

@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Questions, Ideas, Discussions
url: https://github.com/slatedocs/slate/discussions
about: Ask and answer questions, and propose new features.

View File

@ -1,5 +0,0 @@
<!--
⚠️ 🚨 ⚠️ STOP AND READ THIS ⚠️ 🚨 ⚠️
👆👆 see that 'base fork' dropdown above? You should change it! The default value of "slatedocs/slate" submits your change to ALL USERS OF SLATE, not just your company. This is PROBABLY NOT WHAT YOU WANT.
-->

View File

@ -1,42 +0,0 @@
name: Build
on:
push:
branches: [ '*' ]
pull_request:
branches: [ '*' ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: [2.3, 2.4, 2.5, 2.6, 2.7]
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
- uses: actions/cache@v2
with:
path: vendor/bundle
key: gems-${{ runner.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
gems-${{ runner.os }}-${{ matrix.ruby-version }}-
gems-${{ runner.os }}-
# necessary to get ruby 2.3 to work nicely with bundler vendor/bundle cache
# can remove once ruby 2.3 is no longer supported
- run: gem update --system
- run: bundle config set deployment 'true'
- name: bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- run: bundle exec middleman build

View File

@ -1,41 +0,0 @@
name: Deploy
on:
push:
branches: [ 'main' ]
jobs:
deploy:
runs-on: ubuntu-latest
env:
ruby-version: 2.5
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ env.ruby-version }}
- uses: actions/cache@v2
with:
path: vendor/bundle
key: gems-${{ runner.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
gems-${{ runner.os }}-${{ matrix.ruby-version }}-
gems-${{ runner.os }}-
- run: bundle config set deployment 'true'
- name: bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- run: bundle exec middleman build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
keep_files: true

View File

@ -1,50 +0,0 @@
name: Dev Deploy
on:
push:
branches: [ 'dev' ]
jobs:
deploy:
runs-on: ubuntu-latest
env:
ruby-version: 2.5
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ env.ruby-version }}
- uses: actions/cache@v2
with:
path: vendor/bundle
key: gems-${{ runner.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
gems-${{ runner.os }}-${{ matrix.ruby-version }}-
gems-${{ runner.os }}-
- run: bundle config set deployment 'true'
- name: bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- run: bundle exec middleman build
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_KEY }}
repository: slatedocs/slate
tag_with_ref: true
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.0-8
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
destination_dir: dev
publish_dir: ./build
keep_files: true

View File

@ -1,22 +0,0 @@
name: Publish Docker image
on:
release:
types: [published]
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_KEY }}
repository: slatedocs/slate
tag_with_ref: true
tags: latest

View File

@ -1,27 +0,0 @@
*.gem
*.rbc
.bundle
.config
coverage
InstalledFiles
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
*.DS_STORE
build/
.cache
.vagrant
.sass-cache
# YARD artifacts
.yardoc
_yardoc
doc/
.idea/
# Vagrant artifacts
ubuntu-*-console.log

View File

@ -1,254 +0,0 @@
# Changelog
## Version 2.8.0
*October 27, 2020*
* Remove last trailing newline when using the copy code button
* Rework docker image and make available at slatedocs/slate
* Improve Dockerfile layout to improve caching (thanks @micvbang)
* Bump rouge from 3.20 to 3.24
* Bump nokogiri from 1.10.9 to 1.10.10
* Bump middleman from 4.3.8 to 4.3.11
* Bump lunr.js from 2.3.8 to 2.3.9
## Version 2.7.1
*August 13, 2020*
* __[security]__ Bumped middleman from 4.3.7 to 4.3.8
_Note_: Slate uses redcarpet, not kramdown, for rendering markdown to HTML, and so was unaffected by the security vulnerability in middleman.
If you have changed slate to use kramdown, and with GFM, you may need to install the `kramdown-parser-gfm` gem.
## Version 2.7.0
*June 21, 2020*
* __[security]__ Bumped rack in Gemfile.lock from 2.2.2 to 2.2.3
* Bumped bundled jQuery from 3.2.1 to 3.5.1
* Bumped bundled lunr from 0.5.7 to 2.3.8
* Bumped imagesloaded from 3.1.8 to 4.1.4
* Bumped rouge from 3.17.0 to 3.20.0
* Bumped redcarpet from 3.4.0 to 3.5.0
* Fix color of highlighted code being unreadable when printing page
* Add clipboard icon for "Copy to Clipboard" functionality to code boxes (see note below)
* Fix handling of ToC selectors that contain punctutation (thanks @gruis)
* Fix language bar truncating languages that overflow screen width
* Strip HTML tags from ToC title before displaying it in title bar in JS (backup to stripping done in Ruby code) (thanks @atic)
To enable the new clipboard icon, you need to add `code_clipboard: true` to the frontmatter of source/index.html.md.
See [this line](https://github.com/slatedocs/slate/blame/main/source/index.html.md#L19) for an example of usage.
## Version 2.6.1
*May 30, 2020*
* __[security]__ update child dependency activesupport in Gemfile.lock to 5.4.2.3
* Update Middleman in Gemfile.lock to 4.3.7
* Replace Travis-CI with GitHub actions for continuous integration
* Replace Spectrum with GitHub discussions
## Version 2.6.0
*May 18, 2020*
__Note__: 2.5.0 was "pulled" due to a breaking bug discovered after release. It is recommended to skip it, and move straight to 2.6.0.
* Fix large whitespace gap in middle column for sections with codeblocks
* Fix highlighted code elements having a different background than rest of code block
* Change JSON keys to have a different font color than their values
* Disable asset hashing for woff and woff2 elements due to middleman bug breaking woff2 asset hashing in general
* Move Dockerfile to Debian from Alpine
* Converted repo to a [GitHub template](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-template-repository)
* Update sassc to 2.3.0 in Gemfile.lock
## Version 2.5.0
*May 8, 2020*
* __[security]__ update nokogiri to ~> 1.10.8
* Update links in example docs to https://github.com/slatedocs/slate from https://github.com/lord/slate
* Update LICENSE to include full Apache 2.0 text
* Test slate against Ruby 2.5 and 2.6 on Travis-CI
* Update Vagrantfile to use Ubuntu 18.04 (thanks @bradthurber)
* Parse arguments and flags for deploy.sh on script start, instead of potentially after building source files
* Install nodejs inside Vagrantfile (thanks @fernandoaguilar)
* Add Dockerfile for running slate (thanks @redhatxl)
* update middleman-syntax and rouge to ~>3.2
* update middleman to 4.3.6
## Version 2.4.0
*October 19, 2019*
- Move repository from lord/slate to slatedocs/slate
- Fix documentation to point at new repo link, thanks to [Arun](https://github.com/slash-arun), [Gustavo Gawryszewski](https://github.com/gawry), and [Daniel Korbit](https://github.com/danielkorbit)
- Update `nokogiri` to 1.10.4
- Update `ffi` in `Gemfile.lock` to fix security warnings, thanks to [Grey Baker](https://github.com/greysteil) and [jakemack](https://github.com/jakemack)
- Update `rack` to 2.0.7 in `Gemfile.lock` to fix security warnings, thanks to [Grey Baker](https://github.com/greysteil) and [jakemack](https://github.com/jakemack)
- Update middleman to `4.3` and relax constraints on middleman related gems, thanks to [jakemack](https://github.com/jakemack)
- Add sass gem, thanks to [jakemack](https://github.com/jakemack)
- Activate `asset_cache` in middleman to improve cacheability of static files, thanks to [Sam Gilman](https://github.com/thenengah)
- Update to using bundler 2 for `Gemfile.lock`, thanks to [jakemack](https://github.com/jakemack)
## Version 2.3.1
*July 5, 2018*
- Update `sprockets` in `Gemfile.lock` to fix security warnings
## Version 2.3
*July 5, 2018*
- Allows strikethrough in markdown by default.
- Upgrades jQuery to 3.2.1, thanks to [Tomi Takussaari](https://github.com/TomiTakussaari)
- Fixes invalid HTML in `layout.erb`, thanks to [Eric Scouten](https://github.com/scouten) for pointing out
- Hopefully fixes Vagrant memory issues, thanks to [Petter Blomberg](https://github.com/p-blomberg) for the suggestion
- Cleans HTML in headers before setting `document.title`, thanks to [Dan Levy](https://github.com/justsml)
- Allows trailing whitespace in markdown files, thanks to [Samuel Cousin](https://github.com/kuzyn)
- Fixes pushState/replaceState problems with scrolling not changing the document hash, thanks to [Andrey Fedorov](https://github.com/anfedorov)
- Removes some outdated examples, thanks [@al-tr](https://github.com/al-tr), [Jerome Dahdah](https://github.com/jdahdah), and [Ricardo Castro](https://github.com/mccricardo)
- Fixes `nav-padding` bug, thanks [Jerome Dahdah](https://github.com/jdahdah)
- Code style fixes thanks to [Sebastian Zaremba](https://github.com/vassyz)
- Nokogiri version bump thanks to [Grey Baker](https://github.com/greysteil)
- Fix to default `index.md` text thanks to [Nick Busey](https://github.com/NickBusey)
Thanks to everyone who contributed to this release!
## Version 2.2
*January 19, 2018*
- Fixes bugs with some non-roman languages not generating unique headers
- Adds editorconfig, thanks to [Jay Thomas](https://github.com/jaythomas)
- Adds optional `NestingUniqueHeadCounter`, thanks to [Vladimir Morozov](https://github.com/greenhost87)
- Small fixes to typos and language, thx [Emir Ribić](https://github.com/ribice), [Gregor Martynus](https://github.com/gr2m), and [Martius](https://github.com/martiuslim)!
- Adds links to Spectrum chat for questions in README and ISSUE_TEMPLATE
## Version 2.1
*October 30, 2017*
- Right-to-left text stylesheet option, thanks to [Mohammad Hossein Rabiee](https://github.com/mhrabiee)
- Fix for HTML5 history state bug, thanks to [Zach Toolson](https://github.com/ztoolson)
- Small styling changes, typo fixes, small bug fixes from [Marian Friedmann](https://github.com/rnarian), [Ben Wilhelm](https://github.com/benwilhelm), [Fouad Matin](https://github.com/fouad), [Nicolas Bonduel](https://github.com/NicolasBonduel), [Christian Oliff](https://github.com/coliff)
Thanks to everyone who submitted PRs for this version!
## Version 2.0
*July 17, 2017*
- All-new statically generated table of contents
- Should be much faster loading and scrolling for large pages
- Smaller Javascript file sizes
- Avoids the problem with the last link in the ToC not ever highlighting if the section was shorter than the page
- Fixes control-click not opening in a new page
- Automatically updates the HTML title as you scroll
- Updated design
- New default colors!
- New spacings and sizes!
- System-default typefaces, just like GitHub
- Added search input delay on large corpuses to reduce lag
- We even bumped the major version cause hey, why not?
- Various small bug fixes
Thanks to everyone who helped debug or wrote code for this version! It was a serious community effort, and I couldn't have done it alone.
## Version 1.5
*February 23, 2017*
- Add [multiple tabs per programming language](https://github.com/lord/slate/wiki/Multiple-language-tabs-per-programming-language) feature
- Upgrade Middleman to add Ruby 1.4.0 compatibility
- Switch default code highlighting color scheme to better highlight JSON
- Various small typo and bug fixes
## Version 1.4
*November 24, 2016*
- Upgrade Middleman and Rouge gems, should hopefully solve a number of bugs
- Update some links in README
- Fix broken Vagrant startup script
- Fix some problems with deploy.sh help message
- Fix bug with language tabs not hiding properly if no error
- Add `!default` to SASS variables
- Fix bug with logo margin
- Bump tested Ruby versions in .travis.yml
## Version 1.3.3
*June 11, 2016*
Documentation and example changes.
## Version 1.3.2
*February 3, 2016*
A small bugfix for slightly incorrect background colors on code samples in some cases.
## Version 1.3.1
*January 31, 2016*
A small bugfix for incorrect whitespace in code blocks.
## Version 1.3
*January 27, 2016*
We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs.
Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages.
## Version 1.2
*June 20, 2015*
**Fixes:**
- Remove crash on invalid languages
- Update Tocify to scroll to the highlighted header in the Table of Contents
- Fix variable leak and update search algorithms
- Update Python examples to be valid Python
- Update gems
- More misc. bugfixes of Javascript errors
- Add Dockerfile
- Remove unused gems
- Optimize images, fonts, and generated asset files
- Add chinese font support
- Remove RedCarpet header ID patch
- Update language tabs to not disturb existing query strings
## Version 1.1
*July 27, 2014*
**Fixes:**
- Finally, a fix for the redcarpet upgrade bug
## Version 1.0
*July 2, 2014*
[View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed)
**Features:**
- Responsive designs for phones and tablets
- Started tagging versions
**Fixes:**
- Fixed 'unrecognized expression' error
- Fixed #undefined hash bug
- Fixed bug where the current language tab would be unselected
- Fixed bug where tocify wouldn't highlight the current section while searching
- Fixed bug where ids of header tags would have special characters that caused problems
- Updated layout so that pages with disabled search wouldn't load search.js
- Cleaned up Javascript

View File

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@lord.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,12 +0,0 @@
ruby '>=2.3.1'
source 'https://gems.ruby-china.com'
# Middleman
gem 'middleman', '~>4.3'
gem 'middleman-syntax', '~> 3.2'
gem 'middleman-autoprefixer', '~> 2.7'
gem 'middleman-sprockets', '~> 4.1'
gem 'rouge', '~> 3.21'
gem 'redcarpet', '~> 3.5.0'
gem 'nokogiri', '~> 1.10.8'
gem 'sass'

View File

@ -1,136 +0,0 @@
GEM
remote: https://gems.ruby-china.com/
specs:
activesupport (5.2.4.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
autoprefixer-rails (9.5.1.1)
execjs
backports (3.18.2)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.1.7)
contracts (0.13.0)
dotenv (2.7.6)
erubis (2.7.0)
execjs (2.7.0)
fast_blank (1.0.0)
fastimage (2.2.0)
ffi (1.13.1)
haml (5.1.2)
temple (>= 0.8.0)
tilt
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashie (3.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
kramdown (2.3.0)
rexml
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
memoist (0.16.2)
middleman (4.3.11)
coffee-script (~> 2.2)
haml (>= 4.0.5)
kramdown (>= 2.3.0)
middleman-cli (= 4.3.11)
middleman-core (= 4.3.11)
middleman-autoprefixer (2.10.1)
autoprefixer-rails (~> 9.1)
middleman-core (>= 3.3.3)
middleman-cli (4.3.11)
thor (>= 0.17.0, < 2.0)
middleman-core (4.3.11)
activesupport (>= 4.2, < 6.0)
addressable (~> 2.3)
backports (~> 3.6)
bundler
contracts (~> 0.13.0)
dotenv
erubis
execjs (~> 2.0)
fast_blank
fastimage (~> 2.0)
hamster (~> 3.0)
hashie (~> 3.4)
i18n (~> 0.9.0)
listen (~> 3.0.0)
memoist (~> 0.14)
padrino-helpers (~> 0.13.0)
parallel
rack (>= 1.4.5, < 3)
sassc (~> 2.0)
servolux
tilt (~> 2.0.9)
uglifier (~> 3.0)
middleman-sprockets (4.1.1)
middleman-core (~> 4.0)
sprockets (>= 3.0)
middleman-syntax (3.2.0)
middleman-core (>= 3.2)
rouge (~> 3.2)
mini_portile2 (2.4.0)
minitest (5.14.2)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
padrino-helpers (0.13.3.4)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.13.3.4)
tilt (>= 1.4.1, < 3)
padrino-support (0.13.3.4)
activesupport (>= 3.1)
parallel (1.19.2)
public_suffix (4.0.6)
rack (2.2.3)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
redcarpet (3.5.0)
rexml (3.2.4)
rouge (3.24.0)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sassc (2.4.0)
ffi (~> 1.9)
servolux (0.13.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
temple (0.8.2)
thor (1.0.1)
thread_safe (0.3.6)
tilt (2.0.10)
tzinfo (1.2.7)
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
PLATFORMS
ruby
DEPENDENCIES
middleman (~> 4.3)
middleman-autoprefixer (~> 2.7)
middleman-sprockets (~> 4.1)
middleman-syntax (~> 3.2)
nokogiri (~> 1.10.8)
redcarpet (~> 3.5.0)
rouge (~> 3.21)
sass
RUBY VERSION
ruby 2.3.3p222
BUNDLED WITH
2.1.4

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,81 +0,0 @@
<p align="center">
<img src="https://raw.githubusercontent.com/slatedocs/img/main/logo-slate.png" alt="Slate: API Documentation Generator" width="226">
<br>
<a href="https://github.com/slatedocs/slate/actions?query=workflow%3ABuild+branch%3Amain"><img src="https://github.com/slatedocs/slate/workflows/Build/badge.svg?branch=main" alt="Build Status"></a>
</p>
<p align="center">Slate helps you create beautiful, intelligent, responsive API documentation.</p>
<p align="center"><img src="https://raw.githubusercontent.com/slatedocs/img/main/screenshot-slate.png" width=700 alt="Screenshot of Example Documentation created with Slate"></p>
<p align="center"><em>The example above was created with Slate. Check it out at <a href="https://slatedocs.github.io/slate">slatedocs.github.io/slate</a>.</em></p>
Features
------------
* **Clean, intuitive design** — With Slate, the description of your API is on the left side of your documentation, and all the code examples are on the right side. Inspired by [Stripe's](https://stripe.com/docs/api) and [PayPal's](https://developer.paypal.com/webapps/developer/docs/api/) API docs. Slate is responsive, so it looks great on tablets, phones, and even in print.
* **Everything on a single page** — Gone are the days when your users had to search through a million pages to find what they wanted. Slate puts the entire documentation on a single page. We haven't sacrificed linkability, though. As you scroll, your browser's hash will update to the nearest header, so linking to a particular point in the documentation is still natural and easy.
* **Slate is just Markdown** — When you write docs with Slate, you're just writing Markdown, which makes it simple to edit and understand. Everything is written in Markdown — even the code samples are just Markdown code blocks.
* **Write code samples in multiple languages** — If your API has bindings in multiple programming languages, you can easily put in tabs to switch between them. In your document, you'll distinguish different languages by specifying the language name at the top of each code block, just like with GitHub Flavored Markdown.
* **Out-of-the-box syntax highlighting** for [over 100 languages](https://github.com/jneen/rouge/wiki/List-of-supported-languages-and-lexers), no configuration required.
* **Automatic, smoothly scrolling table of contents** on the far left of the page. As you scroll, it displays your current position in the document. It's fast, too. We're using Slate at TripIt to build documentation for our new API, where our table of contents has over 180 entries. We've made sure that the performance remains excellent, even for larger documents.
* **Let your users update your documentation for you** — By default, your Slate-generated documentation is hosted in a public GitHub repository. Not only does this mean you get free hosting for your docs with GitHub Pages, but it also makes it simple for other developers to make pull requests to your docs if they find typos or other problems. Of course, if you don't want to use GitHub, you're also welcome to host your docs elsewhere.
* **RTL Support** Full right-to-left layout for RTL languages such as Arabic, Persian (Farsi), Hebrew etc.
Getting started with Slate is super easy! Simply press the green "use this template" button above and follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](https://slatedocs.github.io/slate/).
Getting Started with Slate
------------------------------
To get started with Slate, please check out the [Getting Started](https://github.com/slatedocs/slate/wiki#getting-started)
section in our [wiki](https://github.com/slatedocs/slate/wiki).
We support running Slate in three different ways:
* [Natively](https://github.com/slatedocs/slate/wiki/Using-Slate-Natively)
* [Using Vagrant](https://github.com/slatedocs/slate/wiki/Using-Slate-in-Vagrant)
* [Using Docker](https://github.com/slatedocs/slate/wiki/Using-Slate-in-Docker)
Companies Using Slate
---------------------------------
* [NASA](https://api.nasa.gov)
* [Sony](http://developers.cimediacloud.com)
* [Best Buy](https://bestbuyapis.github.io/api-documentation/)
* [Travis-CI](https://docs.travis-ci.com/api/)
* [Greenhouse](https://developers.greenhouse.io/harvest.html)
* [WooCommerce](http://woocommerce.github.io/woocommerce-rest-api-docs/)
* [Dwolla](https://docs.dwolla.com/)
* [Clearbit](https://clearbit.com/docs)
* [Coinbase](https://developers.coinbase.com/api)
* [Parrot Drones](http://developer.parrot.com/docs/bebop/)
* [Scale](https://docs.scaleapi.com/)
You can view more in [the list on the wiki](https://github.com/slatedocs/slate/wiki/Slate-in-the-Wild).
Questions? Need Help? Found a bug?
--------------------
If you've got questions about setup, deploying, special feature implementation in your fork, or just want to chat with the developer, please feel free to [start a thread in our Discussions tab](https://github.com/slatedocs/slate/discussions)!
Found a bug with upstream Slate? Go ahead and [submit an issue](https://github.com/slatedocs/slate/issues). And, of course, feel free to submit pull requests with bug fixes or changes to the `dev` branch.
Contributors
--------------------
Slate was built by [Robert Lord](https://lord.io) while at [TripIt](https://www.tripit.com/). The project is now maintained by [Matthew Peveler](https://github.com/MasterOdin) and [Mike Ralphson](https://github.com/MikeRalphson).
Thanks to the following people who have submitted major pull requests:
- [@chrissrogers](https://github.com/chrissrogers)
- [@bootstraponline](https://github.com/bootstraponline)
- [@realityking](https://github.com/realityking)
- [@cvkef](https://github.com/cvkef)
Also, thanks to [Sauce Labs](http://saucelabs.com) for sponsoring the development of the responsive styles.

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