Compare commits

...

573 Commits

Author SHA1 Message Date
xxq250 0c85516a56 贡献者不存在时只显示邮箱 2023-07-18 13:58:14 +08:00
xxq250 f4183a42cf 贡献者不存在时只显示邮箱 2023-07-18 13:51:09 +08:00
xxq250 44dea80793 质量分析运营角色可见 2023-07-07 16:06:27 +08:00
xxq250 52f386802d 质量分析认证老师可见 2023-06-20 10:07:52 +08:00
xxqfamous 0656827d86 增加sidekiq 线程 2023-05-28 22:18:52 +08:00
xxqfamous 2280bf02ac 增加sidekiq失败插件 2023-05-28 22:03:20 +08:00
xxqfamous d0cb7eb269 增加sidekiq失败插件 2023-05-28 21:43:34 +08:00
xxqfamous 7f5e00b516 fixed 复杂文件名称转码Gitea::ClientService 2023-05-19 18:31:55 +08:00
xxqfamous f2a0a22469 fixed 复杂文件名称转码Gitea::ClientService 2023-05-19 18:29:24 +08:00
xxqfamous 489385ffae fixed 复杂文件名称转码Gitea::ClientService 2023-05-19 18:24:23 +08:00
xxqfamous b7c8649507 fixed 复杂文件名称转码Gitea::ClientService 2023-05-19 18:10:37 +08:00
xxqfamous 4fe7196d40 fixed 复杂文件名称转码 2023-05-19 18:04:13 +08:00
xxq250 7a7b93c4af fixed 提交者匹配用户email 2023-05-18 09:12:17 +08:00
xxq250 202d091ff5 fixed 提交者匹配用户email 2023-05-17 21:35:35 +08:00
xxq250 3f1ffcdb34 fixed 提交者匹配用户email 2023-05-17 21:31:32 +08:00
xxq250 bdd9885a41 fixed 提交者匹配用户email 2023-05-17 21:29:03 +08:00
xxq250 3285c89698 fixed 提交者匹配用户,log 2023-05-17 21:22:44 +08:00
xxq250 6afd275814 fixed 提交者匹配用户 2023-05-17 21:18:26 +08:00
xxq250 0fb519c963 fixed 提交者匹配用户 2023-05-17 21:04:37 +08:00
xxq250 0840f632aa Merge remote-tracking branch 'origin/dev_educoder_sync' into dev_educoder_sync 2023-05-17 20:43:21 +08:00
xxq250 59b72f9122 fixed readme权限 2023-05-17 20:40:22 +08:00
xxq250 1201607a39 修改密码方法返回状态判断 2023-03-29 09:34:01 +08:00
xxq250 1ce6070138 修改密码方法返回状态判断 2023-03-29 09:30:40 +08:00
xxq250 cb9230a1a5 修改密码方法返回状态判断 2023-03-29 09:17:54 +08:00
xxq250 a76079ee8e 修改密码方法错误 2023-03-28 21:22:32 +08:00
xxq250 9bd43d80c6 log跟踪 2023-03-12 10:40:17 +08:00
xxq250 f50c9eb9d2 log跟踪 2023-03-12 10:38:07 +08:00
xxq250 89db4e35ac log跟踪 2023-03-12 10:35:42 +08:00
xxq250 9cd4c876ff log跟踪 2023-03-12 10:32:08 +08:00
yystopf ac1a4cc7b7 更改:oauth2取消jwt token 2022-12-11 18:02:57 +08:00
yystopf c475760518 修复 2022-12-11 17:09:46 +08:00
yystopf 88ef03d5d7 更改:oauth_access_token表token的长度 2022-12-11 17:09:14 +08:00
yystopf 3470fa262c 新增:样式打包 2022-12-11 16:11:29 +08:00
yystopf 0fa3361e69 新增:样式打包 2022-12-11 16:11:16 +08:00
yystopf 2191102fa8 修复:移除review引用 2022-12-08 15:09:12 +08:00
yystopf 033d36406e 修复:get_user_info 字段缺失 2022-12-08 15:01:54 +08:00
yystopf 6e62aecbbc 修复:移除代码审查部分migrate 2022-12-08 14:56:02 +08:00
yystopf fb44955a5f 修复:移除代码审查部分model以及controller(表名冲突) 2022-12-08 14:54:41 +08:00
yystopf 6454c375ed 修复:移除oauth2表创建迁移 2022-12-08 14:48:57 +08:00
yystopf 534fdec9f2 merge from develop 2022-12-08 14:28:16 +08:00
yystopf dfa0f1161d Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-12-08 11:52:06 +08:00
yystopf bc6f5cec4d 新增:仓库贡献者行数查询接口 2022-12-08 11:51:59 +08:00
xxq250 ee27c90205 fixed qq命名调整,方便封装 2022-12-06 10:24:48 +08:00
xxq250 534ee80523 Merge remote-tracking branch 'origin/develop' into develop 2022-12-05 17:46:25 +08:00
xxq250 daf7514afe fixed 第三方授权登录配置 2022-12-05 17:46:21 +08:00
yystopf 4b1f1c697e 更改:下载excel文件不走跳转 2022-12-02 13:59:41 +08:00
yystopf 77c7acd582 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-12-02 12:11:30 +08:00
yystopf 025a6a53e9 修复:图片无法下载的问题 2022-12-02 12:11:24 +08:00
xxq250 6b846b10bb fixed 第三方授权登录(github,gitee,qq,wechat) 2022-12-01 17:51:54 +08:00
xxq250 763d7b499e fixed 第三方授权登录(github,gitee,qq,wechat) 2022-12-01 17:22:22 +08:00
yystopf 9b39446dfb 修复:提交文件内容格式由前端决定 2022-11-29 17:08:26 +08:00
yystopf c6e77ac7ee 修复:提交文件未创建新分支时为空判断 2022-11-29 17:02:10 +08:00
yystopf f5cdb6f02d 新增:旧统计接口移除处理 2022-11-29 14:31:14 +08:00
yystopf f7ca03db81 修复:通用分支移除projects_activity表修改 2022-11-28 11:41:36 +08:00
xxq250 8da8b021f6 Merge remote-tracking branch 'origin/develop' into develop 2022-11-28 11:20:01 +08:00
xxq250 70ba78a9b5 fixed 组织用户不存在 2022-11-28 11:19:56 +08:00
yystopf 6191ddd233 修复:通用分支移除声明表修改 2022-11-28 10:57:05 +08:00
xxq250 35cf298f5d fixed 增加emoji表情支持表字段,长度限制 2022-11-25 14:19:05 +08:00
xxq250 ee5d959404 fixed 增加emoji表情支持表字段,长度限制 2022-11-25 14:15:47 +08:00
xxq250 7f47cd8d46 fixed 增加emoji表情支持表字段 2022-11-25 14:09:26 +08:00
xxq250 06c0ac65bf Merge remote-tracking branch 'origin/develop' into develop 2022-11-23 17:58:56 +08:00
xxq250 8f8dab10c3 fixed 增加emoji表情支持 2022-11-23 17:58:51 +08:00
yystopf a6923bf7ed 新增:get_user_info电话号码展示 2022-11-23 17:44:37 +08:00
“xxq250” 667dca0553 Merge remote-tracking branch 'origin/develop' into develop 2022-11-23 17:07:59 +08:00
“xxq250” f23f02cb80 fixed 增加emoji表情支持 2022-11-23 17:07:54 +08:00
yystopf 38a8191b74 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-11-16 15:27:54 +08:00
yystopf e183f48c02 修复:合并请求查询关闭类型须根据合并请求类型查询 2022-11-16 15:27:49 +08:00
“xxq250” a1731f91a9 fixed 附件下载权限 2022-11-15 17:12:10 +08:00
yystopf ea7cf1cd1f 修复:排序字段 2022-11-15 15:17:06 +08:00
yystopf 255b615327 更改:项目首页分类后数量更改 2022-11-15 14:41:08 +08:00
yystopf 64c6f69f56 新增:统计项目分类下私有项目的数量 2022-11-15 14:25:35 +08:00
yystopf 49abadfa3f 新增:合并请求合并之后挂载的issue设置为关闭 2022-11-11 14:13:38 +08:00
yystopf 4cde7c374e 更改:反馈意见编辑器隐藏上传按钮 2022-11-11 14:04:36 +08:00
yystopf b56930b9ab 修复:反馈意见发送邮件失败错误返回 2022-11-11 12:25:25 +08:00
yystopf f98886b3a0 修复 2022-11-11 11:50:07 +08:00
yystopf 30572aa41c 修复:重复代码移除 2022-11-11 11:11:34 +08:00
yystopf ef83697cb8 修复:tooltip闪烁问题 2022-11-10 16:21:43 +08:00
yystopf 570f664c27 修复:标记issue数量问题 2022-11-10 11:02:50 +08:00
yystopf e24921bba3 修复 2022-11-09 14:56:27 +08:00
yystopf e4d62c5335 新增:字符串截取展示 2022-11-09 14:54:43 +08:00
yystopf 6d9cf8aad2 修复 2022-11-09 14:41:17 +08:00
yystopf e3179dfd6e 新增:新增反馈意见邮件回复功能 2022-11-09 14:35:11 +08:00
yystopf 7817487ab7 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-11-09 11:37:18 +08:00
yystopf 83b46fcb50 新增:用户反馈意见后台管理逻辑 2022-11-09 11:37:12 +08:00
“xxq250” 7cc9d207b6 fixed 项目列表查询count优化 2022-11-08 17:18:04 +08:00
“xxq250” abfb62f342 fixed 项目优化排序 2022-11-08 17:16:25 +08:00
“xxq250” ccbbab0741 fixed 项目优化排序 2022-11-08 15:33:12 +08:00
yystopf 3e5c1da2c5 新增:反馈意见模型及接口 2022-11-08 13:27:46 +08:00
yystopf 07aefa79eb 更改:项目后台管理移除精选设置 2022-11-02 14:21:49 +08:00
yystopf 423d5a9316 修复:同步项目权限到组织时需预先判断是否存在于团队中 2022-11-01 15:29:07 +08:00
yystopf 9664ca001e 新增: 邮箱验证码重新发送后之前的验证码需设置为无效 2022-10-27 17:57:55 +08:00
yystopf e15809c186 修复:无法正常转移的问题 2022-10-27 10:48:24 +08:00
yystopf 7d4c0df691 修复 2022-10-27 09:55:55 +08:00
yystopf e72dfa4973 修复:项目迁移设置权限在更改拥有者之后 2022-10-27 09:28:52 +08:00
yystopf 84a8339a04 修复 2022-10-26 15:16:06 +08:00
yystopf 3d5b2e76d7 修复:update_column无法触发count_cache 2022-10-26 14:58:04 +08:00
yystopf 8b14ee3c72 修复:更改组织下项目权限同时更改组织下权限同步至gitea 2022-10-26 14:49:40 +08:00
yystopf 3f7366fbcd 修复:更改用户通知邮箱只能自己改自己的 2022-10-21 15:28:48 +08:00
yystopf cfdbc5a682 修复 2022-10-21 15:07:31 +08:00
yystopf 9b880e3209 修复 2022-10-21 15:04:26 +08:00
yystopf c2ef23b746 修复 2022-10-21 14:42:51 +08:00
yystopf 8a33ea6707 修复 2022-10-21 14:40:43 +08:00
yystopf 9ee4c85b7c 更改:验证返回status以及万能验证码 2022-10-21 14:31:32 +08:00
yystopf e9b23d6577 更改:合并请求代码冲突提示语更改 2022-10-19 16:17:44 +08:00
yystopf 64d9c334ce 修复:项目语言验证信息统一 2022-10-19 15:18:15 +08:00
yystopf cad7e24299 修复:项目列表表头样式 2022-10-18 15:53:37 +08:00
yystopf 3b15dd84fc 新增:标签列表返回总数 2022-10-18 14:52:15 +08:00
yystopf 58a43a8b80 更改:合并请求和issue仅加载开启中的里程碑 2022-10-18 13:43:16 +08:00
yystopf e25231738a 新增:标签名字列表 2022-10-18 13:32:57 +08:00
yystopf 35965f542a 新增:标签名字列表 2022-10-18 13:31:12 +08:00
yystopf fa48e3f5ca 修复:许可证和忽略文件内容为空表单提示 2022-10-18 11:14:35 +08:00
yystopf 13e2738fb5 新增:列表页新增only_watched参数 2022-10-17 17:37:03 +08:00
yystopf 30437d828c 新增:项目git忽略文件新增验证 2022-10-17 13:16:22 +08:00
yystopf dcc7ab6738 更改:项目分类去掉图片上传 2022-10-17 13:01:08 +08:00
yystopf 57a7a17f73 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-10-17 12:57:32 +08:00
yystopf 5196f33f24 新增:项目许可证新增验证 2022-10-17 12:57:24 +08:00
“xxq250” b3cbed2963 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	app/controllers/members_controller.rb
2022-10-17 11:09:48 +08:00
“xxq250” dd1af6712c fixed 项目成员提示修改 2022-10-17 11:08:54 +08:00
yystopf 8807be6e4d 新增:项目语言新增唯一性验证 2022-10-17 10:52:57 +08:00
yystopf 8d41c27044 更改:项目成员添加提示 2022-10-17 10:42:40 +08:00
yystopf 53fe554d1e 更改:后台管理表头样式 2022-10-17 10:25:17 +08:00
“xxq250” 4e02dbe06b Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	app/controllers/attachments_controller.rb
2022-10-17 10:14:13 +08:00
“xxq250” 620ddff9bb fixed issue评论附件权限 2022-10-17 10:13:30 +08:00
yystopf 630a7aadeb 新增:组织数据修复任务 2022-10-15 11:29:23 +08:00
yystopf 6383384287 更改:后台管理用户真实姓名改为昵称 2022-10-14 15:31:20 +08:00
yystopf 83f1263f85 修复:更改查询项目判断条件 2022-10-14 14:52:25 +08:00
yystopf 9c11cd79e8 修复:消息模版无法查询子类的问题 2022-10-10 19:06:47 +08:00
yystopf a7384bc1c3 修复:代码详情页报错 2022-10-08 18:44:04 +08:00
yystopf 55170c7693 新增:更改邮箱相关接口文档 2022-09-29 13:58:14 +08:00
yystopf 2cde13eabb 新增:接口测试以及功能测试 2022-09-29 12:05:57 +08:00
yystopf d68e7f38a3 新增:更改邮箱service逻辑 2022-09-29 09:30:33 +08:00
yystopf 649d9c4ea6 新增:更改邮箱控制器方法 2022-09-28 16:09:10 +08:00
“xxq250” fce8166ba7 fixed 用户活跃数 2022-09-26 16:11:34 +08:00
“xxq250” ae0efc1115 Merge remote-tracking branch 'origin/develop' into develop 2022-09-26 10:38:32 +08:00
“xxq250” dfc2edd62d fixed注册gitea错误信息 2022-09-26 10:38:28 +08:00
“xxq250” fcdbf4ec7f Merge remote-tracking branch 'origin/dev_educoder_sync' into dev_educoder_sync
# Conflicts:
#	app/controllers/concerns/register_helper.rb
2022-09-26 10:32:01 +08:00
“xxq250” 1068168968 fixed注册gitea错误信息 2022-09-26 10:30:50 +08:00
yystopf d7f3a21add 修复:周统计数据需加入年份 2022-09-23 17:56:39 +08:00
yystopf ef9592ef30 更改:活跃度算法更新 2022-09-23 10:28:12 +08:00
yystopf cc42683316 新增:活跃度计算访问量限制 2022-09-23 10:07:52 +08:00
yystopf 70f1e6827f 更改:项目已设置语言,则不重新设置语言 2022-09-21 10:06:29 +08:00
yystopf b5188e3272 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-09-21 09:54:53 +08:00
yystopf ff881732d2 更改:项目已设置语言,则不重新设置语言 2022-09-21 09:54:49 +08:00
“xxq250” 2adf87a289 fixed nps数据统计 2022-09-20 09:52:40 +08:00
“xxq250” 6954a860af fixed nps数据统计 2022-09-20 09:47:29 +08:00
“xxq250” bb8e6aeaf8 nps数据统计 2022-09-20 09:41:27 +08:00
“xxq250” 6d7b7dd058 fixed 修改密码接口 2022-09-19 10:06:49 +08:00
yystopf 007b90c284 修复:删除旧的逻辑 2022-09-15 10:00:00 +08:00
yystopf 481d1b7db0 修复:commit log统计触发规则 2022-09-15 09:57:28 +08:00
yystopf 733f64eaec 新增:项目排行榜新增提交数算法 2022-09-15 09:44:12 +08:00
yystopf 383660c778 更改:组织缓存信息方式改在控制器里面 2022-09-15 09:38:28 +08:00
yystopf 4bd77a870b 更改:webhook创建数量限制为50个 2022-09-08 14:19:08 +08:00
yystopf b1f460d760 更改:webhook创建数量限制为50个 2022-09-08 10:40:52 +08:00
yystopf a438ab6f3e 新增:提示语locale配置 2022-09-06 14:57:54 +08:00
“xxq250” 3a34d8682c Merge remote-tracking branch 'origin/develop' into develop 2022-09-06 10:30:15 +08:00
“xxq250” 60894f00b1 nps已打分区分 2022-09-06 10:29:51 +08:00
“xxq250” 925b05e004 nps已打分区分 2022-09-06 10:29:49 +08:00
yystopf 4878d66620 修复 2022-09-06 09:04:46 +08:00
yystopf 632ade9d25 修复 2022-09-06 09:02:30 +08:00
yystopf 5acd45bf85 修复 2022-09-06 09:00:05 +08:00
yystopf d03b45eecf 新增:创建文件对分支长度进行验证 2022-09-06 08:59:24 +08:00
“xxq250” 32a9d762d8 调整nps用户调研接口,需要登录 2022-08-31 10:39:52 +08:00
“xxq250” 0a79950046 调整nps用户调研接口 2022-08-31 10:38:21 +08:00
“xxq250” 4b7c58b13f Merge remote-tracking branch 'origin/develop' into develop 2022-08-30 18:10:33 +08:00
“xxq250” 7148957368 nps用户调研 2022-08-30 18:10:27 +08:00
yystopf aa50c50254 修复 2022-08-30 10:40:27 +08:00
yystopf 60b3c7925d 新增:添加全部或者移除全部团队项目[文档] 2022-08-30 10:34:37 +08:00
yystopf 0f41cabe71 新增:添加全部或者移除全部团队项目 2022-08-30 10:23:35 +08:00
“xxq250” d04ed7e008 fixed 组织成员列表查询优化 2022-08-29 10:05:56 +08:00
“xxq250” 7993a89ce3 fixed 用户已被注册提示 2022-08-26 15:26:09 +08:00
yystopf 6168256897 修复: diff filepath为空报错 2022-08-22 10:48:05 +08:00
yystopf 4b167dacbb 修复: trace user 手机号为空 2022-08-17 18:39:01 +08:00
yystopf 911c47df8d 新增:文件blame 上个版本的行号 2022-08-17 18:05:15 +08:00
yystopf a37d7b9840 修复: 手机号默认不传 2022-08-17 15:28:58 +08:00
“xxq250” 217ab920a9 fixed commit日志同时更新项目时间 2022-08-16 15:33:15 +08:00
“xxq250” 98ae62d181 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-08-16 14:28:52 +08:00
“xxq250” 98f1723411 fixed 发行版git删除时,不同步处理 2022-08-16 14:28:40 +08:00
yystopf 68a38e75bc 修复: 消息返回接口时间 2022-08-16 14:07:37 +08:00
yystopf ee29c6be5c Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-08-15 15:55:37 +08:00
yystopf c0ee0a694c 更改:代码溯源status改为code 2022-08-15 15:55:33 +08:00
“xxq250” 25fa6f427b Merge remote-tracking branch 'origin/develop' into develop 2022-08-15 14:03:32 +08:00
“xxq250” 467d722d25 fixed reposyncer job任务增加分页 2022-08-15 14:03:27 +08:00
yystopf 3e352d3c7c 新增:获取代码溯源系统维护信息接口 2022-08-12 17:23:19 +08:00
yystopf 13472b2311 新增: 合并请求评论查询is_full 2022-08-11 15:21:11 +08:00
“xxq250” bdddd655bf Merge remote-tracking branch 'origin/develop' into develop 2022-08-11 09:31:49 +08:00
“xxq250” 6ec7a13293 fixed reposyncer 分支组合已配置,不能重复 2022-08-11 09:31:40 +08:00
“xxq250” 716b29c25f fixed 消息模板配置type 2022-08-11 09:29:37 +08:00
“xxq250” 5c4930a362 fixed 消息模板配置type 2022-08-11 09:29:36 +08:00
“xxq250” ad8fed9440 fixed 消息模板配置type 2022-08-11 09:29:35 +08:00
“xxq250” 964bef7896 fixed 消息模板配置type 2022-08-11 09:29:34 +08:00
“xxq250” 7e48e5e8b8 fixed 消息模板配置 2022-08-11 09:29:34 +08:00
“xxq250” 48846a7e31 fixed 已读未读标记优化 2022-08-11 09:29:33 +08:00
yystopf 32db15aad5 新增: commit找不到返回404 2022-08-11 09:29:12 +08:00
“xxq250” 8ec3e4bbaa fixed Gitea::PullRequest::FilesService增加参数 2022-08-11 09:28:12 +08:00
yystopf 4b05838498 新增:合并请求评论新增path参数筛选以及去掉分页最多返回200数据 2022-08-09 09:48:02 +08:00
yystopf b8be0c23cb 修复 2022-08-05 11:05:29 +08:00
yystopf d20a7b1318 修复:项目协作者添加组织成员问题 2022-08-05 10:50:41 +08:00
yystopf f8268accc0 新增: 组织下项目协作者添加当前用户 2022-08-04 17:28:14 +08:00
yystopf a9811768d4 修复: 合并请求评论类型允许为空 2022-08-04 15:46:19 +08:00
yystopf 024bc289de 修改: 合并请求评论必选参数以及审查列表去掉分页 2022-08-03 17:13:45 +08:00
yystopf 96d34d0237 修改:合并请求审查权限 2022-08-03 15:31:04 +08:00
yystopf fea11bdc2e 新增:webhook type类型 2022-08-03 14:20:25 +08:00
yystopf ab5d273f98 新增:版本diff新增diff信息 2022-08-02 19:03:54 +08:00
“xxq250” 8bf4e9b8d2 fixed Repository.url 2022-08-02 18:10:01 +08:00
yystopf 096b0b954d 新增: fork仓库协作者可以提交文件至仓库 2022-08-01 17:14:32 +08:00
yystopf df57312056 修复 2022-07-29 17:29:25 +08:00
“xxq250” f12cfabee3 fixed 精选项目不包含私有仓库 2022-07-28 17:30:09 +08:00
“xxq250” b22909a654 fixed 语言接口token参数错误 2022-07-28 17:20:22 +08:00
“xxq250” 579b45dfa4 fixed 精选项目不包含私有仓库 2022-07-28 17:19:39 +08:00
“xxq250” fbc1f95cd1 Merge remote-tracking branch 'origin/develop' into develop 2022-07-28 16:42:29 +08:00
“xxq250” 4ccf8ea5ff CloudIDEA文件标记已读未读 2022-07-28 16:42:21 +08:00
yystopf d5c141f892 修复:pulls文件夹load 2022-07-28 15:19:31 +08:00
yystopf 35c6cb98db 新增:批量提交文件支持参数选填 2022-07-28 14:25:33 +08:00
yystopf f417e42864 修复: 提示修改 2022-07-28 14:02:37 +08:00
yystopf 6e54203ebb 修复:批量提交文件参数缺失以及数据为空处理 2022-07-28 13:56:31 +08:00
“xxq250” 79a6841bbc Merge remote-tracking branch 'origin/develop' into develop 2022-07-28 09:31:19 +08:00
“xxq250” b3d78741a3 fixed reposyncer同步仓库接口增加gitlink 2022-07-28 09:31:14 +08:00
yystopf 935f3ddf7f Merge pull request '合并请求评论相关接口及文档' (#20) from yystopf/forgeplus:develop into develop 2022-07-27 16:11:17 +08:00
yystopf a2549f7ff1 新增: 评论及审查相关接口文档 2022-07-27 16:07:15 +08:00
yystopf d6b5dc326a 新增: 评论相关api根据需求重写 2022-07-27 14:52:49 +08:00
“xxq250” 003bfe7884 Merge remote-tracking branch 'origin/develop' into develop 2022-07-26 17:08:10 +08:00
“xxq250” df5efa0dc6 fixed 邮箱验证正则优化 2022-07-26 17:08:05 +08:00
yystopf a35db9fe80 新增:reviewers修改入口 2022-07-26 16:45:53 +08:00
yystopf 6183f1f76d 修复: 缺少title和body 2022-07-26 14:38:41 +08:00
yystopf e72273f3b2 修复: 合并请求详情中review需要最新的一个 2022-07-26 14:29:12 +08:00
yystopf cc09f724cc Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-07-26 14:14:33 +08:00
yystopf 7a54c5f536 新增: 接口文档更新 2022-07-26 14:14:25 +08:00
“xxq250” bb3f5cec76 fixed reposyncer同步仓库接口 2022-07-26 11:40:49 +08:00
“xxq250” 19ffd9fea1 fixed PullRequest 统一关联关系字段gitea_id 2022-07-26 10:55:42 +08:00
“xxq250” 5877474f59 Merge remote-tracking branch 'origin/develop' into develop 2022-07-26 10:44:21 +08:00
“xxq250” 1bbde165c2 reposyncer同步仓库接口 2022-07-26 10:44:12 +08:00
yystopf 3f5754a3a5 新增:合并请求详情接口 2022-07-25 18:23:06 +08:00
yystopf 5463c22518 新增: 合并请求创建审查接口 2022-07-25 17:28:38 +08:00
yystopf 5db43bf768 新增:新合并请求列表接口 2022-07-25 16:21:03 +08:00
yystopf 1feb166fd5 修复:合并请求评审模型修改 2022-07-25 16:20:42 +08:00
yystopf 0df1e5fdd0 新增:合并请求版本列表和diff接口文档 2022-07-22 18:08:16 +08:00
yystopf 8ba70a33be 新增: pr版本列表和diff接口 2022-07-22 17:33:08 +08:00
“xxq250” b21f44b59e fixed 代码提交日志根据提交commit记录多次 2022-07-22 10:11:21 +08:00
“xxq250” 1c56f21c96 fixed sonar未检测 2022-07-20 16:19:40 +08:00
yystopf 7793eacf75 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-07-19 16:47:06 +08:00
yystopf 25afedcdfd 新增: 批量更改文件 2022-07-19 16:47:01 +08:00
“xxq250” d95a689815 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-07-19 14:58:29 +08:00
xiaoxiaoqiong b386dc51e4 fixed 后台统计优化,7天时间精确 2022-07-19 14:56:02 +08:00
yystopf 1882120df3 新增: 获取单文件blame信息 2022-07-19 11:14:50 +08:00
yystopf 274cd81655 新增:获取commit列表 2022-07-19 10:41:25 +08:00
yystopf 6273349334 新增: 获取比较blame、token以及异常捕获处理 2022-07-18 15:39:51 +08:00
yystopf e8deb83004 fix: gemfile 2022-07-18 11:20:24 +08:00
yystopf 52701d1c2f Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-07-18 11:18:35 +08:00
yystopf b248f770f1 新增:获取单个提交的blame信息接口以及文档 2022-07-18 11:18:29 +08:00
xiaoxiaoqiong 04b9e43382 fixed 后台统计优化,新增项目数 2022-07-18 11:14:45 +08:00
xiaoxiaoqiong 3580a8653d fixed 后台统计优化,新增项目数 2022-07-18 11:04:57 +08:00
xiaoxiaoqiong d9653e461e fixed 后台统计优化,周存率小数计算 2022-07-18 11:00:47 +08:00
xiaoxiaoqiong d9a1d32ec8 fixed 后台统计优化,周存率 2022-07-18 10:55:41 +08:00
xiaoxiaoqiong b5dfd83527 fix 提交日志提交用户信息不匹配 2022-07-18 10:43:57 +08:00
xiaoxiaoqiong df7b91a8ba gemfile.lock reset 2022-07-18 10:38:45 +08:00
xiaoxiaoqiong 8dae15225e 后台统计优化 2022-07-18 10:37:53 +08:00
xiaoxiaoqiong 5fcf789e63 fixed 提交日志记录用户信息,仓库关联 2022-07-18 09:35:19 +08:00
xiaoxiaoqiong ed0655452c 增加从webhook接收仓库日志记录 2022-07-18 09:34:56 +08:00
yystopf 0dd062ce1c 新增: blobs和文件树接口及文档 2022-07-15 17:03:18 +08:00
yystopf bd3cbf33fd fix 2022-07-15 14:41:00 +08:00
yystopf b8d4b15b40 新增: 分支接口文档 2022-07-15 14:40:35 +08:00
yystopf 24d83133e7 新增: 创建分支接口 2022-07-15 14:02:48 +08:00
yystopf 4ed3a9d478 修复:cherry pick doorkeeper配置 2022-07-14 18:13:06 +08:00
yystopf fbbacfa983 修复: apk文件为下载文件 2022-07-14 09:36:52 +08:00
xiaoxiaoqiong d47708dc1c fixed 代码质量语言不明时-其他 2022-07-12 16:45:34 +08:00
xiaoxiaoqiong 625ed024e2 fixed 代质分析没完成状态时不查详情 2022-07-12 15:57:48 +08:00
xiaoxiaoqiong 60842e64e5 fixed 代质分析没完成状态时不查详情 2022-07-12 15:57:34 +08:00
xiaoxiaoqiong 993135602f fixed 代质分析没完成状态时不查详情 2022-07-12 15:56:44 +08:00
xiaoxiaoqiong 35e8f1d423 fixed 代质分析提示文案 2022-07-12 15:19:01 +08:00
xiaoxiaoqiong dbea2e1c3d fixed 代质分析未完成需要再检测完成,更新时间 2022-07-12 15:13:52 +08:00
xiaoxiaoqiong f1fdf0c37f fixed 代质分析未完成需要再检测完成 2022-07-12 15:09:24 +08:00
yystopf d0988e42b4 新增: 平台接口文档更新 2022-07-08 18:01:07 +08:00
xiaoxiaoqiong ef8f33e1cd 未配置语言根据项目检测更新 2022-07-08 16:33:27 +08:00
xiaoxiaoqiong b380b61873 fixed 代码质量分析 菜单 2022-07-08 14:42:02 +08:00
xiaoxiaoqiong 6730466230 fixed 代码质量分析api utf-8 2022-07-08 13:54:49 +08:00
xiaoxiaoqiong 94d6cac626 fixed 代码质量分析api utf-8 2022-07-08 13:42:36 +08:00
xiaoxiaoqiong 640d841242 fixed 代码质量分析api 2022-07-08 12:42:00 +08:00
xiaoxiaoqiong 6a0066b71c fixed 代码质量分析api 2022-07-08 12:35:08 +08:00
xiaoxiaoqiong aafbb8011b fixed 代码质量分析api 2022-07-08 11:49:07 +08:00
xiaoxiaoqiong 72a87ea909 fixed 代码质量分析api 2022-07-08 11:47:11 +08:00
xiaoxiaoqiong abf909d0e7 fixed 代码质量分析api 2022-07-08 11:46:07 +08:00
xiaoxiaoqiong a2321d5370 fixed 代码质量分析api 2022-07-08 11:43:23 +08:00
yystopf d154f0aecc 修复: readme匹配修复 2022-07-08 11:31:17 +08:00
xiaoxiaoqiong 68e4c8ad5a 代码质量分析api 2022-07-08 10:16:05 +08:00
xiaoxiaoqiong cf533f49cc fixed 接入sonar代码质量分析 2022-07-07 16:19:03 +08:00
yystopf 29d9410e42 修复: readme 匹配项目 2022-07-07 15:02:25 +08:00
xiaoxiaoqiong 2a9a835939 接入sonar代码质量分析 2022-07-07 13:50:21 +08:00
xiaoxiaoqiong d756646b1a 接入sonar代码质量分析 2022-07-07 13:41:14 +08:00
yystopf 3b62f09669 新增: 项目语言匹配并设置 2022-07-07 10:05:12 +08:00
yystopf 5864352049 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-07-07 09:24:18 +08:00
yystopf 1d6d48fc94 新增: pr 最后一次审核展示 2022-07-07 09:24:11 +08:00
xiaoxiaoqiong 484c91a581 fixed 同步gitea密码状态is_sync_pwd更新 2022-07-06 15:26:49 +08:00
yystopf 7b91ad37e5 修复 2022-06-30 16:38:46 +08:00
yystopf 9dbb9a42d6 新增: compare 支持sha对比 2022-06-30 16:33:09 +08:00
yystopf a608803aa8 新增: 合并请求审查需审查权限 2022-06-30 11:00:18 +08:00
yystopf 76cc185a1d 新增: 合并请求审核model 2022-06-29 17:16:29 +08:00
yystopf e76503ae26 fix: gitea client version 2022-06-26 09:06:11 +08:00
yystopf 50991f503f Merge pull request '新增oauth验证接口入口以及webhooks接口' (#14) from yystopf/forgeplus:hh_new_api into develop 2022-06-24 14:16:06 +08:00
yystopf acd031ca7d 修复: gemfile.lock 2022-06-24 14:14:57 +08:00
yystopf b59b76be4a 新增: 更新文档 2022-06-24 11:04:16 +08:00
yystopf 211581cef0 新增: webhooks文档使用新api地址 2022-06-24 09:26:01 +08:00
yystopf 7cad953413 新增: 用户项目列表支持多个参数 2022-06-23 18:16:57 +08:00
yystopf fe58175ee0 新增: webhooks使用token访问的接口 2022-06-23 16:14:00 +08:00
yystopf 5d0849a148 新增: 用户项目列表以及helper方法 2022-06-23 12:19:03 +08:00
yystopf d14bf35ca1 修复: gitea module命名重复问题 2022-06-23 11:33:11 +08:00
yystopf d7dd3901b8 新增: 项目详情 2022-06-22 19:08:14 +08:00
yystopf aefd6c08dc 新增: gitea-client引入以及路由定义 2022-06-21 17:39:11 +08:00
yystopf 3c2c742121 修复: 项目邀请链接生成多次返回提示 2022-06-21 11:37:41 +08:00
yystopf 9221e55752 修复: 邀请链接跳转用户已加入仓库的提示以及项目申请记录只创建一条 2022-06-21 11:18:14 +08:00
yystopf ba1fa8b685 修复: 项目邀请链接私有项目无法访问的情况 2022-06-20 16:37:59 +08:00
yystopf 29e3a55a0c 修复: 项目邀请链接私有项目无法访问的情况 2022-06-20 16:36:01 +08:00
xiaoxiaoqiong c426467a68 Merge remote-tracking branch 'origin/develop' into develop 2022-06-20 15:38:48 +08:00
xiaoxiaoqiong 9fe8df3c1b auth token过期时间7天 2022-06-20 15:38:42 +08:00
yystopf 531495429c 修复: 无法正常更改token长度的问题 2022-06-20 13:05:25 +08:00
yystopf bed2469014 fix: change error 2022-06-20 10:34:25 +08:00
yystopf 45b7f70d9f 新增:项目邀请链接增加时间限制,以及show_link接口新增 2022-06-20 10:16:39 +08:00
yystopf 1ebb6cb561 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-06-20 09:34:29 +08:00
yystopf 21ccedab9c 修复: doorkeeper 无法生成jwt token 2022-06-17 18:33:37 +08:00
xiaoxiaoqiong 8f45bcf959 Merge remote-tracking branch 'origin/develop' into develop 2022-06-17 17:02:31 +08:00
xiaoxiaoqiong 1f9caeece5 auth2接入 2022-06-17 17:02:24 +08:00
yystopf 5b4e6f4902 修复: 项目存在敏感词更新forked数量使用update_column 2022-06-17 14:19:41 +08:00
yystopf 3d0e323801 fix 2022-06-17 14:07:33 +08:00
yystopf f6fb50529c 新增: 邀请项目链接接口文档 2022-06-17 14:06:59 +08:00
yystopf c42f3d5928 新增:邀请用户链接生成 2022-06-17 14:06:59 +08:00
yystopf 42d2b51f7f 修复: 项目敏感词判定只在创建或者更新的时候 2022-06-16 13:42:17 +08:00
xiaoxiaoqiong 66c40d4791 fixed gitea接口返回判断 2022-06-15 11:16:08 +08:00
yystopf ce467736a7 修复: readme无法正常跳转目录的问题 2022-06-13 12:53:40 +08:00
yystopf 3e4dd90e17 修复: 用户名称展示时只去掉首末的空格 2022-06-08 10:46:55 +08:00
yystopf 8ae5587516 fix: search name use strip 2022-06-08 10:37:31 +08:00
xiaoxiaoqiong 0b543f7dda 通知邮件支持用户不存在时发送base_url 2022-06-01 16:08:20 +08:00
xiaoxiaoqiong a07204111a 通知邮件支持用户不存在时发送 2022-06-01 15:24:39 +08:00
yystopf 038df804c0 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-06-01 10:01:15 +08:00
yystopf 877948b0cd 新增: 通用消息模板后台创建 2022-06-01 10:00:57 +08:00
xiaoxiaoqiong 9a17c4865f 项目名称和描述增加敏感词检测 2022-06-01 09:27:18 +08:00
yystopf 9427db3e5a 新增: 通用消息模板 2022-05-31 16:34:08 +08:00
yystopf 81da71d478 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-05-30 14:50:23 +08:00
yystopf 169dc84e22 新增: 组织下项目需返回是否为公有项目字段 2022-05-30 14:50:12 +08:00
xiaoxiaoqiong d6fd85f536 Repository.url重写,导入项目时为空 2022-05-30 11:18:24 +08:00
xiaoxiaoqiong 6448a30e03 render_error替换成tip_exception 2022-05-30 10:25:43 +08:00
xiaoxiaoqiong 17fb43cea8 render_error替换成tip_exception 2022-05-30 10:24:39 +08:00
yystopf a6e50d2a25 修复 devops无法激活项目的问题 2022-05-27 10:48:20 +08:00
yystopf bd16ca476d 增加: 退出仓库api文档 2022-05-26 15:08:42 +08:00
yystopf 3dfe5d5d0f 修复 sync_gitea_params 2022-05-26 10:28:55 +08:00
yystopf eadc517a25 Merge pull request '同步develop最新代码' (#11) from yystopf/forgeplus:dev_educoder_sync into dev_educoder_sync 2022-05-25 17:27:42 +08:00
yystopf 1652e615be 同步develop最新代码 2022-05-25 17:25:21 +08:00
yystopf 2ea78b4f20 增加: 已登录用户对用户名、邮箱、电话进行校验 2022-05-25 11:47:35 +08:00
yystopf e36c7a4b6a 修复: 邮箱搜索不需要return 404 2022-05-24 18:09:36 +08:00
yystopf 8e8ec821f2 新增: 根据邮箱来获取用户 2022-05-24 17:26:10 +08:00
yystopf 5cf257c3cc Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-05-24 11:45:53 +08:00
yystopf aa18fe0ad4 修复: 转移项目时新接受者需要移除原来的权限角色 2022-05-24 11:44:05 +08:00
yystopf 1358c23ca6 fix: trasfer project member must remove old permission 2022-05-24 11:43:47 +08:00
yystopf c27cc063e6 add: new update user info simple and sync gitea 2022-05-24 10:59:52 +08:00
yystopf b0092487e6 fix: is readme use regex 2022-05-23 18:10:41 +08:00
yystopf fbebd0a623 fix 2022-05-23 09:27:09 +08:00
yystopf fe23c2afbf fix: replace content next if blank 2022-05-21 16:45:42 +08:00
yystopf 779c86108a fix: readme relative delay and replace_content 2022-05-20 17:00:02 +08:00
yystopf 83e43f0c97 add: new readme delay function 2022-05-20 11:43:22 +08:00
yystopf e545424b7d fix: project count use count 2022-05-19 15:54:38 +08:00
yystopf e237fd46f7 fix: not found user return 404 2022-05-18 11:37:23 +08:00
yystopf ca3c564529 fix: not found user return 404 2022-05-18 11:03:39 +08:00
yystopf 9cd18397f7 fix: import user login length required 2022-05-18 10:11:09 +08:00
xiaoxiaoqiong 7574071445 fix educoder to Gitlink::utils 2022-05-17 15:41:39 +08:00
yystopf 77620f7735 add: download and import user template xlsx 2022-05-16 16:59:25 +08:00
yystopf 50dc5cce5d fix 2022-05-07 14:06:48 +08:00
yystopf a6cee63d17 fix: change owner must fix foreign_key 2022-05-07 11:57:58 +08:00
yystopf 000197b0d1 fix: issues and pull_request length calculate 2022-05-06 17:25:34 +08:00
yystopf 6aa3321d17 fix: pr title description validate 2022-05-06 14:29:05 +08:00
yystopf d44308fc82 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-05-06 09:56:38 +08:00
yystopf ae7d0d1329 add: issues description and journals notes validate 2022-05-06 09:56:22 +08:00
xiaoxiaoqiong 55c74de8e4 fork_users加入组织 2022-05-05 10:41:02 +08:00
yystopf 7c88ea3d67 add: quit repo 2022-05-05 10:00:02 +08:00
yystopf f15cd44dff add: compare add paginate 2022-04-28 18:53:33 +08:00
yystopf 3abd6037d9 fix: show super description aways desplay 2022-04-28 11:12:16 +08:00
yystopf ec3a556a6f fix: default value for show super description 2022-04-28 11:03:42 +08:00
yystopf 793cbb372a Merge pull request '用户新增个人简介markdown编辑字段' (#8) from yystopf/forgeplus:hh_develop into develop 2022-04-28 10:53:06 +08:00
yystopf 396ac55429 add: user super description 2022-04-28 10:42:55 +08:00
yystopf 088c617cc1 add: name query for branches 2022-04-26 17:15:59 +08:00
xiaoxiaoqiong 17314b9164 take error utf8 2022-04-24 14:54:27 +08:00
xiaoxiaoqiong e6521ffdd2 utf8 2022-04-24 14:46:59 +08:00
yystopf fc3cf01d3f add: get user image action 2022-04-18 13:49:08 +08:00
yystopf 8f5bb0e2d9 fix: organization gitea_token read by associations 2022-04-18 10:52:48 +08:00
yystopf ef559b11a0 add: settings banner 2022-04-14 14:21:16 +08:00
yystopf 7f59f6739f fix 2022-04-12 11:20:19 +08:00
yystopf d6937f195c sync from develop 2022-04-12 11:01:09 +08:00
yystopf 2dfd69ae21 fix: response data result 2022-04-11 16:08:50 +08:00
yystopf 720c073f32 fix 2022-04-11 15:48:47 +08:00
yystopf 0076468a15 fix: trace client request data 2022-04-11 15:30:28 +08:00
yystopf 910ae48556 fix: exception to ex 2022-04-11 10:50:18 +08:00
yystopf eac7331070 fix: settings need prefix 2022-04-08 15:03:40 +08:00
yystopf 551f333261 fix 2022-04-08 14:52:56 +08:00
yystopf dec264d169 fix: sync user pwd 2022-04-07 16:28:40 +08:00
yystopf 7055974443 fix 2022-04-06 17:04:31 +08:00
yystopf 3536918938 fix 2022-03-31 16:18:16 +08:00
yystopf 56278b84f2 Merge pull request '导航增加动态用户数据获取' (#3) from hh_develop_navbar into develop 2022-03-31 16:08:36 +08:00
yystopf 882a50cf56 add: setting navbar varible 2022-03-31 16:04:48 +08:00
yystopf db4031b8bf fix 2022-03-31 14:24:47 +08:00
yystopf ecfc39565c fix 2022-03-31 13:18:38 +08:00
yystopf 9ced678f91 fix: user trace token 2022-03-31 13:03:54 +08:00
yystopf 7951ca28d5 Merge pull request '代码溯源service封装' (#2) from hh_develop into develop 2022-03-31 12:59:34 +08:00
yystopf 4bbb843edf add: trace users and get trace token 2022-03-31 12:54:39 +08:00
yystopf 747646cd9d add: trace client and api completed 2022-03-30 16:19:32 +08:00
yystopf d0d906d04c fix: readme image regex error rescued 2022-03-28 11:05:21 +08:00
yystopf bc639488aa fix: issues filter error 2022-03-22 10:45:14 +08:00
xiaoxiaoqiong 99fbecc834 gitea 请求延长到20分钟 2022-03-11 14:06:12 +08:00
yystopf 8d0a6d267a fix: download escape 2022-03-10 10:47:06 +08:00
yystopf b1c03ed5e8 fix: activity issues must only issue 2022-03-10 09:51:46 +08:00
yystopf ef12f85687 fix: create pull request valid merge_user_login 2022-03-07 11:17:10 +08:00
yystopf e120c4dac2 add: origin repository need open pr menu 2022-03-07 10:53:07 +08:00
yystopf e1cf2fcdeb fix: owner project not allow repeat name 2022-03-07 10:25:05 +08:00
yystopf c4f380873e fix: is public project attachment allow is not member read 2022-03-07 10:20:51 +08:00
yystopf 5cb2e55f74 add: organization users insist team nickname search 2022-03-07 09:58:05 +08:00
xiaoxiaoqiong 1dd3fbc69a fixed fork列表中存在组织时显示错误 2022-03-03 14:16:57 +08:00
yystopf b97c42d0ae fix: email logo 2022-03-02 10:33:35 +08:00
yystopf a2612d8009 fix 2022-02-24 18:09:11 +08:00
yystopf 2f2655525f fix: user rank user_id must exist 2022-02-24 18:07:18 +08:00
yystopf 1a93477635 fix: forked templete delay 2022-02-24 14:26:04 +08:00
yystopf 7c664addbd fix 2022-02-22 11:03:28 +08:00
yystopf c6b79f82bc fix: change password new version 2022-02-22 10:03:51 +08:00
xiaoxiaoqiong 4e3f9cc019 竞赛通知任务调度 2022-02-21 16:48:59 +08:00
xiaoxiaoqiong 5ed7b3e4ad 竞赛通知任务调度 2022-02-21 16:46:40 +08:00
xiaoxiaoqiong 4e2c46260c Merge remote-tracking branch 'origin/develop' into develop 2022-02-17 18:28:40 +08:00
xiaoxiaoqiong 9ba00b21c9 竞赛通知api 2022-02-17 18:28:32 +08:00
yystopf b11f5fd228 fix: cache rollback 2022-02-17 11:12:50 +08:00
yystopf 90dbe0730a fix: job not affect 2022-02-17 10:59:18 +08:00
yystopf d6633cb73a fix 2022-02-17 09:43:44 +08:00
yystopf a7a6abd22a fix: add rule for issue expire 2022-02-17 09:40:44 +08:00
yystopf c956667ce0 fix 2022-02-17 09:36:49 +08:00
yystopf 5701c818ed fix 2022-02-16 15:10:10 +08:00
yystopf 1ac2ddfaa5 fix: default setting for new template message 2022-02-16 11:46:34 +08:00
yystopf 4aac05d4e1 fix: build user template message data must fronted 2022-02-16 11:17:03 +08:00
yystopf 84b56bfcb8 fix: project milestone create notice template 2022-02-16 09:34:31 +08:00
yystopf 7485564bb9 add: template message platform varible 2022-02-15 18:30:13 +08:00
yystopf b5acf2308a Merge pull request '新增站内信以及里程碑完成度修复' (#299) from yystopf/forgeplus:develop into develop 2022-02-15 17:33:30 +08:00
yystopf e3f4313c80 fix 2022-02-15 17:29:13 +08:00
yystopf b223abe229 fix: init data 2022-02-15 17:26:46 +08:00
yystopf b3bede308c add: some new message rules 2022-02-15 17:13:06 +08:00
xiaoxiaoqiong 2f170a54c6 fixed setting编辑类型下拉选中 2022-02-15 17:10:57 +08:00
yystopf 22293572ac fix: issue changed about version callback 2022-02-14 17:02:59 +08:00
xiaoxiaoqiong 8720cab1e9 通过配置确定github克隆方式 2022-02-14 16:53:29 +08:00
yystopf 959c1e8d95 add: user profile setting message 2022-02-14 13:55:34 +08:00
yystopf 29dc3fff39 fix: migrate use old rule 2022-02-11 16:27:22 +08:00
yystopf 298abdd1b1 fix: devops organization bug 2022-02-10 14:08:14 +08:00
yystopf 26f87fba16 fix: edit transfer need change fork info 2022-01-25 14:26:11 +08:00
yystopf 1e9a32a93e fix: issues select count paginator 2022-01-25 11:39:06 +08:00
yystopf 2dc79052c2 fix: create project trend when status is closed 2022-01-25 10:34:20 +08:00
yystopf 380ca3a066 fix: projects query rule 2022-01-24 14:26:24 +08:00
yystopf 237b0afb08 fix: team user build use find or create by 2022-01-24 10:44:46 +08:00
yystopf e14936e820 fix: issues select count 2022-01-24 10:00:44 +08:00
yystopf 655c85851f Merge branch 'develop' of https://git.trustie.net/Gitlink/forgeplus into develop 2022-01-21 18:20:40 +08:00
yystopf 1c7e414aa4 fix: owner allow nil 2022-01-21 18:19:43 +08:00
yystopf 099fc52e00 fix: contributor error rescue 2022-01-21 18:19:34 +08:00
yystopf 490957ec3b fix: contributor error rescue 2022-01-21 18:19:27 +08:00
yystopf b1884d30d5 fix: detail result delay 2022-01-21 18:19:06 +08:00
xiaoxiaoqiong 98d8ee1fb6 Merge remote-tracking branch 'origin/develop' into develop 2022-01-21 15:50:41 +08:00
xiaoxiaoqiong 2ca77732c8 fixed 注册登录类型 2022-01-21 15:50:37 +08:00
yystopf 70d22f7c4f fix: create team overflow tip 2022-01-14 16:09:38 +08:00
yystopf 25d0e784bb fix: pr assignee info use array 2022-01-14 16:00:59 +08:00
yystopf 5d45b24299 fix: devops return result changed 2022-01-14 10:55:53 +08:00
yystopf b6b8befde7 fix: pr update must edit assignee login 2022-01-14 10:55:01 +08:00
yystopf f33b9559cd fix: download delay 2022-01-13 11:24:27 +08:00
yystopf f9bc2258ec fix: migrate repo github use another addr 2022-01-11 10:48:29 +08:00
yystopf 2a09ced1ce fix: branches use branch name api 2022-01-07 15:41:50 +08:00
yystopf 7a1e6cfbad fix: issue edit and new branches only load name api 2022-01-07 15:19:10 +08:00
yystopf 47d1f727ce fix: create team count limit 2022-01-06 17:38:44 +08:00
yystopf a7665df0ea fix: download file url use cgi escape 2022-01-06 15:04:59 +08:00
yystopf 84f12adce8 fix: webhook tasks list error delay 2022-01-06 14:29:31 +08:00
yystopf 7fde1e0e12 fix: webhook field changed 2022-01-06 11:10:49 +08:00
yystopf 499734ebf9 fix: upload user image allow base64 2022-01-04 22:44:39 +08:00
yystopf f339df699e add: user upload image 2022-01-03 22:32:09 +08:00
yystopf cfd94cb3b7 fix: migrate repo username nil is excepted 2022-01-03 20:33:11 +08:00
yystopf 43e0617429 fix: webhook field changed 2021-12-30 09:47:12 +08:00
yystopf d6b66d5324 fix 2021-12-29 09:56:49 +08:00
yystopf 0c1df3b2cb fix 2021-12-29 09:53:14 +08:00
yystopf fa86d3ea10 fix: branch delay 2021-12-29 09:50:57 +08:00
yystopf 8c99b754fb fix: create pr branch name escape 2021-12-28 18:37:44 +08:00
yystopf f3cf2c87c9 fix: create pr branch name escape 2021-12-28 18:29:58 +08:00
yystopf 8e4e6fc0ac Merge pull request '1224里程碑、1231里程碑内容' (#296) from yystopf/forgeplus:develop into develop 2021-12-28 16:09:45 +08:00
yystopf 75f3166ffa fix 2021-12-28 14:45:12 +08:00
yystopf 04bf423fcb fix 2021-12-28 14:42:55 +08:00
yystopf 51e8c9d908 fix: compare use url escape 2021-12-28 14:22:06 +08:00
yystopf 4304a35b80 fix 2021-12-28 11:07:40 +08:00
yystopf 076375633a fix 2021-12-27 17:55:02 +08:00
yystopf dbf5e711a5 fix 2021-12-27 17:44:08 +08:00
yystopf 4432e65683 fix: operate issue permission reset 2021-12-27 17:32:35 +08:00
yystopf dcf44a78f0 fix: unvalid branch name return error 2021-12-27 16:34:54 +08:00
yystopf 12edc620df fix: complete profile condition 2021-12-24 16:15:59 +08:00
yystopf 4ce03145df fix 2021-12-23 14:33:31 +08:00
yystopf 3e04a37ece add: team remove and joined template message 2021-12-23 14:26:40 +08:00
yystopf 78f464ccba fix: escape 2021-12-23 10:37:57 +08:00
yystopf 64423f1999 fix 2021-12-22 18:16:39 +08:00
yystopf 05c3f60dab fix 2021-12-22 18:08:10 +08:00
yystopf 0083ef33cb fix 2021-12-22 16:03:23 +08:00
yystopf 36b68df273 fix: remote register validate 2021-12-22 14:39:47 +08:00
yystopf e1a5918c22 add: project trends project info 2021-12-22 13:57:02 +08:00
yystopf 26ae9b35df fix: change member role and change team user team 2021-12-22 11:32:40 +08:00
yystopf 8e79b43aaf add: member bind team user 2021-12-22 11:16:27 +08:00
yystopf d28eba6423 fix: create org error 2021-12-21 15:16:38 +08:00
yystopf 688be1bb7d fix: return issue version id 2021-12-21 15:16:38 +08:00
yystopf df69dee282 fix: some error for read raw data 2021-12-21 15:14:10 +08:00
yystopf 45a77e5c07 fix: readme private file path use authorize 2021-12-21 14:24:27 +08:00
yystopf 7849bd0ebf fix: remove pr permission 2021-12-21 10:16:29 +08:00
yystopf 3649bf1fd0 fix 2021-12-20 15:53:24 +08:00
yystopf 6ffc2938a1 fix: download file url escape 2021-12-20 15:39:33 +08:00
yystopf aa60de1dac fix: valid pr title length 2021-12-20 15:38:08 +08:00
yystopf 29f98513e2 fix: org update error 2021-12-20 15:38:08 +08:00
yystopf e35cdf39fb fix: login password validate 2021-12-20 15:34:55 +08:00
yystopf e51b86538b Merge pull request '更改易修为疑修' (#292) from yystopf/forgeplus:develop into develop 2021-12-17 15:44:20 +08:00
yystopf da4fd3a762 fix: 易修 to 疑修 2021-12-17 15:35:30 +08:00
xiaoxiaoqiong efc82b9841 fix: issue is collaborators 2021-12-14 10:17:15 +08:00
yystopf e3df503dd2 fix 2021-12-14 10:13:28 +08:00
yystopf 6a2ad67386 fix 2021-12-14 09:53:54 +08:00
yystopf 3d12db3a07 fix: atme service use perform later 2021-12-14 09:39:26 +08:00
yystopf 1faaf1d7d1 fix: project menu list wiki location 2021-12-13 11:45:58 +08:00
yystopf f8a6f62342 fix: project rank include educoder 2021-12-10 09:35:03 +08:00
yystopf 66d1246a6c fix: educoder project menu return 2021-12-09 15:54:21 +08:00
yystopf f79beef3f9 fix: issues branch educoder use master 2021-12-09 14:33:46 +08:00
yystopf 81e6691632 fix: educoder entries image file type 2021-12-09 11:33:43 +08:00
yystopf 38d6519381 fix 2021-12-09 11:08:54 +08:00
yystopf 16418675ac fix 2021-12-09 11:08:10 +08:00
yystopf 102858bc8c fix: educoder entries file use hash 2021-12-09 11:06:49 +08:00
yystopf 0d64768e4b fix: educoder file visit delay 2021-12-09 09:37:28 +08:00
yystopf beccac652f fix 2021-12-08 18:25:31 +08:00
yystopf 30eb1958c1 fix 2021-12-08 18:23:29 +08:00
yystopf 33e17e8439 fix: educoder sub_entries and commit author 2021-12-08 18:18:19 +08:00
yystopf e0c47c2abd fix: educoder clone url 2021-12-08 16:18:13 +08:00
yystopf 422549f9e7 fix 2021-12-08 15:01:33 +08:00
yystopf 0358229b95 fix: educoder api delay 2021-12-08 14:47:15 +08:00
yystopf c4586fbb36 fix: remove detail language and contributors 2021-12-08 14:11:37 +08:00
xiaoxiaoqiong f94006abfd fixed educode not owner 2021-12-07 16:59:04 +08:00
xiaoxiaoqiong 4d61e7618a fixed detail 2021-12-07 16:46:06 +08:00
xiaoxiaoqiong 36286d9003 fixed:educode项目 2021-12-07 16:20:05 +08:00
yystopf 51356da7f3 fix: owners not return 404 2021-12-07 14:34:57 +08:00
yystopf ebe893022f fix: api doc logo 2021-12-07 14:34:57 +08:00
yystopf c5f22e6c70 fix: org delete status error 2021-12-07 14:34:57 +08:00
xiaoxiaoqiong 922561afb1 项目精选加索引 2021-12-01 17:20:52 +08:00
yystopf 6f7899d16f fix: create pr authorize tip 2021-11-30 20:23:37 +08:00
yystopf 4e3c8e414c fix 2021-11-30 15:36:51 +08:00
yystopf d588a78f62 fix: locales for projects update form 2021-11-30 15:35:36 +08:00
yystopf a7d681c4dd fix: compare commit author image url 2021-11-30 15:03:55 +08:00
yystopf 7a93db9ed2 fix: labels limit and issues operate field 2021-11-30 13:58:51 +08:00
yystopf 74e5fa0e31 fix: fork project id validate 2021-11-29 17:01:39 +08:00
yystopf de995c8714 fix: merge conflict 2021-11-29 15:43:47 +08:00
yystopf ea156cec7e fix: download type add video type 2021-11-29 15:33:09 +08:00
yystopf 7499d8af89 fix: project private params to boolean 2021-11-29 14:43:29 +08:00
yystopf f8654edc3b fix: project labels return success info 2021-11-29 14:28:13 +08:00
yystopf d16f290aa6 fix: create pr validate fork_project_id 2021-11-29 14:17:27 +08:00
yystopf 9385d346f1 fix 2021-11-29 14:03:17 +08:00
yystopf 22f3371090 fix: change issues priority id default value 2021-11-29 11:05:33 +08:00
yystopf c0a4f8f4ec fix: create pull request need compare 2021-11-29 10:53:59 +08:00
yystopf 7586a0fb21 fix: change issue tag change size 2021-11-29 10:27:41 +08:00
yystopf c0e3a91a46 fix: page 500 2021-11-29 09:32:39 +08:00
xiaoxiaoqiong 7ebd8681fa 500页面样式调整 2021-11-26 09:49:13 +08:00
xxq250 72553dec57 Merge pull request '一些功能修改以及bug修复' (#263) from yystopf/forgeplus:hh_hotfix into develop 2021-11-26 09:39:58 +08:00
yystopf dee68808b1 fix 2021-11-25 17:37:05 +08:00
yystopf 96d7917bbf fix: change 500 html 2021-11-25 17:34:21 +08:00
yystopf abca0fe432 fix: change pr path id to number 2021-11-25 15:08:59 +08:00
yystopf d7612a0921 add: create update pr need authorize 2021-11-25 14:16:45 +08:00
yystopf c54950a95f fix: compare params contain .json 2021-11-25 14:06:55 +08:00
yystopf be0f68cede fix 2021-11-25 11:19:50 +08:00
yystopf 1b92b53099 fix 2021-11-25 11:00:19 +08:00
yystopf 5634413cac add: create pullrequest validate 2021-11-25 10:52:42 +08:00
yystopf 1a9ed1425e fix: destroy decrement forked count 2021-11-23 13:48:09 +08:00
yystopf f9d4316a8e fix: change fork project status 2021-11-23 11:43:44 +08:00
yystopf 6f7f815fd4 fix: change warn image 2021-11-19 15:15:40 +08:00
yystopf ddb826733b fix: project setting permission control 2021-11-19 14:56:20 +08:00
yystopf 1f989d0a37 fix: delete organization tip 2021-11-19 14:44:25 +08:00
yystopf d63626424e Merge pull request '更改邮件默认发送规则' (#251) from yystopf/forgeplus:hh_email_fix into develop 2021-11-19 10:38:04 +08:00
yystopf 55ab694505 fix: change email default rule 2021-11-19 10:21:09 +08:00
yystopf 0885575cc4 fix: organization validate name tip 2021-11-18 17:31:22 +08:00
yystopf a188648287 fix: qq qun url 2021-11-18 17:25:50 +08:00
yystopf 8011dabaac fix: undo events 2021-11-18 17:02:09 +08:00
yystopf 88a08e73c0 fix: web icon 2021-11-18 16:13:33 +08:00
yystopf 6713f9b280 fix: pullrequest trend action name 2021-11-17 11:04:15 +08:00
556 changed files with 23631 additions and 6535 deletions

View File

@ -23,7 +23,7 @@
* Fix 版本库中附件下载400(#51625) * Fix 版本库中附件下载400(#51625)
* Fix loading页面优化(#51588) * Fix loading页面优化(#51588)
* Fix 提交详情页面优化(#51577) * Fix 提交详情页面优化(#51577)
* Fix 修复修复制功能(#51569) * Fix 修复修复制功能(#51569)
* Fix 修复新建发行版用户信息显示错误的问题(#51665) * Fix 修复新建发行版用户信息显示错误的问题(#51665)
* Fix 修复查看文件详细信息报错的问题(#51561) * Fix 修复查看文件详细信息报错的问题(#51561)
* Fix 修复提交记录中时间显示格式问题(#51526) * Fix 修复提交记录中时间显示格式问题(#51526)
@ -62,7 +62,7 @@
## [v3.0.3](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-05-08 ## [v3.0.3](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-05-08
* BUGFIXES * BUGFIXES
* Fix 解决修标题过长导致的排版问题(45469) * Fix 解决修标题过长导致的排版问题(45469)
* Fix 解决合并请求详情页面排版错误的问题(45457) * Fix 解决合并请求详情页面排版错误的问题(45457)
* FIX 解决转移仓库界面专有名词描述错误的问题(45455) * FIX 解决转移仓库界面专有名词描述错误的问题(45455)
* Fix 解决markdown格式文件自动生成数字排序的问题(45454) * Fix 解决markdown格式文件自动生成数字排序的问题(45454)

16
Gemfile
View File

@ -1,4 +1,5 @@
source 'https://gems.ruby-china.com' #source 'https://gems.ruby-china.com'
source 'https://mirrors.cloud.tencent.com/rubygems/'
git_source(:github) { |repo| "https://github.com/#{repo}.git" } git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 5.2.0' gem 'rails', '~> 5.2.0'
@ -101,6 +102,7 @@ gem 'rails-i18n', '~> 5.1'
gem 'sidekiq' gem 'sidekiq'
gem 'sinatra' gem 'sinatra'
gem "sidekiq-cron", "~> 1.1" gem "sidekiq-cron", "~> 1.1"
gem 'sidekiq-failures'
# batch insert # batch insert
gem 'bulk_insert' gem 'bulk_insert'
@ -118,6 +120,10 @@ gem 'deep_cloneable', '~> 3.0.0'
# oauth2 # oauth2
gem 'omniauth', '~> 1.9.0' gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0' gem 'omniauth-oauth2', '~> 1.6.0'
gem "omniauth-github"
gem "omniauth-rails_csrf_protection"
gem 'omniauth-gitee', '~> 1.0.0'
gem "omniauth-wechat-oauth2"
# global var # global var
gem 'request_store' gem 'request_store'
@ -128,3 +134,11 @@ gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1' gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar' gem 'letter_avatar'
gem 'jwt'
gem 'doorkeeper'
gem 'doorkeeper-jwt'
gem 'gitea-client', '~> 0.10.6'

View File

@ -106,6 +106,10 @@ GEM
activerecord (>= 3.1.0, < 7) activerecord (>= 3.1.0, < 7)
diff-lcs (1.3) diff-lcs (1.3)
diffy (3.3.0) diffy (3.3.0)
doorkeeper (5.5.1)
railties (>= 5)
doorkeeper-jwt (0.4.1)
jwt (>= 2.1)
e2mmap (0.1.0) e2mmap (0.1.0)
elasticsearch (7.5.0) elasticsearch (7.5.0)
elasticsearch-api (= 7.5.0) elasticsearch-api (= 7.5.0)
@ -450,6 +454,8 @@ DEPENDENCIES
chromedriver-helper chromedriver-helper
deep_cloneable (~> 3.0.0) deep_cloneable (~> 3.0.0)
diffy diffy
doorkeeper
doorkeeper-jwt
enumerize enumerize
faraday (~> 0.15.4) faraday (~> 0.15.4)
font-awesome-sass (= 4.7.0) font-awesome-sass (= 4.7.0)
@ -458,6 +464,7 @@ DEPENDENCIES
harmonious_dictionary (~> 0.0.1) harmonious_dictionary (~> 0.0.1)
jbuilder (~> 2.5) jbuilder (~> 2.5)
jquery-rails jquery-rails
jwt
kaminari (~> 1.1, >= 1.1.1) kaminari (~> 1.1, >= 1.1.1)
letter_avatar letter_avatar
listen (>= 3.0.5, < 3.2) listen (>= 3.0.5, < 3.2)

View File

@ -14,6 +14,7 @@
//= require bootstrap-datepicker //= require bootstrap-datepicker
//= require bootstrap-datetimepicker //= require bootstrap-datetimepicker
//= require bootstrap.viewer //= require bootstrap.viewer
//= require bootstrap/bootstrap-toggle
//= require jquery.mloading //= require jquery.mloading
//= require jquery-confirm.min //= require jquery-confirm.min
//= require common //= require common

View File

@ -0,0 +1,180 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
+function ($) {
'use strict';
// TOGGLE PUBLIC CLASS DEFINITION
// ==============================
var Toggle = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, this.defaults(), options)
this.render()
}
Toggle.VERSION = '2.2.0'
Toggle.DEFAULTS = {
on: 'On',
off: 'Off',
onstyle: 'primary',
offstyle: 'default',
size: 'normal',
style: '',
width: null,
height: null
}
Toggle.prototype.defaults = function() {
return {
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
}
}
Toggle.prototype.render = function () {
this._onstyle = 'btn-' + this.options.onstyle
this._offstyle = 'btn-' + this.options.offstyle
var size = this.options.size === 'large' ? 'btn-lg'
: this.options.size === 'small' ? 'btn-sm'
: this.options.size === 'mini' ? 'btn-xs'
: ''
var $toggleOn = $('<label class="btn">').html(this.options.on)
.addClass(this._onstyle + ' ' + size)
var $toggleOff = $('<label class="btn">').html(this.options.off)
.addClass(this._offstyle + ' ' + size + ' active')
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
.addClass(size)
var $toggleGroup = $('<div class="toggle-group">')
.append($toggleOn, $toggleOff, $toggleHandle)
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
.addClass(size).addClass(this.options.style)
this.$element.wrap($toggle)
$.extend(this, {
$toggle: this.$element.parent(),
$toggleOn: $toggleOn,
$toggleOff: $toggleOff,
$toggleGroup: $toggleGroup
})
this.$toggle.append($toggleGroup)
var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
$toggleOn.addClass('toggle-on')
$toggleOff.addClass('toggle-off')
this.$toggle.css({ width: width, height: height })
if (this.options.height) {
$toggleOn.css('line-height', $toggleOn.height() + 'px')
$toggleOff.css('line-height', $toggleOff.height() + 'px')
}
this.update(true)
this.trigger(true)
}
Toggle.prototype.toggle = function () {
if (this.$element.prop('checked')) this.off()
else this.on()
}
Toggle.prototype.on = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
this.$element.prop('checked', true)
if (!silent) this.trigger()
}
Toggle.prototype.off = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
this.$element.prop('checked', false)
if (!silent) this.trigger()
}
Toggle.prototype.enable = function () {
this.$toggle.removeAttr('disabled')
this.$element.prop('disabled', false)
}
Toggle.prototype.disable = function () {
this.$toggle.attr('disabled', 'disabled')
this.$element.prop('disabled', true)
}
Toggle.prototype.update = function (silent) {
if (this.$element.prop('disabled')) this.disable()
else this.enable()
if (this.$element.prop('checked')) this.on(silent)
else this.off(silent)
}
Toggle.prototype.trigger = function (silent) {
this.$element.off('change.bs.toggle')
if (!silent) this.$element.change()
this.$element.on('change.bs.toggle', $.proxy(function() {
this.update()
}, this))
}
Toggle.prototype.destroy = function() {
this.$element.off('change.bs.toggle')
this.$toggleGroup.remove()
this.$element.removeData('bs.toggle')
this.$element.unwrap()
}
// TOGGLE PLUGIN DEFINITION
// ========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.toggle')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
if (typeof option == 'string' && data[option]) data[option]()
})
}
var old = $.fn.bootstrapToggle
$.fn.bootstrapToggle = Plugin
$.fn.bootstrapToggle.Constructor = Toggle
// TOGGLE NO CONFLICT
// ==================
$.fn.toggle.noConflict = function () {
$.fn.bootstrapToggle = old
return this
}
// TOGGLE DATA-API
// ===============
$(function() {
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
})
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
var $checkbox = $(this).find('input[type=checkbox]')
$checkbox.bootstrapToggle('toggle')
e.preventDefault()
})
}(jQuery);

View File

@ -0,0 +1,9 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
//# sourceMappingURL=bootstrap-toggle.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"bootstrap-toggle.min.js","sources":["bootstrap-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","outerHeight","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,SAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,SACV,SAAtBjB,KAAKI,QAAQa,KAAkB,SAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUa,aAAcV,EAAWU,cAAeT,EAAcS,aAAa,EACpHlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUc,cAAeX,EAAWW,cACjFd,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQQ,KAAMrB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUe,IAAI,cAAef,EAAUL,SAAW,MAClDQ,EAAWY,IAAI,cAAeZ,EAAWR,SAAW,OAErDpB,KAAKyC,QAAO,GACZzC,KAAK0C,SAAQ,IAGdrC,EAAOgB,UAAUsB,OAAS,WACrB3C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU+B,GAC/B,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUP,IAAM,SAAU8B,GAChC,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUyB,OAAS,WACzB9C,KAAKgC,QAAQe,WAAW,YACxB/C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU2B,QAAU,WAC1BhD,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUoB,OAAS,SAAUG,GAC/B5C,KAAKO,SAAS0B,KAAK,YAAajC,KAAKgD,UACpChD,KAAK8C,SACN9C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG+B,GACtC5C,KAAKc,IAAI8B,IAGfvC,EAAOgB,UAAUqB,QAAU,SAAUE,GACpC5C,KAAKO,SAASO,IAAI,oBACb8B,GAAQ5C,KAAKO,SAAS0C,SAC3BjD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEqD,MAAM,WAC5ClD,KAAKyC,UACHzC,QAGJK,EAAOgB,UAAU8B,QAAU,WAC1BnD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAasB,SAClBpD,KAAKO,SAAS8C,WAAW,aACzBrD,KAAKO,SAAS+C,SAiBf,IAAIC,GAAM1D,EAAE2D,GAAGC,eAEf5D,GAAE2D,GAAGC,gBAA8B3D,EACnCD,EAAE2D,GAAGC,gBAAgBC,YAAcrD,EAKnCR,EAAE2D,GAAGb,OAAOgB,WAAa,WAExB,MADA9D,GAAE2D,GAAGC,gBAAkBF,EAChBvD,MAMRH,EAAE,WACDA,EAAE,6CAA6C4D,oBAGhD5D,EAAE+D,UAAU/C,GAAG,kBAAmB,2BAA4B,SAASgD,GACtE,GAAIC,GAAYjE,EAAEG,MAAM+D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}

View File

@ -0,0 +1,180 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
+function ($) {
'use strict';
// TOGGLE PUBLIC CLASS DEFINITION
// ==============================
var Toggle = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, this.defaults(), options)
this.render()
}
Toggle.VERSION = '2.2.0'
Toggle.DEFAULTS = {
on: 'On',
off: 'Off',
onstyle: 'primary',
offstyle: 'default',
size: 'normal',
style: '',
width: null,
height: null
}
Toggle.prototype.defaults = function() {
return {
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
}
}
Toggle.prototype.render = function () {
this._onstyle = 'btn-' + this.options.onstyle
this._offstyle = 'btn-' + this.options.offstyle
var size = this.options.size === 'large' ? 'btn-large'
: this.options.size === 'small' ? 'btn-small'
: this.options.size === 'mini' ? 'btn-mini'
: ''
var $toggleOn = $('<label class="btn">').html(this.options.on)
.addClass(this._onstyle + ' ' + size)
var $toggleOff = $('<label class="btn">').html(this.options.off)
.addClass(this._offstyle + ' ' + size + ' active')
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
.addClass(size)
var $toggleGroup = $('<div class="toggle-group">')
.append($toggleOn, $toggleOff, $toggleHandle)
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
.addClass(size).addClass(this.options.style)
this.$element.wrap($toggle)
$.extend(this, {
$toggle: this.$element.parent(),
$toggleOn: $toggleOn,
$toggleOff: $toggleOff,
$toggleGroup: $toggleGroup
})
this.$toggle.append($toggleGroup)
var width = this.options.width || Math.max($toggleOn.width(), $toggleOff.width())+($toggleHandle.outerWidth()/2)
var height = this.options.height || Math.max($toggleOn.height(), $toggleOff.height())
$toggleOn.addClass('toggle-on')
$toggleOff.addClass('toggle-off')
this.$toggle.css({ width: width, height: height })
if (this.options.height) {
$toggleOn.css('line-height', $toggleOn.height() + 'px')
$toggleOff.css('line-height', $toggleOff.height() + 'px')
}
this.update(true)
this.trigger(true)
}
Toggle.prototype.toggle = function () {
if (this.$element.prop('checked')) this.off()
else this.on()
}
Toggle.prototype.on = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
this.$element.prop('checked', true)
if (!silent) this.trigger()
}
Toggle.prototype.off = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
this.$element.prop('checked', false)
if (!silent) this.trigger()
}
Toggle.prototype.enable = function () {
this.$toggle.removeAttr('disabled')
this.$element.prop('disabled', false)
}
Toggle.prototype.disable = function () {
this.$toggle.attr('disabled', 'disabled')
this.$element.prop('disabled', true)
}
Toggle.prototype.update = function (silent) {
if (this.$element.prop('disabled')) this.disable()
else this.enable()
if (this.$element.prop('checked')) this.on(silent)
else this.off(silent)
}
Toggle.prototype.trigger = function (silent) {
this.$element.off('change.bs.toggle')
if (!silent) this.$element.change()
this.$element.on('change.bs.toggle', $.proxy(function() {
this.update()
}, this))
}
Toggle.prototype.destroy = function() {
this.$element.off('change.bs.toggle')
this.$toggleGroup.remove()
this.$element.removeData('bs.toggle')
this.$element.unwrap()
}
// TOGGLE PLUGIN DEFINITION
// ========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.toggle')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
if (typeof option == 'string' && data[option]) data[option]()
})
}
var old = $.fn.bootstrapToggle
$.fn.bootstrapToggle = Plugin
$.fn.bootstrapToggle.Constructor = Toggle
// TOGGLE NO CONFLICT
// ==================
$.fn.toggle.noConflict = function () {
$.fn.bootstrapToggle = old
return this
}
// TOGGLE DATA-API
// ===============
$(function() {
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
})
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
var $checkbox = $(this).find('input[type=checkbox]')
$checkbox.bootstrapToggle('toggle')
e.preventDefault()
})
}(jQuery);

View File

@ -0,0 +1,9 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-large":"small"===this.options.size?"btn-small":"mini"===this.options.size?"btn-mini":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.width(),d.width())+e.outerWidth()/2,i=this.options.height||Math.max(c.height(),d.height());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
//# sourceMappingURL=bootstrap2-toggle.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"bootstrap2-toggle.min.js","sources":["bootstrap2-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,YAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,YACV,SAAtBjB,KAAKI,QAAQa,KAAkB,WAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUN,QAASS,EAAWT,SAAUU,EAAcS,aAAa,EAC1GlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUL,SAAUQ,EAAWR,SAC5EK,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQO,KAAMpB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUc,IAAI,cAAed,EAAUL,SAAW,MAClDQ,EAAWW,IAAI,cAAeX,EAAWR,SAAW,OAErDpB,KAAKwC,QAAO,GACZxC,KAAKyC,SAAQ,IAGdpC,EAAOgB,UAAUqB,OAAS,WACrB1C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU8B,GAC/B,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUP,IAAM,SAAU6B,GAChC,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUwB,OAAS,WACzB7C,KAAKgC,QAAQc,WAAW,YACxB9C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU0B,QAAU,WAC1B/C,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUmB,OAAS,SAAUG,GAC/B3C,KAAKO,SAAS0B,KAAK,YAAajC,KAAK+C,UACpC/C,KAAK6C,SACN7C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG8B,GACtC3C,KAAKc,IAAI6B,IAGftC,EAAOgB,UAAUoB,QAAU,SAAUE,GACpC3C,KAAKO,SAASO,IAAI,oBACb6B,GAAQ3C,KAAKO,SAASyC,SAC3BhD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEoD,MAAM,WAC5CjD,KAAKwC,UACHxC,QAGJK,EAAOgB,UAAU6B,QAAU,WAC1BlD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAaqB,SAClBnD,KAAKO,SAAS6C,WAAW,aACzBpD,KAAKO,SAAS8C,SAiBf,IAAIC,GAAMzD,EAAE0D,GAAGC,eAEf3D,GAAE0D,GAAGC,gBAA8B1D,EACnCD,EAAE0D,GAAGC,gBAAgBC,YAAcpD,EAKnCR,EAAE0D,GAAGb,OAAOgB,WAAa,WAExB,MADA7D,GAAE0D,GAAGC,gBAAkBF,EAChBtD,MAMRH,EAAE,WACDA,EAAE,6CAA6C2D,oBAGhD3D,EAAE8D,UAAU9C,GAAG,kBAAmB,2BAA4B,SAAS+C,GACtE,GAAIC,GAAYhE,EAAEG,MAAM8D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}

View File

@ -8,6 +8,7 @@
@import "jquery.mloading"; @import "jquery.mloading";
@import "jquery-confirm.min"; @import "jquery-confirm.min";
@import "bootstrap-datetimepicker.min"; @import "bootstrap-datetimepicker.min";
@import "bootstrap/bootstrap-toggle.min";
@import "codemirror/lib/codemirror"; @import "codemirror/lib/codemirror";
@import "editormd/css/editormd.min"; @import "editormd/css/editormd.min";
@ -204,3 +205,13 @@ input.form-control {
font-size: 1rem; font-size: 1rem;
} }
} }
.table th, .table td {
padding: 0.75rem 0.1rem;
vertical-align: top;
border-top: 1px solid #dee2e6;
}
.table .thead-light th{
white-space: nowrap;
}

View File

@ -0,0 +1,83 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
.checkbox label .toggle,
.checkbox-inline .toggle {
margin-left: -20px;
margin-right: 5px;
}
.toggle {
position: relative;
overflow: hidden;
}
.toggle input[type="checkbox"] {
display: none;
}
.toggle-group {
position: absolute;
width: 200%;
top: 0;
bottom: 0;
left: 0;
transition: left 0.35s;
-webkit-transition: left 0.35s;
-moz-user-select: none;
-webkit-user-select: none;
}
.toggle.off .toggle-group {
left: -100%;
}
.toggle-on {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 50%;
margin: 0;
border: 0;
border-radius: 0;
}
.toggle-off {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
right: 0;
margin: 0;
border: 0;
border-radius: 0;
}
.toggle-handle {
position: relative;
margin: 0 auto;
padding-top: 0px;
padding-bottom: 0px;
height: 100%;
width: 0px;
border-width: 0 1px;
}
.toggle.btn { min-width: 59px; min-height: 34px; }
.toggle-on.btn { padding-right: 24px; }
.toggle-off.btn { padding-left: 24px; }
.toggle.btn-lg { min-width: 79px; min-height: 45px; }
.toggle-on.btn-lg { padding-right: 31px; }
.toggle-off.btn-lg { padding-left: 31px; }
.toggle-handle.btn-lg { width: 40px; }
.toggle.btn-sm { min-width: 50px; min-height: 30px;}
.toggle-on.btn-sm { padding-right: 20px; }
.toggle-off.btn-sm { padding-left: 20px; }
.toggle.btn-xs { min-width: 35px; min-height: 22px;}
.toggle-on.btn-xs { padding-right: 12px; }
.toggle-off.btn-xs { padding-left: 12px; }

View File

@ -0,0 +1,28 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
.toggle{position:relative;overflow:hidden}
.toggle input[type=checkbox]{display:none}
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
.toggle.off .toggle-group{left:-100%}
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
.toggle.btn{min-width:59px;min-height:34px}
.toggle-on.btn{padding-right:24px}
.toggle-off.btn{padding-left:24px}
.toggle.btn-lg{min-width:79px;min-height:45px}
.toggle-on.btn-lg{padding-right:31px}
.toggle-off.btn-lg{padding-left:31px}
.toggle-handle.btn-lg{width:40px}
.toggle.btn-sm{min-width:50px;min-height:30px}
.toggle-on.btn-sm{padding-right:20px}
.toggle-off.btn-sm{padding-left:20px}
.toggle.btn-xs{min-width:35px;min-height:22px}
.toggle-on.btn-xs{padding-right:12px}
.toggle-off.btn-xs{padding-left:12px}

View File

@ -0,0 +1,85 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
label.checkbox .toggle,
label.checkbox.inline .toggle {
margin-left: -20px;
margin-right: 5px;
}
.toggle {
min-width: 40px;
height: 20px;
position: relative;
overflow: hidden;
}
.toggle input[type="checkbox"] {
display: none;
}
.toggle-group {
position: absolute;
width: 200%;
top: 0;
bottom: 0;
left: 0;
transition: left 0.35s;
-webkit-transition: left 0.35s;
-moz-user-select: none;
-webkit-user-select: none;
}
.toggle.off .toggle-group {
left: -100%;
}
.toggle-on {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 50%;
margin: 0;
border: 0;
border-radius: 0;
}
.toggle-off {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
right: 0;
margin: 0;
border: 0;
border-radius: 0;
}
.toggle-handle {
position: relative;
margin: 0 auto;
padding-top: 0px;
padding-bottom: 0px;
height: 100%;
width: 0px;
border-width: 0 1px;
}
.toggle-handle.btn-mini {
top: -1px;
}
.toggle.btn { min-width: 30px; }
.toggle-on.btn { padding-right: 24px; }
.toggle-off.btn { padding-left: 24px; }
.toggle.btn-large { min-width: 40px; }
.toggle-on.btn-large { padding-right: 35px; }
.toggle-off.btn-large { padding-left: 35px; }
.toggle.btn-small { min-width: 25px; }
.toggle-on.btn-small { padding-right: 20px; }
.toggle-off.btn-small { padding-left: 20px; }
.toggle.btn-mini { min-width: 20px; }
.toggle-on.btn-mini { padding-right: 12px; }
.toggle-off.btn-mini { padding-left: 12px; }

View File

@ -0,0 +1,28 @@
/*! ========================================================================
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
* http://www.bootstraptoggle.com
* ========================================================================
* Copyright 2014 Min Hur, The New York Times Company
* Licensed under MIT
* ======================================================================== */
label.checkbox .toggle,label.checkbox.inline .toggle{margin-left:-20px;margin-right:5px}
.toggle{min-width:40px;height:20px;position:relative;overflow:hidden}
.toggle input[type=checkbox]{display:none}
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
.toggle.off .toggle-group{left:-100%}
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
.toggle-handle.btn-mini{top:-1px}
.toggle.btn{min-width:30px}
.toggle-on.btn{padding-right:24px}
.toggle-off.btn{padding-left:24px}
.toggle.btn-large{min-width:40px}
.toggle-on.btn-large{padding-right:35px}
.toggle-off.btn-large{padding-left:35px}
.toggle.btn-small{min-width:25px}
.toggle-on.btn-small{padding-right:20px}
.toggle-off.btn-small{padding-left:20px}
.toggle.btn-mini{min-width:20px}
.toggle-on.btn-mini{padding-right:12px}
.toggle-off.btn-mini{padding-left:12px}

View File

@ -1,14 +1,45 @@
class AccountsController < ApplicationController class AccountsController < ApplicationController
before_action :require_login, only: [:login_check, :simple_update]
include ApplicationHelper include ApplicationHelper
#skip_before_action :check_account, :only => [:logout] #skip_before_action :check_account, :only => [:logout]
def simple_update
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
Register::RemoteForm.new(simple_update_params).validate!
ActiveRecord::Base.transaction do
result = auto_update(current_user, simple_update_params)
if result[:message].blank?
render_ok
else
render_error(result[:message])
end
end
end
def index def index
render json: session render json: session
end 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 def remote_register
Register::RemoteForm.new(remote_register_params).validate!
username = params[:username]&.gsub(/\s+/, "") username = params[:username]&.gsub(/\s+/, "")
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
email = params[:email]&.gsub(/\s+/, "") email = params[:email]&.gsub(/\s+/, "")
@ -93,7 +124,9 @@ class AccountsController < ApplicationController
sync_params = { sync_params = {
password: params[:password].to_s, password: params[:password].to_s,
email: @user.mail email: @user.mail,
login_name: @user.login,
source_id: 0
} }
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
@ -191,7 +224,9 @@ class AccountsController < ApplicationController
sync_params = { sync_params = {
password: params[:password].to_s, password: params[:password].to_s,
email: @user.mail email: @user.mail,
login_name: @user.login,
source_id: 0
} }
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
@ -314,6 +349,11 @@ class AccountsController < ApplicationController
render_ok render_ok
end end
def login_check
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
render_ok
end
private private
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 # type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
@ -352,6 +392,10 @@ class AccountsController < ApplicationController
{ login: pre + code, email: email, phone: phone } { login: pre + code, email: email, phone: phone }
end end
def sync_gitea_params
params.permit(:login, :email, :password)
end
def user_params def user_params
params.require(:user).permit(:login, :email, :phone) params.require(:user).permit(:login, :email, :phone)
end end
@ -368,4 +412,11 @@ class AccountsController < ApplicationController
params.permit(:login, :namespace, :password, :code) params.permit(:login, :namespace, :password, :code)
end end
def remote_register_params
params.permit(:username, :email, :password, :platform)
end
def simple_update_params
params.permit(:username, :email, :password, :platform)
end
end end

View File

@ -1,10 +1,33 @@
class Admins::DashboardsController < Admins::BaseController class Admins::DashboardsController < Admins::BaseController
def index def index
@active_user_count = User.where(last_login_on: today).count # 用户活跃数
@weekly_active_user_count = User.where(last_login_on: current_week).count day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
@month_active_user_count = User.where(last_login_on: current_month).count weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:user_id).uniq
month_user_ids = CommitLog.where(created_at: current_month).pluck(:user_id).uniq
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
user_ids = User.where(created_on: pre_week).pluck(:id).uniq
weekly_keep_user_count = User.where(id: user_ids).where(last_login_on: current_week).count
@weekly_keep_rate = format("%.2f", user_ids.size > 0 ? weekly_keep_user_count.to_f / user_ids.size : 0)
@new_user_count = User.where(created_on: current_month).count # 新用户注册数
@day_new_user_count = User.where(created_on: today).count
@weekly_new_user_count = User.where(created_on: current_week).count
@month_new_user_count = User.where(created_on: current_month).count
# 活跃项目数
day_project_ids = (CommitLog.where(created_at: today).pluck(:project_id).uniq + Issue.where(created_on: today).pluck(:project_id).uniq).uniq
weekly_project_ids = (CommitLog.where(created_at: current_week).pluck(:project_id).uniq + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq
@day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count
@weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
@month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
# 新增项目数
@day_new_project_count = Project.where(created_on: today).count
@weekly_new_project_count = Project.where(created_on: current_week).count
@month_new_project_count = Project.where(created_on: current_month).count
end end
def month_active_user def month_active_user
@ -42,10 +65,14 @@ class Admins::DashboardsController < Admins::BaseController
end end
def current_week def current_week
7.days.ago.beginning_of_day..Time.now.end_of_day 7.days.ago.end_of_day..Time.now.end_of_day
end end
def current_month def current_month
30.days.ago.beginning_of_day..Time.now.end_of_day 30.days.ago.end_of_day..Time.now.end_of_day
end
def pre_week
14.days.ago.end_of_day..7.days.ago.end_of_day
end end
end end

View File

@ -0,0 +1,49 @@
class Admins::FeedbacksController < Admins::BaseController
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
def index
sort_by = Feedback.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
feedbacks = Feedback.order("#{sort_by} #{sort_direction}")
@feedbacks = paginate(feedbacks)
end
def destroy
if @feedback.destroy
redirect_to admins_feedbacks_path
flash[:success] = "反馈意见删除成功"
else
redirect_to admins_feedbacks_path
flash[:danger] = "反馈意见删除失败"
end
end
def new_history
@feedback_message_history = FeedbackMessageHistory.new
end
def create_history
@feedback_message_history = @feedback.feedback_message_histories.new(feedback_message_history_params)
@feedback_message_history.user = current_user
if @feedback_message_history.save
redirect_to admins_feedbacks_path
flash[:success] = "发送通知成功"
else
redirect_to admins_feedbacks_path
flash[:danger] = @feedback_message_history.errors.full_messages.join(", ")
end
end
private
def feedback_params
params.require(:feedback).permit!
end
def feedback_message_history_params
params.require(:feedback_message_history).permit(:title, :content)
end
def get_feedback
@feedback = Feedback.find_by_id(params[:id])
end
end

View File

@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
def create def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportUserService.call(params[:file].to_io) result = Admins::ImportUserFromExcelService.call(params[:file].to_io)
render_ok(result) render_ok(result)
rescue Admins::ImportUserService::Error => ex rescue Admins::ImportUserService::Error => ex
render_error(ex) render_error(ex)

View File

@ -2,8 +2,24 @@ class Admins::MessageTemplatesController < Admins::BaseController
before_action :get_template, only: [:edit, :update, :destroy] before_action :get_template, only: [:edit, :update, :destroy]
def index def index
message_templates = MessageTemplate.group(:type).count.keys message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result
@message_templates = kaminari_array_paginate(message_templates) @message_templates = kaminari_paginate(message_templates)
end
def new
@message_template = MessageTemplate.new
end
def create
@message_template = MessageTemplate::CustomTip.new(message_template_params)
@message_template.type = "MessageTemplate::CustomTip"
if @message_template.save!
redirect_to admins_message_templates_path
flash[:success] = "创建消息模板成功"
else
render :new
flash[:danger] = "创建消息模板失败"
end
end end
def edit def edit
@ -31,7 +47,9 @@ class Admins::MessageTemplatesController < Admins::BaseController
private private
def message_template_params def message_template_params
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit! # type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
# params.require(type.split("::").join("_").underscore.to_sym).permit!
params.require(:message_template).permit!
end end
def get_template def get_template

View File

@ -0,0 +1,26 @@
class Admins::NpsController < Admins::BaseController
def index
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
@user_nps = UserNp.joins(:user).order(created_at: :desc)
keyword = params[:keyword].to_s.strip.presence
if keyword
sql = 'CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword OR users.login LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword'
@user_nps = @user_nps.where(sql, keyword: "%#{keyword}%")
end
@user_nps = @user_nps.where("action_type != 'close'") if params[:done_score].present?
@min_score = @user_nps.where("action_type != 'close'").minimum("score")
@max_score = @user_nps.where("action_type != 'close'").maximum("score")
@score_total_count = UserNp.where("action_type !='close'").count
@user_nps = paginate @user_nps.includes(:user)
end
def switch_change
edu_setting = EduSetting.find_by(name: "nps-on-off-switch")
if edu_setting.blank?
edu_setting = EduSetting.new(name: "nps-on-off-switch")
end
edu_setting.value = params[:switch].to_s
edu_setting.save
render_ok
end
end

View File

@ -1,6 +1,6 @@
class Admins::ProjectIgnoresController < Admins::BaseController class Admins::ProjectIgnoresController < Admins::BaseController
before_action :set_ignore, only: [:edit,:update, :destroy,:show] before_action :set_ignore, only: [:edit,:update, :destroy,:show]
before_action :validate_params, only: [:create, :update] # before_action :validate_params, only: [:create, :update]
def index def index
sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
@ -31,12 +31,12 @@ class Admins::ProjectIgnoresController < Admins::BaseController
# } # }
@project_ignore = Ignore.new(ignore_params) @project_ignore = Ignore.new(ignore_params)
if @project_ignore.save! if @project_ignore.save
redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
flash[:success] = "创建成功" flash[:success] = "创建成功"
else else
render :new redirect_to admins_project_ignores_path
flash[:danger] = "创建失败" flash[:danger] = @project_ignore.errors.full_messages.join(",")
end end
end end
@ -58,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController
redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
flash[:success] = "更新成功" flash[:success] = "更新成功"
else else
render :edit redirect_to admins_project_ignores_path
flash[:danger] = "更新失败" flash[:danger] = @project_ignore.errors.full_messages.join(",")
end end
end end
@ -98,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController
params.require(:ignore).permit(:name,:content) params.require(:ignore).permit(:name,:content)
end end
def validate_params # def validate_params
name = params[:ignore][:name] # name = params[:ignore][:name]
if name.blank? # if name.blank?
flash[:danger] = "名称不允许为空" # flash[:danger] = "名称不允许为空"
redirect_to admins_project_ignores_path # redirect_to admins_project_ignores_path
elsif check_ignore_present?(name) && @project_ignore.blank? # elsif check_ignore_present?(name) && @project_ignore.blank?
flash[:danger] = "创建失败:名称已存在" # flash[:danger] = "创建失败:名称已存在"
redirect_to admins_project_ignores_path # redirect_to admins_project_ignores_path
end # end
end # end
def check_ignore_present?(name) # def check_ignore_present?(name)
return true if name.blank? # return true if name.blank?
name_downcase = name.downcase # name_downcase = name.downcase
name_upcase = name.upcase # name_upcase = name.upcase
name_first_big = name.capitalize # name_first_big = name.capitalize
Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big) # Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
end # end
end end

View File

@ -27,17 +27,18 @@ class Admins::ProjectLanguagesController < Admins::BaseController
flash[:success] = '创建成功' flash[:success] = '创建成功'
else else
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:danger] = '创建失败' flash[:danger] = @project_language.errors.full_messages.join(",")
end end
end end
def update def update
if @project_language.update_attribute(:name, @name) @project_language.attributes = {name: @name}
if @project_language.save
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:success] = '更新成功' flash[:success] = '更新成功'
else else
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:success] = '更新失败' flash[:danger] = @project_language.errors.full_messages.join(",")
end end
end end

View File

@ -1,6 +1,6 @@
class Admins::ProjectLicensesController < Admins::BaseController class Admins::ProjectLicensesController < Admins::BaseController
before_action :set_license, only: [:edit,:update, :destroy,:show] before_action :set_license, only: [:edit,:update, :destroy,:show]
before_action :validate_params, only: [:create, :update] # before_action :validate_params, only: [:create, :update]
def index def index
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
@ -30,13 +30,12 @@ class Admins::ProjectLicensesController < Admins::BaseController
# position: max_position # position: max_position
# } # }
@project_license = License.new(license_params) @project_license = License.new(license_params)
if @project_license.save
if @project_license.save!
redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
flash[:success] = "创建成功" flash[:success] = "创建成功"
else else
render :new redirect_to admins_project_licenses_path
flash[:danger] = "创建失败" flash[:danger] = @project_license.errors.full_messages.join(",")
end end
end end
@ -54,12 +53,13 @@ class Admins::ProjectLicensesController < Admins::BaseController
# permissions: permissions.to_s, # permissions: permissions.to_s,
# limitations: limitations.to_s # limitations: limitations.to_s
# } # }
if @project_license.update_attributes(license_params) @project_license.attributes = license_params
if @project_license.save
redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
flash[:success] = "更新成功" flash[:success] = "更新成功"
else else
render :edit render admins_project_licenses_path
flash[:danger] = "更新失败" flash[:danger] = @project_license.errors.full_messages.join(",")
end end
end end
@ -98,23 +98,23 @@ class Admins::ProjectLicensesController < Admins::BaseController
params.require(:license).permit(:name,:content) params.require(:license).permit(:name,:content)
end end
def validate_params # def validate_params
name = params[:license][:name] # name = params[:license][:name]
if name.blank? # if name.blank?
flash[:danger] = "名称不允许为空" # flash[:danger] = "名称不允许为空"
redirect_to admins_project_licenses_path # redirect_to admins_project_licenses_path
elsif check_license_present?(name) && @project_license.blank? # elsif check_license_present?(name) && @project_license.blank?
flash[:danger] = "创建失败:名称已存在" # flash[:danger] = "创建失败:名称已存在"
redirect_to admins_project_licenses_path # redirect_to admins_project_licenses_path
end # end
end # end
def check_license_present?(name) # def check_license_present?(name)
return true if name.blank? # return true if name.blank?
name_downcase = name.downcase # name_downcase = name.downcase
name_upcase = name.upcase # name_upcase = name.upcase
name_first_big = name.capitalize # name_first_big = name.capitalize
License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big) # License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
end # end
end end

View File

@ -0,0 +1,55 @@
class Api::V1::BaseController < ApplicationController
include Api::ProjectHelper
include Api::UserHelper
include Api::PullHelper
# before_action :doorkeeper_authorize!
# skip_before_action :user_setup
protected
# def current_user
# #client方法对接需要一直带着用户标识uid
# Rails.logger.info doorkeeper_token
# if doorkeeper_token && doorkeeper_token.resource_owner_id.blank?
# # return User.anonymous if params[:uid].nil?
# # tip_exception("2222")
# # return render_error('缺少用户标识!') if params[:uid].nil?
# User.current = User.find(params[:uid])
# else
# User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
# end
# end
def limit
params.fetch(:limit, 15)
end
def page
params.fetch(:page, 1)
end
# 具有对仓库的管理权限
def require_manager_above
@project = load_project
return render_forbidden if !current_user.admin? && !@project.manager?(current_user)
end
# 具有对仓库的操作权限
def require_operate_above
@project = load_project
return render_forbidden if !current_user.admin? && !@project.operator?(current_user)
end
# 具有仓库的操作权限或者fork仓库的操作权限
def require_operate_above_or_fork_project
@project = load_project
puts !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
end
# 具有对仓库的访问权限
def require_public_and_member_above
@project = load_project
return render_forbidden if !@project.is_public && !current_user.admin? && !@project.member?(current_user)
end
end

View File

@ -0,0 +1,18 @@
class Api::V1::Projects::BranchesController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:all]
def all
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
end
before_action :require_operate_above, only: [:create]
def create
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
end
private
def branch_params
params.require(:branch).permit(:new_branch_name, :old_branch_name)
end
end

View File

@ -0,0 +1,8 @@
class Api::V1::Projects::CodeStatsController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:index]
def index
@result_object = Api::V1::Projects::CodeStats::ListService.call(@project, {ref: params[:ref]}, @project.owner&.gitea_token)
# puts @result_object
end
end

View File

@ -0,0 +1,12 @@
class Api::V1::Projects::CommitsController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:index, :diff]
def index
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
puts @result_object
end
def diff
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
end
end

View File

@ -0,0 +1,17 @@
class Api::V1::Projects::ContentsController < Api::V1::BaseController
before_action :require_operate_above_or_fork_project, only: [:batch]
def batch
@batch_content_params = batch_content_params
# 处理下author和committer信息如果没传则默认为当前用户信息
@batch_content_params.merge!(author_email: current_user.mail, author_name: current_user.login) if batch_content_params[:author_email].blank? && batch_content_params[:author_name].blank?
@batch_content_params.merge!(committer_email: current_user.mail, committer_name: current_user.login) if batch_content_params[:committer_email].blank? && batch_content_params[:committer_name].blank?
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, @batch_content_params, @project.owner.gitea_token)
end
private
def batch_content_params
params.require(:content).permit(:author_email, :author_name, :author_timeunix, :branch, :committer_email, :committer_name, :committer_timeunix, :message, :new_branch, files: [ :action_type, :content, :encoding, :file_path])
end
end

View File

@ -0,0 +1,12 @@
class Api::V1::Projects::GitController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:trees, :blobs]
def trees
@result_object = Api::V1::Projects::Git::TreesService.call(@project, params[:sha], {recursive: params[:recursive], page: page, limit: limit}, current_user&.gitea_token)
end
def blobs
@result_object = Api::V1::Projects::Git::BlobsService.call(@project, params[:sha], current_user&.gitea_token)
end
end

View File

@ -0,0 +1,5 @@
class Api::V1::Projects::Pulls::BaseController < Api::V1::BaseController
before_action :require_public_and_member_above
before_action :load_pull_request
end

View File

@ -0,0 +1,40 @@
class Api::V1::Projects::Pulls::JournalsController < Api::V1::Projects::Pulls::BaseController
def index
@journals = Api::V1::Projects::Pulls::Journals::ListService.call(@project, @pull_request, params, current_user)
@journals = @journals.limit(200)
end
def create
@journal = Api::V1::Projects::Pulls::Journals::CreateService.call(@project, @pull_request, create_params, current_user)
end
before_action :find_journal, only: [:update, :destroy]
def update
@journal = Api::V1::Projects::Pulls::Journals::UpdateService.call(@project, @pull_request, @journal, update_params, current_user)
end
def destroy
if @journal.destroy
render_ok
else
render_error("删除评论失败!")
end
end
private
def create_params
params.permit(:parent_id, :line_code, :note, :commit_id, :path, :type, :review_id, :diff => {})
end
def update_params
params.permit(:note, :commit_id, :state)
end
def find_journal
@journal = @pull_request.journals.find_by_id(params[:id])
return render_not_found unless @journal.present?
end
end

View File

@ -0,0 +1,20 @@
class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
before_action :require_public_and_member_above
def index
@pulls = Api::V1::Projects::Pulls::ListService.call(@project, query_params)
@pulls = kaminari_paginate(@pulls)
end
before_action :load_pull_request, only: [:show]
def show
@result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token)
@last_review = @pull_request.reviews.order(created_at: :desc).take
end
private
def query_params
params.permit(:status, :keyword, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction)
end
end

View File

@ -0,0 +1,23 @@
class Api::V1::Projects::Pulls::ReviewsController < Api::V1::Projects::Pulls::BaseController
def index
@reviews = @pull_request.reviews
@reviews = @reviews.where(status: params[:status]) if params[:status].present?
# @reviews = kaminari_paginate(@reviews)
end
before_action :require_reviewer, only: [:create]
def create
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
end
private
def require_reviewer
return render_forbidden('您没有审查权限,请联系项目管理员') if !current_user.admin? && !@pull_request.reviewers.exists?(current_user.id) && !@project.manager?(current_user)
end
def review_params
params.require(:review).permit(:content, :commit_id, :status)
end
end

View File

@ -0,0 +1,10 @@
class Api::V1::Projects::Pulls::VersionsController < Api::V1::Projects::Pulls::BaseController
def index
@result_object = Api::V1::Projects::Pulls::Versions::ListService.call(@project, @pull_request, {page: page, limit: limit}, current_user&.gitea_token)
end
def diff
@result_object = Api::V1::Projects::Pulls::Versions::GetDiffService.call(@project, @pull_request, params[:id], {filepath: params[:filepath]}, current_user&.gitea_token)
end
end

View File

@ -0,0 +1,61 @@
class Api::V1::Projects::WebhooksController < Api::V1::BaseController
before_action :require_manager_above
before_action :find_webhook, only: [:show, :update, :destroy, :tests, :hooktasks]
def index
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
@webhooks = @project.webhooks
@webhooks = @webhooks.where(type: params[:type]) if params[:type].present?
@webhooks = kaminari_paginate(@webhooks)
end
def create
return render_error("webhooks数量已到上限请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, create_webhook_params, current_user&.gitea_token)
end
def show
@result_object = Api::V1::Projects::Webhooks::GetService.call(@project, params[:id], current_user&.gitea_token)
end
def update
@result_object = Api::V1::Projects::Webhooks::UpdateService.call(@project, params[:id], webhook_params, current_user&.gitea_token)
end
def destroy
@result_object = Api::V1::Projects::Webhooks::DeleteService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('删除失败!')
end
end
def tests
@result_object = Api::V1::Projects::Webhooks::TestsService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('推送失败!')
end
end
def hooktasks
@hooktasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
@hooktasks = kaminari_paginate(@hooktasks)
end
private
def create_webhook_params
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, :type, events: [])
end
def webhook_params
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
end
def find_webhook
@webhook = Gitea::Webhook.find_by_id(params[:id])
return render_not_found unless @webhook.present?
end
end

View File

@ -0,0 +1,19 @@
class Api::V1::ProjectsController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:show, :compare, :blame]
def index
render_ok
end
def show
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
end
def compare
@result_object = Api::V1::Projects::CompareService.call(@project, params[:from], params[:to], current_user&.gitea_token)
end
def blame
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
end
end

View File

@ -0,0 +1,16 @@
class Api::V1::Users::FeedbacksController < Api::V1::BaseController
before_action :load_observe_user
before_action :check_auth_for_observe_user
def create
@result = Api::V1::Users::Feedbacks::CreateService.call(@observe_user, feedback_params)
return render_error("反馈意见创建失败.") if @result.nil?
return render_ok
end
private
def feedback_params
params.permit(:content)
end
end

View File

@ -0,0 +1,13 @@
class Api::V1::Users::ProjectsController < Api::V1::BaseController
before_action :load_observe_user
def index
@object_results = Api::V1::Users::Projects::ListService.call(@observe_user, query_params, current_user)
@projects = kaminari_paginate(@object_results)
end
private
def query_params
params.permit(:category, :is_public, :project_type, :sort_by, :sort_direction, :search)
end
end

View File

@ -0,0 +1,81 @@
class Api::V1::UsersController < Api::V1::BaseController
before_action :load_observe_user
before_action :check_auth_for_observe_user
def send_email_vefify_code
code = %W(0 1 2 3 4 5 6 7 8 9)
verification_code = code.sample(6).join
mail = params[:email]
code_type = params[:code_type]
sign = Digest::MD5.hexdigest("#{OPENKEY}#{mail}")
Rails.logger.info sign
tip_exception(501, "请求不合理") if sign != params[:smscode]
# 60s内不能重复发送
send_email_limit_cache_key = "send_email_60_second_limit:#{mail}"
tip_exception(-2, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key)
send_email_control = LimitForbidControl::SendEmailCode.new(mail)
tip_exception(-2, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
begin
UserMailer.update_email(mail, verification_code).deliver_now
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
send_email_control.increment!
rescue Exception => e
logger_error(e)
tip_exception(-2,"邮件发送失败,请稍后重试")
end
ver_params = {code_type: code_type, code: verification_code, email: mail}
last_code = VerificationCode.where(code_type: code_type, email: mail).last
last_code.update_attributes!({created_at: Time.current - 10.minute}) if last_code.present?
data = VerificationCode.new(ver_params)
if data.save!
render_ok
else
tip_exception(-1, "创建数据失败")
end
end
def check_password
password = params[:password]
return tip_exception(-5, "8~16位密码支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD
return tip_exception(-5, "密码错误") unless @observe_user.check_password?(password)
render_ok
end
def check_email
mail = strip(params[:email])
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
exist_owner = Owner.find_by(mail: mail)
return tip_exception(-2, '邮箱已被使用') if exist_owner
render_ok
end
def check_email_verify_code
code = strip(params[:code])
mail = strip(params[:email])
code_type = params[:code_type]
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last
return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试
return tip_exception(-6, "验证码不正确") if verifi_code&.code != code
return tip_exception(-6, "验证码已失效") if !verifi_code&.effective?
render_ok
end
def update_email
@result_object = Api::V1::Users::UpdateEmailService.call(@observe_user, params, current_user.gitea_token)
if @result_object
return render_ok
else
return render_error('更改邮箱失败!')
end
end
end

View File

@ -174,11 +174,11 @@ class ApplicationController < ActionController::Base
end end
def require_profile_completed def require_profile_completed
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed? # tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
end end
def require_user_profile_completed(user) def require_user_profile_completed(user)
tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed? # tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
end end
# 异常提醒 # 异常提醒
@ -248,6 +248,18 @@ class ApplicationController < ActionController::Base
#return if params[:controller] == "main" #return if params[:controller] == "main"
# Find the current user # Find the current user
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer')
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
if @doorkeeper_token.present?
# client方法对接需要一直带着用户标识uid
if @doorkeeper_token.resource_owner_id.blank?
tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
User.current = User.find(params[:uid])
else
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
end
end
else
User.current = find_current_user User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
@ -265,13 +277,15 @@ class ApplicationController < ActionController::Base
end end
end end
# if !User.current.logged? && Rails.env.development? if !User.current.logged? && Rails.env.development?
# User.current = User.find 1 user = User.find 1
# end User.current = user
start_user_session(user)
end
# 测试版前端需求 # 测试版前端需求
logger.info("subdomain:#{request.subdomain}") # logger.info("subdomain:#{request.subdomain}")
# if request.subdomain != "www" # if request.subdomain != "www"
# if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 # if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
# User.current = User.find 81403 # User.current = User.find 81403
@ -284,6 +298,7 @@ class ApplicationController < ActionController::Base
# cookies.signed[:user_id] = user.id # cookies.signed[:user_id] = user.id
# end # end
# end # end
end
# User.current = User.find 81403 # User.current = User.find 81403
end end
@ -686,18 +701,24 @@ class ApplicationController < ActionController::Base
@project, @owner = Project.find_with_namespace(namespace, id) @project, @owner = Project.find_with_namespace(namespace, id)
if @project and current_user.can_read_project?(@project) if @project and (current_user.can_read_project?(@project) || controller_path == "projects/project_invite_links")
logger.info "########### has project and can read project" logger.info "########### has project and can read project"
@project @project
# elsif @project && current_user.is_a?(AnonymousUser) # elsif @project && current_user.is_a?(AnonymousUser)
# logger.info "###########This is AnonymousUser" # logger.info "###########This is AnonymousUser"
# @project = nil if !@project.is_public? # @project = nil if !@project.is_public?
# render_forbidden and return # render_forbidden and return
else
if @project.present?
logger.info "########### has project and but can't read project"
@project = nil
render_forbidden and return
else else
logger.info "###########project not found" logger.info "###########project not found"
@project = nil @project = nil
render_not_found and return render_not_found and return
end end
end
@project @project
end end
@ -709,14 +730,20 @@ class ApplicationController < ActionController::Base
Rails.application.config_for(:configuration)['platform_url'] || request.base_url Rails.application.config_for(:configuration)['platform_url'] || request.base_url
end end
def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase)
end
def convert_image! def convert_image!
@image = params[:image] @image = params[:image]
@image = @image.nil? && params[:user].present? ? params[:user][:image] : @image @image = @image.nil? && params[:user].present? ? params[:user][:image] : @image
return unless @image.present? return unless @image.present?
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
if @image.class == ActionDispatch::Http::UploadedFile if @image.class == ActionDispatch::Http::UploadedFile
render_error('请上传文件') if @image.size.zero? return render_error('请上传文件') if @image.size.zero?
render_error('文件大小超过限制') if @image.size > max_size.to_i return render_error('文件大小超过限制') if @image.size > max_size.to_i
return render_error('头像格式不正确!') unless image_type?(File.extname(@image.original_filename.to_s)[1..-1])
else else
image = @image.to_s.strip image = @image.to_s.strip
return render_error('请上传正确的图片') if image.blank? return render_error('请上传正确的图片') if image.blank?

View File

@ -31,11 +31,11 @@ class AttachmentsController < ApplicationController
def get_file def get_file
normal_status(-1, "参数缺失") if params[:download_url].blank? normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:")) url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s)
if url.starts_with?(base_url) if url.starts_with?(base_url) && !url.starts_with?("#{base_url}/repo")
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?') url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?')
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
response = Faraday.get(request_url) response = Faraday.get(request_url)
filename = url.to_s.split("/").pop() filename = url.to_s.split("/").pop()
@ -213,20 +213,17 @@ class AttachmentsController < ApplicationController
def attachment_candown def attachment_candown
unless current_user.admin? || current_user.business? unless current_user.admin? || current_user.business?
candown = true candown = true
unless params[:type] == 'history' if @file.container
if @file.container && current_user.logged?
if @file.container.is_a?(Issue) if @file.container.is_a?(Issue)
course = @file.container.project project = @file.container.project
candown = course.member?(current_user) candown = project.is_public || (current_user.logged? && project.member?(current_user))
elsif @file.container.is_a?(Journal) elsif @file.container.is_a?(Journal)
course = @file.container.issue.project project = @file.container.issue.project
candown = course.member?(current_user) candown = project.is_public || (current_user.logged? && project.member?(current_user))
else else
course = nil project = nil
end
tip_exception(403, "您没有权限进入") if course.present? && !candown
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
end end
tip_exception(403, "您没有权限进入") if project.present? && !candown
end end
end end
end end

View File

@ -8,7 +8,7 @@ class Ci::BaseController < ApplicationController
namespace = params[:owner] namespace = params[:owner]
id = params[:repo] || params[:id] id = params[:repo] || params[:id]
@ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id) @ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id, current_user.login)
end end
def load_all_repo def load_all_repo

View File

@ -14,12 +14,12 @@ class Ci::CloudAccountsController < Ci::BaseController
def create def create
flag, msg = check_bind_cloud_account! flag, msg = check_bind_cloud_account!
return render_error(msg) if flag === true return tip_exception(msg) if flag === true
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@cloud_account = bind_account! @cloud_account = bind_account!
if @cloud_account.blank? if @cloud_account.blank?
render_error('激活失败, 请检查你的云服务器信息是否正确.') tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
else else
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
@ -27,17 +27,17 @@ class Ci::CloudAccountsController < Ci::BaseController
end end
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def activate def activate
return render_error('请先认证') unless current_user.ci_certification? return tip_exception('请先认证') unless current_user.ci_certification?
begin begin
@cloud_account = Ci::CloudAccount.find params[:id] @cloud_account = Ci::CloudAccount.find params[:id]
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
if @repo if @repo
return render_error('该项目已经激活') if @repo.repo_active? return tip_exception('该项目已经激活') if @repo.repo_active?
@repo.activate!(@project) @repo.activate!(@project)
else else
@repo = Ci::Repo.auto_create!(@ci_user, @project) @repo = Ci::Repo.auto_create!(@ci_user, @project)
@ -50,7 +50,7 @@ class Ci::CloudAccountsController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
end end
@ -59,39 +59,39 @@ class Ci::CloudAccountsController < Ci::BaseController
def bind def bind
flag, msg = check_bind_cloud_account! flag, msg = check_bind_cloud_account!
return render_error(msg) if flag === true return tip_exception(msg) if flag === true
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@cloud_account = bind_account! @cloud_account = bind_account!
if @cloud_account.blank? if @cloud_account.blank?
render_error('激活失败, 请检查你的云服务器信息是否正确.') tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
else else
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
end end
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def trustie_bind def trustie_bind
account = params[:account].to_s account = params[:account].to_s
return render_error("account不能为空.") if account.blank? return tip_exception("account不能为空.") if account.blank?
flag, msg = check_trustie_bind_cloud_account! flag, msg = check_trustie_bind_cloud_account!
return render_error(msg) if flag === true return tip_exception(msg) if flag === true
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@cloud_account = trustie_bind_account! @cloud_account = trustie_bind_account!
if @cloud_account.blank? if @cloud_account.blank?
render_error('激活失败, 请检查你的云服务器信息是否正确.') tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
else else
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
end end
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def unbind def unbind
@ -107,18 +107,18 @@ class Ci::CloudAccountsController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def oauth_grant def oauth_grant
password = params[:password].to_s password = params[:password].to_s
return render_error('你输入的密码不正确.') unless current_user.check_password?(password) return tip_exception('你输入的密码不正确.') unless current_user.check_password?(password)
oauth = current_user.oauths.last oauth = current_user.oauths.last
return render_error("服务器出小差了.") if oauth.blank? return tip_exception("服务器出小差了.") if oauth.blank?
result = gitea_oauth_grant!(password, oauth) result = gitea_oauth_grant!(password, oauth)
return render_error('授权失败.') unless result === true return tip_exception('授权失败.') unless result === true
current_user.set_drone_step!(User::DEVOPS_CERTIFICATION) current_user.set_drone_step!(User::DEVOPS_CERTIFICATION)
end end

View File

@ -30,7 +30,7 @@ class Ci::PipelinesController < Ci::BaseController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size
if size > 0 if size > 0
render_error("#{params[:branch]}分支已经存在流水线!") tip_exception("#{params[:branch]}分支已经存在流水线!")
return return
end end
pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner], pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner],
@ -53,7 +53,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok({id: pipeline.id}) render_ok({id: pipeline.id})
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
# 在代码库创建文件 # 在代码库创建文件
@ -81,6 +81,7 @@ class Ci::PipelinesController < Ci::BaseController
repo_branch: pipeline.branch, repo_branch: pipeline.branch,
repo_config: pipeline.file_name repo_config: pipeline.file_name
} }
Rails.logger.info("########create_params===#{create_params.to_json}")
repo = Ci::Repo.create_repo(create_params) repo = Ci::Repo.create_repo(create_params)
repo repo
end end
@ -118,7 +119,7 @@ class Ci::PipelinesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def destroy def destroy
@ -132,7 +133,7 @@ class Ci::PipelinesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def content def content
@ -182,7 +183,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def update_stage def update_stage
@ -192,7 +193,7 @@ class Ci::PipelinesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def delete_stage def delete_stage
@ -205,7 +206,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def update_stage_index(pipeline_id, show_index, diff) def update_stage_index(pipeline_id, show_index, diff)
@ -229,7 +230,7 @@ class Ci::PipelinesController < Ci::BaseController
unless steps.empty? unless steps.empty?
steps.each do |step| steps.each do |step|
unless step[:template_id] unless step[:template_id]
render_error('请选择模板!') tip_exception('请选择模板!')
return return
end end
if !step[:id] if !step[:id]
@ -246,7 +247,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def create_stage_step def create_stage_step
@ -262,7 +263,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def update_stage_step def update_stage_step
@ -279,7 +280,7 @@ class Ci::PipelinesController < Ci::BaseController
render_ok render_ok
end end
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def delete_stage_step def delete_stage_step
@ -289,6 +290,6 @@ class Ci::PipelinesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
end end

View File

@ -30,19 +30,19 @@ class Ci::ProjectsController < Ci::BaseController
@file = interactor.result @file = interactor.result
render_result(1, "更新成功") render_result(1, "更新成功")
else else
render_error(interactor.error) tip_exception(interactor.error)
end end
end end
def activate def activate
return render_error('你还未认证') unless current_user.ci_certification? return tip_exception('你还未认证') unless current_user.ci_certification?
begin begin
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
if @repo if @repo
return render_error('该项目已经激活') if @repo.repo_active? @repo.destroy! if @repo&.repo_user_id == 0
return tip_exception('该项目已经激活') if @repo.repo_active?
@repo.activate!(@project) @repo.activate!(@project)
return render_ok
else else
@repo = Ci::Repo.auto_create!(@ci_user, @project) @repo = Ci::Repo.auto_create!(@ci_user, @project)
@ci_user.update_column(:user_syncing, false) @ci_user.update_column(:user_syncing, false)
@ -55,12 +55,12 @@ class Ci::ProjectsController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
end end
def deactivate def deactivate
return render_error('该项目已经取消激活') if !@repo.repo_active? return tip_exception('该项目已经取消激活') if !@repo.repo_active?
@project.update_column(:open_devops, false) @project.update_column(:open_devops, false)
@repo.deactivate_repos! @repo.deactivate_repos!

View File

@ -20,14 +20,14 @@ class Ci::SecretsController < Ci::BaseController
if result["id"] if result["id"]
render_ok render_ok
else else
render_error(result["message"]) tip_exception(result["message"])
end end
else else
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret
if result["id"] if result["id"]
render_ok render_ok
else else
render_error(result["message"]) tip_exception(result["message"])
end end
end end
end end
@ -39,14 +39,14 @@ class Ci::SecretsController < Ci::BaseController
Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret
render_ok render_ok
else else
render_error("参数名不能为空") tip_exception("参数名不能为空")
end end
rescue Exception => ex rescue Exception => ex
render_ok render_ok
end end
def ci_drone_url def ci_drone_url
user = User.find_by(login: params[:owner]) user = User.find_by(login: params[:owner]) || User.find_by(login: current_user.login)
user&.ci_cloud_account.drone_url user&.ci_cloud_account.drone_url
end end

View File

@ -50,7 +50,7 @@ class Ci::TemplatesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def update def update
@ -63,7 +63,7 @@ class Ci::TemplatesController < Ci::BaseController
) )
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
def destroy def destroy
@ -73,7 +73,7 @@ class Ci::TemplatesController < Ci::BaseController
end end
render_ok render_ok
rescue Exception => ex rescue Exception => ex
render_error(ex.message) tip_exception(ex.message)
end end
#======流水线模板查询=====# #======流水线模板查询=====#

View File

@ -0,0 +1,30 @@
class CommitLogsController < ApplicationController
def create
tip_exception "未认证" unless params[:token].to_s == "7917908927b6f1b792f2027a08a8b24a2de42c1692c2fd45da0dee5cf90a5af5"
ref = params[:ref]
user_name = params[:pusher][:login]
user_mail = params[:pusher][:email]
user = User.find_by(mail: user_mail)
user = User.find_by(login: user_name) if user.blank?
repository_id = params[:repository][:id]
repository_name = params[:repository][:name]
repository_full_name = params[:repository][:full_name]
owner_name = repository_full_name.split("/")[0]
owner = User.find_by(login: owner_name)
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
project.update_column(:updated_on, Time.now) if project.present?
params[:commits].each do |commit|
commit_id = commit[:id]
message = commit[:message]
CommitLog.create(user: user, project: project, repository_id: repository_id,
name: repository_name, full_name: repository_full_name,
ref: ref, commit_id: commit_id, message: message)
# 统计数据新增
CacheAsyncSetJob.perform_later("project_common_service", {commits: 1}, project.id)
end
end
end

View File

@ -6,22 +6,33 @@ class CompareController < ApplicationController
end end
def show def show
if params[:type] == "sha"
load_compare_params
@compare_result ||= gitea_compare(@base, @head)
else
load_compare_params load_compare_params
compare compare
@merge_status, @merge_message = get_merge_message @merge_status, @merge_message = get_merge_message
end end
@page_size = page_size <= 0 ? 1 : page_size
@page_limit = page_limit <=0 ? 15 : page_limit
@page_offset = (@page_size -1) * @page_limit
Rails.logger.info("+========#{@page_size}-#{@page_limit}-#{@page_offset}")
end
private private
def get_merge_message def get_merge_message
if @base.blank? || @head.blank? if @base.blank? || @head.blank?
return -2, "请选择分支" return -2, "请选择分支"
else else
return -2, "目标仓库未开启合并请求PR功能" unless @project.has_menu_permission("pulls")
if @head.include?(":") if @head.include?(":")
fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take fork_project = @project.forked_projects.joins(:owner).where(users: { login: @head.to_s.split("/")[0] }).take
return -2, "请选择正确的仓库" unless fork_project.present? return -2, "请选择正确的仓库" unless fork_project.present?
@exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take @exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take
else else
@exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take @exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).last
end end
if @exist_pullrequest.present? 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='/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}'>#{@exist_pullrequest.try(:title)}</a>"
@ -42,12 +53,22 @@ class CompareController < ApplicationController
end end
def load_compare_params def load_compare_params
@base = Addressable::URI.unescape(params[:base]) # @base = Addressable::URI.unescape(params[:base])
@head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head] @base = params[:base].include?(":") ? Addressable::URI.unescape(params[:base].split(":")[0]) + ':' + Base64.decode64(params[:base].split(":")[1]) : Base64.decode64(params[:base])
@head = params[:head].include?('.json') ? params[:head][0..-6] : params[:head]
# @head = Addressable::URI.unescape(@head)
@head = @head.include?(":") ? Addressable::URI.unescape(@head.split(":")[0]) + ':' + Base64.decode64(@head.split(":")[1]) : Base64.decode64(@head)
end end
def gitea_compare(base, head) 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, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
end
def page_size
params.fetch(:page, 1).to_i
end
def page_limit
params.fetch(:limit, 15).to_i
end end
end end

View File

@ -18,15 +18,15 @@ module Acceleratorable
end end
def accelerator_domain def accelerator_domain
Gitea.gitea_config[:accelerator]["domain"] GiteaService.gitea_config[:accelerator]["domain"]
end end
def accelerator_username def accelerator_username
Gitea.gitea_config[:accelerator]["access_key_id"] GiteaService.gitea_config[:accelerator]["access_key_id"]
end end
def config_accelerator? def config_accelerator?
Gitea.gitea_config[:accelerator].present? GiteaService.gitea_config[:accelerator].present?
end end
def is_foreign_url?(clone_addr) def is_foreign_url?(clone_addr)

View File

@ -0,0 +1,20 @@
module Api::ProjectHelper
extend ActiveSupport::Concern
def load_project
namespace = params[:owner]
repo = params[:repo]
@project, @owner = Project.find_with_namespace(namespace, repo)
if @project
logger.info "###########project founded"
@project
else
logger.info "###########project not found"
@project = nil
render_not_found and return
end
@project
end
end

View File

@ -0,0 +1,19 @@
module Api::PullHelper
extend ActiveSupport::Concern
def load_pull_request
pull_request_id = params[:pull_id] || params[:id]
@pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id)
@issue = @pull_request&.issue
if @pull_request
logger.info "###########pull_request founded"
@pull_request
else
logger.info "###########pull_request not found"
@pull_request = nil
render_not_found and return
end
@pull_request
end
end

View File

@ -0,0 +1,28 @@
module Api::UserHelper
extend ActiveSupport::Concern
def load_observe_user
username = params[:owner]
@observe_user = User.find_by(login: username)
if @observe_user
logger.info "###########observe_user not founded"
@observe_user
else
logger.info "###########observe_user not found"
@observe_user = nil
render_not_found and return
end
@observe_user
end
# 是否具有查看用户或编辑用户的权限
def check_auth_for_observe_user
return render_forbidden unless current_user.admin? || @observe_user.id == current_user.id
end
def strip(str)
str.to_s.strip.presence
end
end

View File

@ -160,9 +160,9 @@ module Ci::CloudAccountManageable
state = SecureRandom.hex(8) state = SecureRandom.hex(8)
# redirect_uri eg: # redirect_uri eg:
# https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805 # https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805
redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login") # redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
clientId = client_id(oauth) # clientId = client_id(oauth)
grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{clientId}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}" grant_url = "#{@cloud_account.drone_url}/login"
logger.info "[gitea] grant_url: #{grant_url}" logger.info "[gitea] grant_url: #{grant_url}"
conn = Faraday.new(url: grant_url) do |req| conn = Faraday.new(url: grant_url) do |req|
@ -188,6 +188,7 @@ module Ci::CloudAccountManageable
response = conn.get response = conn.get
logger.info "[drone] response headers: #{response.headers}" logger.info "[drone] response headers: #{response.headers}"
# true
response.headers['location'].include?('error') ? false : true response.headers['location'].include?('error') ? false : true
end end

View File

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

View File

@ -11,7 +11,7 @@ module LoginHelper
def set_autologin_cookie(user) def set_autologin_cookie(user)
token = Token.get_or_create_permanent_login_token(user, "autologin") token = Token.get_or_create_permanent_login_token(user, "autologin")
sync_user_token_to_trustie(user.login, token.value) # sync_user_token_to_trustie(user.login, token.value)
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
cookie_options = { cookie_options = {
@ -108,10 +108,15 @@ module LoginHelper
def sync_pwd_to_gitea!(user, hash={}) def sync_pwd_to_gitea!(user, hash={})
return true if user.is_sync_pwd? return true if user.is_sync_pwd?
sync_params = { email: user.mail } sync_params = {
login_name: user.name,
source_id: 0,
email: user.mail
}
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash)) interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
if interactor.success? if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########" Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
user.update_column(:is_sync_pwd, true)
true true
else else
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}" Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"

View File

@ -1,30 +1,82 @@
module RegisterHelper module RegisterHelper
extend ActiveSupport::Concern extend ActiveSupport::Concern
def autologin_register(username, email, password, platform= 'forge') def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false)
result = {message: nil, user: nil} result = {message: nil, user: nil}
email = email.blank? ? "#{username}@example.org" : email
user = User.new(admin: false, login: username, mail: email, type: "User") user = User.new(admin: false, login: username, mail: email, type: "User")
user.password = password user.password = password
user.platform = platform user.platform = platform
user.phone = phone if phone.present?
user.nickname = nickname if nickname.present?
if need_edit_info
user.need_edit_info
else
user.activate user.activate
end
return unless user.valid? return unless user.valid?
create_gitea_user!(user, username, email, password)
end
def create_gitea_user!(forge_user, username, email, password=random_password)
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
if interactor.success? result = {}
gitea_user = interactor.result if interactor.success? || interactor.result[:message].to_s.include?("已被注册")
gitea_user = interactor.result[:message].to_s.include?("已被注册") ? Gitea::User::GetService.call(username, password) : interactor.result
Rails.logger.info "##### [gitea] create_gitea_user result: #{gitea_user}"
if gitea_user[:body].present?
result = Gitea::User::GenerateTokenService.call(username, password) result = Gitea::User::GenerateTokenService.call(username, password)
user.gitea_token = result['sha1'] forge_user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id'] forge_user.gitea_uid = gitea_user[:body]['id'] if gitea_user[:body].present? && gitea_user[:body]['id'] !=0
if user.save! forge_user.mail = email
UserExtension.create!(user_id: user.id) if forge_user.save
result[:user] = {id: user.id, token: user.gitea_token} 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 end
else else
result[:message] = interactor.error result[:message] = interactor.result[:message]
end
else
Rails.logger.info "##### [gitea] create_gitea_user result: #{interactor.result[:message]}"
result[:message] = interactor.result[:message]
end end
result result
end end
def random_password
"#{Random.rand(11111111)}"
end
def auto_update(user, params={})
return if params.blank?
result = {message: nil, user: nil}
before_login = user.login
user.login = params[:username]
user.password = params[:password]
user.mail = params[:email]
if user.save!
sync_params = {
password: params[:password].to_s,
email: params[:email],
login_name: params[:username],
new_name: params[:username],
source_id: 0
}
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
if interactor.success?
result[:user] = user
else
result[:message] = '用户同步Gitea失败!'
end
else
result[:message] = user.errors.full_messages.join(",")
return
end
end
end end

View File

@ -3,7 +3,7 @@ module RenderHelper
render json: { status: 0, message: 'success' }.merge(data) render json: { status: 0, message: 'success' }.merge(data)
end end
def render_error(status = -1, message = '') def render_error(message = '', status=-1)
render json: { status: status, message: message } render json: { status: status, message: message }
end end

View File

@ -5,7 +5,26 @@ module Repository::LanguagesPercentagable
result = Gitea::Repository::Languages::ListService.call(@owner.login, result = Gitea::Repository::Languages::ListService.call(@owner.login,
@repository.identifier, current_user&.gitea_token) @repository.identifier, current_user&.gitea_token)
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil @transform_language = @transform_language = result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
update_project_language(@transform_language) unless @transform_language.nil?
@transform_language
end
def update_project_language(language)
return if @project.project_language.present?
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
@project.update_column(:project_language_id, db_language.id)
rescue
return
update_project_language(@transform_language) unless @transform_language.nil?
@transform_language
end
def update_project_language(language)
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
@project.update_column(:project_language_id, db_language.id) if @project.project_language_id.nil?
rescue
return
end end
# hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781} # hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781}

View File

@ -6,14 +6,23 @@ class ForksController < ApplicationController
def create def create
@new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call @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 end
private private
def authenticate_project! def authenticate_project!
Rails.logger.info "authenticate_project1=======================#{current_user&.id},#{@project.user_id}"
Rails.logger.info "authenticate_project2=======================#{current_user&.id == @project.user_id}"
if current_user&.id == @project.user_id if current_user&.id == @project.user_id
render_result(-1, "自己不能fork自己的项目") render_result(-1, "自己不能fork自己的项目")
elsif Project.exists?(user_id: current_user.id, identifier: @project.identifier) elsif Project.exists?(user_id: current_user.id, identifier: @project.identifier)
render_result(-1, "fork失败你已拥有了这个项目") render_result(0, "fork失败你已拥有了这个项目")
end end
# return if current_user != @project.owner # return if current_user != @project.owner
# render_result(-1, "自己不能fork自己的项目") # render_result(-1, "自己不能fork自己的项目")

View File

@ -2,12 +2,12 @@ class IssueTagsController < ApplicationController
before_action :require_login, except: [:index] before_action :require_login, except: [:index]
before_action :load_repository before_action :load_repository
before_action :set_user before_action :set_user
before_action :check_issue_permission, except: :index before_action :check_issue_tags_permission
before_action :set_issue_tag, only: [:edit, :update, :destroy] before_action :set_issue_tag, only: [:edit, :update, :destroy]
def index def index
issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}") issue_tags = @project.issue_tags.includes(:issues).reorder("issue_tags.#{order_name} #{order_type}")
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user)) @user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
@page = params[:page] || 1 @page = params[:page] || 1
@limit = params[:limit] || 15 @limit = params[:limit] || 15
@ -17,7 +17,7 @@ class IssueTagsController < ApplicationController
def create def create
title = params[:name].to_s.strip.first(10) title = params[:name].to_s.strip.first(15)
desc = params[:description].to_s.first(30) desc = params[:description].to_s.first(30)
color = params[:color] || "#ccc" color = params[:color] || "#ccc"
@ -29,7 +29,7 @@ class IssueTagsController < ApplicationController
if title.present? if title.present?
if IssueTag.exists?(name: title, project_id: @project.id) if IssueTag.exists?(name: title, project_id: @project.id)
normal_status(-1, "标签已存在") normal_status(-1, "项目标记已存在")
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@ -37,12 +37,12 @@ class IssueTagsController < ApplicationController
if issue_tag.save if issue_tag.save
# gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call # gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call
# if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"]) # if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"])
# normal_status(0, "标签创建成功") normal_status(0, "项目标记创建成功!")
# else # else
# normal_status(-1, "标签创建失败") # normal_status(-1, "项目标记创建失败")
# end # end
else else
normal_status(-1, "标签创建失败") normal_status(-1, "项目标记创建失败")
end end
rescue => e rescue => e
puts "create version release error: #{e.message}" puts "create version release error: #{e.message}"
@ -51,7 +51,7 @@ class IssueTagsController < ApplicationController
end end
end end
else else
normal_status(-1, "标签名称不能为空") normal_status(-1, "项目标记名称不能为空")
end end
end end
@ -60,8 +60,8 @@ class IssueTagsController < ApplicationController
end end
def update def update
title = params[:name] title = params[:name].to_s.strip.first(15)
desc = params[:description] desc = params[:description].to_s.first(30)
color = params[:color] || "#ccc" color = params[:color] || "#ccc"
tag_params = { tag_params = {
@ -71,19 +71,19 @@ class IssueTagsController < ApplicationController
} }
if title.present? if title.present?
if IssueTag.exists?(name: title, project_id: @project.id) && (@issue_tag.name != title) if IssueTag.exists?(name: title, project_id: @project.id) && (@issue_tag.name != title)
normal_status(-1, "标签已存在") normal_status(-1, "项目标记已存在")
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
if @issue_tag.update_attributes(tag_params) if @issue_tag.update_attributes(tag_params)
# gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call # gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call
# if gitea_tag # if gitea_tag
# normal_status(0, "标签更新成功") # normal_status(0, "项目标记更新成功")
# else # else
# normal_status(-1, "标签更新失败") # normal_status(-1, "项目标记更新失败")
# end # end
else else
normal_status(-1, "标签更新失败") normal_status(-1, "项目标记更新失败")
end end
rescue => e rescue => e
puts "create version release error: #{e.message}" puts "create version release error: #{e.message}"
@ -92,7 +92,7 @@ class IssueTagsController < ApplicationController
end end
end end
else else
normal_status(-1, "标签名称不能为空") normal_status(-1, "项目标记名称不能为空")
end end
end end
@ -102,12 +102,12 @@ class IssueTagsController < ApplicationController
if @issue_tag.destroy if @issue_tag.destroy
# issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call # issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call
# if issue_tag # if issue_tag
# normal_status(0, "标签删除成功") # normal_status(0, "项目标记删除成功")
# else # else
# normal_status(-1, "标签删除失败") # normal_status(-1, "项目标记删除失败")
# end # end
else else
normal_status(-1, "标签删除失败") normal_status(-1, "项目标记删除失败")
end end
rescue => e rescue => e
puts "create version release error: #{e.message}" puts "create version release error: #{e.message}"
@ -122,16 +122,16 @@ class IssueTagsController < ApplicationController
@user = @project.owner @user = @project.owner
end end
def check_issue_permission def check_issue_tags_permission
unless @project.member?(current_user) || current_user.admin? unless @project.manager?(current_user) || current_user.admin?
normal_status(-1, "您没有权限") return render_forbidden('你不是管理员,没有权限操作')
end end
end end
def set_issue_tag def set_issue_tag
@issue_tag = IssueTag.find_by_id(params[:id]) @issue_tag = IssueTag.find_by_id(params[:id])
unless @issue_tag.present? unless @issue_tag.present?
normal_status(-1, "标签不存在") normal_status(-1, "项目标记不存在")
end end
end end

View File

@ -15,6 +15,7 @@ class IssuesController < ApplicationController
include TagChosenHelper include TagChosenHelper
def index def index
@user_operate_issue = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user))
@user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user) || @project.is_public?) @user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user) || @project.is_public?)
issues = @project.issues.issue_issue.issue_index_includes issues = @project.issues.issue_issue.issue_index_includes
issues = issues.where(is_private: false) unless @user_admin_or_member issues = issues.where(is_private: false) unless @user_admin_or_member
@ -23,13 +24,13 @@ class IssuesController < ApplicationController
@filter_issues = @all_issues @filter_issues = @all_issues
@filter_issues = @filter_issues.where.not(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::ADD @filter_issues = @filter_issues.where.not(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::ADD
@filter_issues = @filter_issues.where(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::SOLVING @filter_issues = @filter_issues.where(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::SOLVING
@filter_issues = @filter_issues.where("subject LIKE ? OR description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present? @filter_issues = @filter_issues.where("issues.subject LIKE ? OR issues.description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
@open_issues = @all_issues.where.not(status_id: IssueStatus::CLOSED) @open_issues = @all_issues.where.not(status_id: IssueStatus::CLOSED)
@close_issues = @all_issues.where(status_id: IssueStatus::CLOSED) @close_issues = @all_issues.where(status_id: IssueStatus::CLOSED)
@assign_to_me = @filter_issues.where(assigned_to_id: current_user&.id)
@my_published = @filter_issues.where(author_id: current_user&.id)
scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "Issue") scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "Issue")
@issues_size = scopes.size @issues_size = scopes.size
@assign_to_me = scopes.where(assigned_to_id: current_user&.id)
@my_published = scopes.where(author_id: current_user&.id)
@issues = paginate(scopes) @issues = paginate(scopes)
respond_to do |format| respond_to do |format|
@ -108,7 +109,7 @@ class IssuesController < ApplicationController
def create def create
issue_params = issue_send_params(params) issue_params = issue_send_params(params)
Issues::CreateForm.new({subject:issue_params[:subject]}).validate! Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
@issue = Issue.new(issue_params) @issue = Issue.new(issue_params)
if @issue.save! if @issue.save!
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
@ -125,9 +126,15 @@ class IssuesController < ApplicationController
end end
end end
if params[:issue_tag_ids].present? if params[:issue_tag_ids].present?
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
return normal_status(-1, "最多只能创建一个标记。")
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
params[:issue_tag_ids].each do |tag| params[:issue_tag_ids].each do |tag|
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end end
else
return normal_status(-1, "请输入正确的标记。")
end
end end
if params[:assigned_to_id].present? if params[:assigned_to_id].present?
Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id, Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id,
@ -142,11 +149,13 @@ class IssuesController < ApplicationController
end end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE) if params[:status_id].to_i == 5
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}" 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 AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
render json: {status: 0, message: "创建成", id: @issue.id} render json: {status: 0, message: "创建成", id: @issue.id}
else else
normal_status(-1, "创建失败") normal_status(-1, "创建失败")
end end
@ -165,10 +174,17 @@ class IssuesController < ApplicationController
last_token = @issue.token last_token = @issue.token
last_status_id = @issue.status_id last_status_id = @issue.status_id
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank? @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? if params[:issue_tag_ids].present?
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
return normal_status(-1, "最多只能创建一个标记。")
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
@issue&.issue_tags_relates&.destroy_all @issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag| params[:issue_tag_ids].each do |tag|
IssueTagsRelate.create(issue_id: @issue.id, issue_tag_id: tag) next if tag == [""]
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end
else
return normal_status(-1, "请输入正确的标记。")
end end
end end
@ -207,7 +223,7 @@ class IssuesController < ApplicationController
normal_status(-1, "不允许修改为关闭状态") normal_status(-1, "不允许修改为关闭状态")
else else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) 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], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
if @issue.update_attributes(issue_params) if @issue.update_attributes(issue_params)
if @issue&.pull_request.present? 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('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?
@ -231,7 +247,7 @@ class IssuesController < ApplicationController
end end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now) @issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project! # @issue.update_closed_issues_count_in_project!
if @issue.issue_type.to_s == "2" && last_status_id != 5 if @issue.issue_type.to_s == "2" && last_status_id != 5
if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))
@ -473,7 +489,8 @@ class IssuesController < ApplicationController
end end
def operate_issue_permission def operate_issue_permission
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || @project.is_public?) @issue = Issue.find_by_id(params[:id]) unless @issue.present?
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || (@project.is_public && @issue.nil?) || (@project.is_public && @issue.present? && @issue.author_id == current_user.id))
end end
def export_issues(issues) def export_issues(issues)

View File

@ -23,6 +23,7 @@ class JournalsController < ApplicationController
normal_status(-1, "评论内容不能为空") normal_status(-1, "评论内容不能为空")
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Journals::CreateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
journal_params = { journal_params = {
journalized_id: @issue.id , journalized_id: @issue.id ,
journalized_type: "Issue", journalized_type: "Issue",
@ -53,6 +54,9 @@ class JournalsController < ApplicationController
end end
end end
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def destroy def destroy
@ -71,6 +75,7 @@ class JournalsController < ApplicationController
def update def update
content = params[:content] content = params[:content]
if content.present? if content.present?
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
if @journal.update_attribute(:notes, content) if @journal.update_attribute(:notes, content)
normal_status(0, "更新成功") normal_status(0, "更新成功")
else else
@ -79,7 +84,9 @@ class JournalsController < ApplicationController
else else
normal_status(-1, "评论的内容不能为空") normal_status(-1, "评论的内容不能为空")
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def get_children_journals def get_children_journals

View File

@ -21,6 +21,14 @@ class MainController < ApplicationController
uid_logger("main start is #{cookies[:_educoder_session]}") uid_logger("main start is #{cookies[:_educoder_session]}")
end 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后再路由分发 # TODO: 这块之后需要整合者架构重新变化统一跳转到index后再路由分发
if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild" 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, :content_type=> 'text/html'

View File

@ -0,0 +1,56 @@
class MarkFilesController < ApplicationController
before_action :require_login
before_action :load_project
before_action :load_pull_request
def index
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token, { "only-file-name": true })
@mark_files = MarkFile.where(pull_request_id: @pull_request.id)
end
def create
# unless @pull_request.mark_files.present?
# MarkFile.bulk_insert(*%i[pull_request_id, file_path_sha file_path created_at updated_at]) do |worker|
# @files_result['Files'].each do |file|
# worker.add(pull_request_id: @pull_request.id, file_path_sha: SecureRandom.uuid.gsub("-", ""), file_path: file['Name'])
# end
# end
# end
end
def mark_file_as_unread
tip_exception "参数错误" if params[:file_path_sha].blank?
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
mark_file.file_path = file_path
mark_file.user_id = current_user.id
mark_file.mark_as_read = false
mark_file.save
render_ok
rescue Exception => e
tip_exception "参数解析错误"
end
def mark_file_as_read
tip_exception "参数错误" if params[:file_path_sha].blank?
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
mark_file.file_path = file_path
mark_file.user_id = current_user.id
mark_file.mark_as_read = true
mark_file.save
render_ok
rescue Exception => e
tip_exception "参数解析错误"
end
private
def review_params
params.require(:review).permit(:content, :commit_id, :status)
end
def load_pull_request
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
end
end

View File

@ -3,11 +3,19 @@ class MembersController < ApplicationController
before_action :load_project before_action :load_project
before_action :find_user_with_id, only: %i[create remove change_role] before_action :find_user_with_id, only: %i[create remove change_role]
before_action :check_user_profile_completed, only: [:create] before_action :check_user_profile_completed, only: [:create]
before_action :operate!, except: %i[index] before_action :operate!
before_action :check_member_exists!, only: %i[create] before_action :check_member_exists!, only: %i[create]
before_action :check_member_not_exists!, only: %i[remove change_role] before_action :check_member_not_exists!, only: %i[remove change_role]
def create 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) 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('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? SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
@ -26,6 +34,9 @@ class MembersController < ApplicationController
@total_count = scope.size @total_count = scope.size
@members = paginate(scope) @members = paginate(scope)
if @project.owner.is_a?(Organization) && (params[:page].to_i == 1 || params[:page].blank?) && !@project.members.exists?(user_id: current_user.id)
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
end
end end
def remove def remove
@ -61,11 +72,14 @@ class MembersController < ApplicationController
end end
def check_member_exists! def check_member_exists!
return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists? @current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
return render_error("#{@user&.nickname}已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?)
end end
def check_member_not_exists! def check_member_not_exists!
return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists? @current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
return render_error("用户为组织成员,请到组织下操作!") if (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) && !member_exists?
return render_error("#{@user&.nickname}还不是项目成员") unless member_exists?
end end
def check_user_profile_completed def check_user_profile_completed

View File

@ -0,0 +1,33 @@
class NoticesController < ApplicationController
def create
return tip_exception("参数有误") if params["source"].blank?
user_id = params[:user_id]
if params["source"] == "CompetitionBegin"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionBegin', user_id, competition_id)
elsif params["source"] == "CompetitionResult"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionResult', user_id, competition_id)
elsif params["source"] == "CompetitionReview"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id)
elsif params["source"] == "CustomTip"
users_id = params[:users_id]
props = params[:props].to_unsafe_hash
return tip_exception("参数有误") unless props.is_a?(Hash) && users_id.is_a?(Array)
template_id = params[:template_id]
SendTemplateMessageJob.perform_later('CustomTip', users_id, template_id, props)
else
tip_exception("#{params["source"]}未配置")
end
render_ok
end
private
def params_props
params.require(:notice).permit(:props)
end
end

View File

@ -0,0 +1,17 @@
class NpsController < ApplicationController
before_action :require_login
# close,关闭
# createIssue,创建issue
# createPullRequest,创建PR
# auditPullRequest,审核PR
# indexProject,项目主页
# createProject,创建项目
# createOrganization,创建组织
def create
tip_exception "缺少参数" if params[:action_id].blank? || params[:action_type].blank?
UserNp.create(:action_id => params[:action_id].to_i, :action_type => params[:action_type], :user_id => User.current.id, :score => params[:score].to_f, memo: params[:memo])
render_ok
end
end

View File

@ -2,6 +2,7 @@ class Oauth::BaseController < ActionController::Base
include RenderHelper include RenderHelper
include LoginHelper include LoginHelper
include ControllerRescueHandler include ControllerRescueHandler
include RegisterHelper
# include LaboratoryHelper # include LaboratoryHelper
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
@ -22,7 +23,7 @@ class Oauth::BaseController < ActionController::Base
end end
def auth_hash def auth_hash
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") # Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
request.env['omniauth.auth'] request.env['omniauth.auth']
end end

View File

@ -0,0 +1,68 @@
class Oauth::CallbacksController < Oauth::BaseController
def create
process_callback
rescue Exception => e
Rails.logger.info "授权失败:#{e}"
tip_exception("授权失败")
end
private
def config_providers
config = Rails.application.config_for(:configuration)
config.dig("oauth").keys
end
# QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"}
def process_callback
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
if auth_hash.blank?
redirect_to("/login") && return
end
new_user = false
platform = auth_hash[:provider]
uid = auth_hash[:uid]
mail = auth_hash.info.email || nil
nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid)
if open_user.present? && open_user.user.present?
successful_authentication(open_user.user)
else
if current_user.blank? || !current_user.logged?
has_user = User.find_by(mail: mail)
if has_user.present?
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra)
successful_authentication(has_user)
else
new_user = true
login = build_login_name(platform, auth_hash.info.nickname)
mail = "#{login}@example.org" if mail.blank?
code = %W(0 1 2 3 4 5 6 7 8 9)
rand_password = code.sample(10).join
reg_result = autologin_register(login, mail, rand_password, platform, nil, nickname)
Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ")
if reg_result[:message].blank?
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra)
successful_authentication(open_user.user)
else
tip_exception(reg_result.present? ? reg_result[:message] : "授权失败")
end
end
else
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra)
end
end
redirect_to root_path(new_user: new_user)
end
# gitee,github nickname=login,如果系统未占用保留原用户名
def build_login_name(provider, nickname)
if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank?
nickname
else
User.generate_user_login('p')
end
end
end

View File

@ -0,0 +1,130 @@
class ObRepositorySyncsController < ApplicationController
before_action :require_login
before_action :load_project
before_action :load_ob_repository_sync, except: [:create]
before_action :authenticate_user!
def index
render_ok(data: @ob_repository_sync)
end
def create
tip_exception "参数错误" if params[:github_address].blank? && params[:gitee_address].blank?
project_name ="#{@project.owner.name}:#{@project.identifier}"
service = ObRepositorySync::ApiService.new(project_name)
domain = GiteaService.gitea_config[:domain]
project_params = params.merge({ "gitlink_address": "#{domain}/#{@project.owner&.login}/#{@project.identifier}.git" })
res = service.create_projects(project_params)
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
sync_id = res["data"]["id"]
ob_repository_sync = ObRepositorySync.find_or_initialize_by(project_id: @project.id)
ob_repository_sync.project_id = @project.id
ob_repository_sync.user_id = current_user.id
ob_repository_sync.name = project_name
ob_repository_sync.github_address = "#{params[:github_address]}"
ob_repository_sync.gitee_address = "#{params[:gitee_address]}"
ob_repository_sync.github_token = "#{params[:github_token]}"
ob_repository_sync.gitee_token = "#{params[:gitee_token]}"
ob_repository_sync.sync_id = sync_id
ob_repository_sync.save!
render_ok
end
def delete
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.delete_project @ob_repository_sync.sync_id
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
if res["code"].to_s == "200"
@ob_repository_sync.destroy!
end
render_ok
end
def jobs
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
page = params[:page] || 1
limit = params[:limit] || 10
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
source = ""
if params[:type] && params[:type].to_s.downcase == "github"
source = "github_branch"
elsif params[:type] && params[:type].to_s.downcase == "gitee"
source = "gitee_branch"
end
res = service.get_projects_jobs(source, page, limit)
data = res["data"]["list"]
render_ok(count: res["data"]["total"], data: data)
end
def create_jobs
tip_exception "必须配置一个分支" if params[:github_branch].blank? && params[:gitee_branch].blank? && params[:gitlink_branch].blank?
ob_jobs = ObRepositorySyncJob.where(ob_repository_sync_id: @ob_repository_sync.id)
ob_jobs = ob_jobs.where(job_type: params[:job_type]) if params[:job_type].present?
ob_jobs = ob_jobs.where(github_branch: params[:github_branch]) if params[:github_branch].present?
ob_jobs = ob_jobs.where(gitee_branch: params[:gitee_branch]) if params[:gitee_branch].present?
ob_jobs = ob_jobs.where(gitlink_branch: params[:gitlink_branch]) if params[:gitlink_branch].present?
tip_exception "该分支组合已配置,不能重复!" if ob_jobs.count > 0
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.create_projects_jobs(params)
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
job_id = res["data"]["id"]
job = ObRepositorySyncJob.new
job.ob_repository_sync_id = @ob_repository_sync.id
job.github_branch = "#{params[:github_branch]}"
job.gitee_branch = "#{params[:gitee_branch]}"
job.gitlink_branch = "#{params[:gitlink_branch]}"
job.job_type = "#{params[:job_type]}"
job.base = "#{params[:base]}"
job.job_id = job_id
job.save
render_ok
end
def delete_job
tip_exception "缺少参数job_id" if params[:job_id].blank?
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.delete_job params[:job_id]
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
job = ObRepositorySyncJob.find_by(ob_repository_sync_id: @ob_repository_sync.id, job_id: params[:job_id])
job.destroy! if job.present?
render_ok
end
def start_job
tip_exception "缺少参数job_id" if params[:job_id].blank?
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.start_job params[:job_id]
tip_exception "启动错误: #{res["msg"]}" if res["code"].to_s != "200"
render_ok
end
def stop_job
tip_exception "缺少参数job_id" if params[:job_id].blank?
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.stop_job params[:job_id]
tip_exception "停止错误: #{res["msg"]}" if res["code"].to_s != "200"
render_ok
end
def job_logs
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
tip_exception "缺少参数job_id" if params[:job_id].blank?
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
res = service.job_logs params[:job_id]
tip_exception "请求错误: #{res["msg"]}" if res["code"].to_s != "200"
render_ok(count: res["data"]["total"], data: res["data"]["list"])
end
private
def load_ob_repository_sync
@ob_repository_sync = ObRepositorySync.find_by(project_id: @project.id)
end
def authenticate_user!
return if @project.member?(current_user) || current_user.admin?
render_forbidden('你没有权限操作')
end
end

View File

@ -4,8 +4,14 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
def index def index
@organization_users = @organization.organization_users.includes(:user) @organization_users = @organization.organization_users.includes(:user)
if params[:search].present?
search = params[:search].to_s.downcase search = params[:search].to_s.downcase
@organization_users = @organization_users.joins(:user).merge(User.like(search)) user_condition_users = User.like(search).to_sql
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
@organization_users = @organization_users.where(user_id: users).distinct
end
@organization_users = kaminari_paginate(@organization_users) @organization_users = kaminari_paginate(@organization_users)
end end

View File

@ -28,9 +28,10 @@ class Organizations::OrganizationsController < Organizations::BaseController
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name]) tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name])
Organizations::CreateForm.new(organization_params).validate! Organizations::CreateForm.new(organization_params.merge(original_name: "")).validate!
@organization = Organizations::CreateService.call(current_user, organization_params) @organization = Organizations::CreateService.call(current_user, organization_params)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present? Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
Cache::V2::OwnerCommonService.new(@organization.id).reset
end end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
@ -39,15 +40,16 @@ class Organizations::OrganizationsController < Organizations::BaseController
def update def update
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Organizations::CreateForm.new(organization_params).validate! Organizations::CreateForm.new(organization_params.merge(original_name: @organization.login)).validate!
login = @organization.login login = @organization.login
@organization.login = organization_params[:name] if organization_params[:name].present? @organization.login = organization_params[:name] if organization_params[:name].present?
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present? @organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
@organization.save! @organization.save!
sync_organization_extension! sync_organization_extension!
Gitea::Organization::UpdateService.call(@organization.gitea_token, login, @organization.reload) Gitea::Organization::UpdateService.call(current_user.gitea_token, login, @organization.reload)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present? Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
Cache::V2::OwnerCommonService.new(@organization.id).reset
end end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
@ -57,10 +59,16 @@ class Organizations::OrganizationsController < Organizations::BaseController
def destroy def destroy
tip_exception("密码不正确") unless current_user.check_password?(password) tip_exception("密码不正确") unless current_user.check_password?(password)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Gitea::Organization::DeleteService.call(@organization.gitea_token, @organization.login) gitea_destroy = Gitea::Organization::DeleteService.call(current_user.gitea_token, @organization.login)
if gitea_destroy[:status] == 204
@organization.destroy! @organization.destroy!
end
render_ok render_ok
elsif gitea_destroy[:status] == 500
tip_exception("当组织内含有仓库时,无法删除此组织")
else
tip_exception("")
end
end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception(e.message) tip_exception(e.message)

View File

@ -21,6 +21,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
tip_exception(e.message) tip_exception(e.message)
end end
def create_all
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
ActiveRecord::Base.transaction do
@organization.projects.each do |project|
TeamProject.build(@organization.id, @team.id, project.id)
end
Gitea::Organization::TeamProject::CreateAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
render_ok
end
end
def destroy def destroy
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@ -33,6 +44,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
tip_exception(e.message) tip_exception(e.message)
end end
def destroy_all
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
ActiveRecord::Base.transaction do
@team.team_projects.each do |project|
project.destroy!
end
Gitea::Organization::TeamProject::DeleteAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
render_ok
end
end
private private
def load_organization def load_organization
@organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id]) @organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id])
@ -47,7 +69,7 @@ class Organizations::TeamProjectsController < Organizations::BaseController
end end
def load_operate_project def load_operate_project
@operate_project = Project.find_by(id: project_mark) || Project.find_by(identifier: project_mark) @operate_project = @organization.projects.where(id: project_mark).take || @organization.projects.where(identifier: project_mark).take
tip_exception("项目不存在") if @operate_project.nil? tip_exception("项目不存在") if @operate_project.nil?
end end

View File

@ -18,7 +18,7 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@team_user = TeamUser.build(@organization.id, @operate_user.id, @team.id) @team_user = TeamUser.build(@organization.id, @operate_user.id, @team.id)
@organization_user = OrganizationUser.build(@organization.id, @operate_user.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? SendTemplateMessageJob.perform_later('TeamJoined', @operate_user.id, @organization.id, @team.id) if Site.has_notice_menu?
Gitea::Organization::TeamUser::CreateService.call(@organization.gitea_token, @team.gtid, @operate_user.login) Gitea::Organization::TeamUser::CreateService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
end end
rescue Exception => e rescue Exception => e
@ -31,6 +31,7 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@team_user.destroy! @team_user.destroy!
Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, @operate_user.login) Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
SendTemplateMessageJob.perform_later('TeamLeft', @operate_user.id, @organization.id, @team.id) if Site.has_notice_menu?
org_team_users = @organization.team_users.where(user_id: @operate_user.id) org_team_users = @organization.team_users.where(user_id: @operate_user.id)
unless org_team_users.present? unless org_team_users.present?
@organization.organization_users.find_by(user_id: @operate_user.id).destroy! @organization.organization_users.find_by(user_id: @operate_user.id).destroy!

View File

@ -4,6 +4,14 @@ class Organizations::TeamsController < Organizations::BaseController
before_action :check_user_can_edit_org, only: [:create, :update, :destroy] before_action :check_user_can_edit_org, only: [:create, :update, :destroy]
def index def index
if params[:is_full].present?
if can_edit_org?
@teams = @organization.teams
else
@teams = []
end
else
#if @organization.is_owner?(current_user) || current_user.admin? #if @organization.is_owner?(current_user) || current_user.admin?
@teams = @organization.teams @teams = @organization.teams
#else #else
@ -14,6 +22,7 @@ class Organizations::TeamsController < Organizations::BaseController
@teams = kaminari_paginate(@teams) @teams = kaminari_paginate(@teams)
end end
end
def search def search
tip_exception("请输入搜索关键词") if params[:search].nil? tip_exception("请输入搜索关键词") if params[:search].nil?
@ -34,9 +43,13 @@ class Organizations::TeamsController < Organizations::BaseController
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
if @organization.teams.count >= 50
return tip_exception("组织的团队数量已超过限制!")
else
Organizations::CreateTeamForm.new(team_params).validate! Organizations::CreateTeamForm.new(team_params).validate!
@team = Organizations::Teams::CreateService.call(current_user, @organization, team_params) @team = Organizations::Teams::CreateService.call(current_user, @organization, team_params)
end end
end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception(e.message) tip_exception(e.message)

View File

@ -20,7 +20,7 @@ class OwnersController < ApplicationController
@is_admin = current_user.admin? || @owner.is_owner?(current_user.id) @is_admin = current_user.admin? || @owner.is_owner?(current_user.id)
@is_member = @owner.is_member?(current_user.id) @is_member = @owner.is_member?(current_user.id)
# 用户 # 用户
else elsif @owner.is_a?(User)
#待办事项,现在未做 #待办事项,现在未做
if User.current.admin? || User.current.login == @owner.login if User.current.admin? || User.current.login == @owner.login
@waiting_applied_messages = @owner.applied_messages.waiting @waiting_applied_messages = @owner.applied_messages.waiting
@ -45,7 +45,6 @@ class OwnersController < ApplicationController
@projects_common_count = user_projects.common.size @projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size @projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size @projects_sync_mirrior_count = user_projects.sync_mirror.size
puts @owner.as_json
end end
end end

View File

@ -12,6 +12,7 @@ class PraiseTreadController < ApplicationController
begin begin
return normal_status(2, "你已点过赞了") if current_user.liked?(@project) return normal_status(2, "你已点过赞了") if current_user.liked?(@project)
current_user.like!(@project) current_user.like!(@project)
SendTemplateMessageJob.perform_later('ProjectPraised', current_user.id, @project.id) if Site.has_notice_menu?
render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)}) render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)})
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)

View File

@ -10,7 +10,7 @@ class ProjectCategoriesController < ApplicationController
end end
def group_list def group_list
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc) @project_categories = ProjectCategory.select("id, name, projects_count, private_projects_count, (projects_count - private_projects_count) as public_projects_count").having('public_projects_count > 0').order(public_projects_count: :desc)
# projects = Project.no_anomory_projects.visible # projects = Project.no_anomory_projects.visible
# @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size # @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size
end end

View File

@ -3,7 +3,7 @@ class ProjectTrendsController < ApplicationController
before_action :check_project_public before_action :check_project_public
def index def index
project_trends = @project.project_trends.preload(:user, trend: :user) project_trends = @project.project_trends.preload(:user, trend: :user, project: :owner)
check_time = params[:time] #时间的筛选 check_time = params[:time] #时间的筛选
check_type = params[:type] #动态类型的筛选,目前已知的有 Issue, PullRequest, Version check_type = params[:type] #动态类型的筛选,目前已知的有 Issue, PullRequest, Version

View File

@ -0,0 +1,42 @@
class Projects::ProjectInviteLinksController < Projects::BaseController
before_action :require_manager!, except: [:show_link, :redirect_link]
before_action :require_login
def current_link
role = params[:role]
is_apply = params[:is_apply]
return render_error('请输入正确的参数!') unless role.present? && is_apply.present?
@project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id, role: role, is_apply: is_apply)
@project_invite_link = ProjectInviteLink.build!(@project, current_user, role, is_apply) unless @project_invite_link.present?
end
def generate_link
ActiveRecord::Base.transaction do
params_data = link_params.merge({user_id: current_user.id, project_id: @project.id})
Projects::ProjectInviteLinks::CreateForm.new(params_data).validate!
@project_invite_link = ProjectInviteLink.build!(project, user, params_data[:role], params_data[:is_apply])
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show_link
@project_invite_link = ProjectInviteLink.find_by(sign: params[:invite_sign])
return render_not_found unless @project_invite_link.present?
end
def redirect_link
Projects::LinkJoinService.call(current_user, @project, params[:invite_sign])
render_ok
rescue Exception => e
uid_logger_error(e.message)
normal_status(-1, e.message)
end
private
def link_params
params.require(:project_invite_link).permit(:role, :is_apply)
end
end

View File

@ -9,7 +9,7 @@ class Projects::WebhooksController < Projects::BaseController
def create def create
ActiveRecord::Base.transaction do 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? return render_error("参数错误.") unless webhook_params.present?
form = Projects::Webhooks::CreateForm.new(webhook_params) form = Projects::Webhooks::CreateForm.new(webhook_params)
return render json: {status: -1, message: form.errors} unless form.validate! return render json: {status: -1, message: form.errors} unless form.validate!

View File

@ -13,16 +13,20 @@ class ProjectsController < ApplicationController
def menu_list def menu_list
menu = [] menu = []
user_is_admin = current_user.admin? || @project.manager?(current_user)
menu.append(menu_hash_by_name("home")) menu.append(menu_hash_by_name("home"))
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code") 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("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("pulls")) if @project.has_menu_permission("pulls") && @project.forge?
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") && @project.forge?
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("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("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
menu.append(menu_hash_by_name("activity")) 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("sonar"))
menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge?
menu.append(menu_hash_by_name("quit")) if !user_is_admin && @project.member(current_user.id) && @project.forge?
render json: menu render json: menu
end end
@ -36,8 +40,9 @@ class ProjectsController < ApplicationController
category_id = params[:category_id] category_id = params[:category_id]
@total_count = @total_count =
if category_id.blank? if category_id.blank?
ps = ProjectStatistic.first # ps = ProjectStatistic.first
ps.common_projects_count + ps.mirror_projects_count unless ps.blank? # ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
@projects.total_count
else else
cate = ProjectCategory.find_by(id: category_id) cate = ProjectCategory.find_by(id: category_id)
cate&.projects_count || 0 cate&.projects_count || 0
@ -49,6 +54,13 @@ class ProjectsController < ApplicationController
Projects::CreateForm.new(project_params).validate! Projects::CreateForm.new(project_params).validate!
@project = Projects::CreateService.new(current_user, project_params).call @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 end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
@ -59,7 +71,7 @@ class ProjectsController < ApplicationController
Projects::MigrateForm.new(mirror_params).validate! Projects::MigrateForm.new(mirror_params).validate!
@project = @project =
if enable_accelerator?(mirror_params[:clone_addr]) if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr])
source_clone_url = mirror_params[:clone_addr] source_clone_url = mirror_params[:clone_addr]
uid_logger("########## 已动加速器 ##########") uid_logger("########## 已动加速器 ##########")
result = Gitea::Accelerator::MigrateService.call(mirror_params) result = Gitea::Accelerator::MigrateService.call(mirror_params)
@ -71,6 +83,11 @@ class ProjectsController < ApplicationController
else else
Projects::MigrateService.call(current_user, mirror_params) Projects::MigrateService.call(current_user, mirror_params)
end end
elsif EduSetting.get("mirror_address").to_s.include?("cnpmjs") && mirror_params[:clone_addr].include?("github.com")
source_clone_url = mirror_params[:clone_addr]
clone_url = source_clone_url.gsub('github.com', 'github.com.cnpmjs.org')
uid_logger("########## 更改clone_addr ##########")
Projects::MigrateService.call(current_user, mirror_params.merge(source_clone_url: source_clone_url, clone_addr: clone_url))
else else
Projects::MigrateService.call(current_user, mirror_params) Projects::MigrateService.call(current_user, mirror_params)
end end
@ -82,8 +99,9 @@ class ProjectsController < ApplicationController
def branches def branches
return @branches = [] unless @project.forge? return @branches = [] unless @project.forge?
result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier) # result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
@branches = result.is_a?(Hash) && result.key?(:status) ? [] : result result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name])
@branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result
end end
def branches_slice def branches_slice
@ -94,18 +112,18 @@ class ProjectsController < ApplicationController
end end
def group_type_list def group_type_list
project_statics = ProjectStatistic.first # project_statics = ProjectStatistic.first
@project_statics_list = [ @project_statics_list = [
{ {
project_type: 'common', project_type: 'common',
name: '开源托管项目', name: '开源托管项目',
projects_count: project_statics&.common_projects_count || 0 projects_count: Project.common.size || 0
}, },
{ {
project_type: 'mirror', project_type: 'mirror',
name: '开源镜像项目', name: '开源镜像项目',
projects_count: project_statics&.mirror_projects_count || 0 projects_count: Project.sync_mirror.size + Project.mirror.size || 0
} }
] ]
@ -129,7 +147,7 @@ class ProjectsController < ApplicationController
validate_params = project_params.slice(:name, :description, validate_params = project_params.slice(:name, :description,
:project_category_id, :project_language_id, :private, :identifier) :project_category_id, :project_language_id, :private, :identifier)
Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier)).validate! Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier, project_name: @project.name)).validate!
private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false
@ -144,6 +162,15 @@ class ProjectsController < ApplicationController
} }
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params) gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
@project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]}) @project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
# 更新对应所属分类下的项目数量(私有)
before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public
after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public
before_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][0] : @project.project_category_id
after_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][1] : @project.project_category_id
before_pc = ProjectCategory.find_by_id(before_pc_id)
after_pc = ProjectCategory.find_by_id(after_pc_id)
before_pc.decrement!(:private_projects_count, 1) if before_pc.present? && !before_is_public
after_pc.increment!(:private_projects_count, 1) if after_pc.present? && !after_is_public
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? 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 end
@ -161,6 +188,8 @@ class ProjectsController < ApplicationController
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
@project.destroy! @project.destroy!
@project.forked_projects.update_all(forked_from_project_id: nil) @project.forked_projects.update_all(forked_from_project_id: nil)
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
@project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
render_ok render_ok
end end
else else
@ -171,6 +200,22 @@ class ProjectsController < ApplicationController
tip_exception(e.message) tip_exception(e.message)
end end
def quit
user_is_admin = current_user.admin? || @project.manager?(current_user)
if !user_is_admin && @project.member(current_user.id) && @project.forge?
ActiveRecord::Base.transaction do
Projects::DeleteMemberInteractor.call(@project.owner, @project, current_user)
SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, current_user.id, @project.id) if Site.has_notice_menu?
render_ok
end
else
render_forbidden('你不能退出该仓库')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def watch_users def watch_users
watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct
@watchers_count = watchers.size @watchers_count = watchers.size
@ -184,7 +229,7 @@ class ProjectsController < ApplicationController
end end
def fork_users def fork_users
fork_users = @project.fork_users.includes(:user, :project, :fork_project).order("fork_users.created_at desc").distinct fork_users = @project.fork_users.includes(:owner, :project, :fork_project).order("fork_users.created_at desc").distinct
@forks_count = fork_users.size @forks_count = fork_users.size
@fork_users = paginate(fork_users) @fork_users = paginate(fork_users)
end end

View File

@ -2,7 +2,7 @@ class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show, :files, :commits] before_action :require_login, except: [:index, :show, :files, :commits]
before_action :require_profile_completed, only: [:create] before_action :require_profile_completed, only: [:create]
before_action :load_repository before_action :load_repository
before_action :check_menu_authorize before_action :check_menu_authorize, only: [:index, :show, :create, :update, :refuse_merge, :pr_merge]
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits] 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 :load_pull_request, only: [:files, :commits]
before_action :find_atme_receivers, only: [:create, :update] before_action :find_atme_receivers, only: [:create, :update]
@ -16,7 +16,7 @@ class PullRequestsController < ApplicationController
issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user)) issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user))
@all_issues = issues.distinct @all_issues = issues.distinct
@filter_issues = @all_issues @filter_issues = @all_issues
@filter_issues = @filter_issues.where("subject LIKE ? OR description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present? @filter_issues = @filter_issues.where("issues.subject LIKE ? OR issues.description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
@open_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::OPEN}) @open_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::OPEN})
@close_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::CLOSED}) @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}) @merged_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::MERGED})
@ -29,7 +29,7 @@ class PullRequestsController < ApplicationController
end end
def new def new
@all_branches = Branches::ListService.call(@owner, @project) @all_branches = Branches::ListService.call(@owner, @project, params[:branch_name])
@is_fork = @project.forked_from_project_id.present? @is_fork = @project.forked_from_project_id.present?
@projects_names = [{ @projects_names = [{
project_user_login: @owner.try(:login), project_user_login: @owner.try(:login),
@ -50,16 +50,20 @@ class PullRequestsController < ApplicationController
end end
def get_branches def get_branches
branch_result = Branches::ListService.call(@owner, @project) branch_result = Branches::ListService.call(@owner, @project, params[:name])
render json: branch_result render json: branch_result
# return json: branch_result # return json: branch_result
end end
def create def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"]) @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
reviewers = User.where(id: params[:reviewer_ids])
@pull_request.reviewers = reviewers
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu? 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? 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)}" Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
@ -69,6 +73,8 @@ class PullRequestsController < ApplicationController
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
end end
rescue => e
normal_status(-1, e.message)
end end
def edit def edit
@ -78,6 +84,7 @@ class PullRequestsController < ApplicationController
end end
def update def update
return render_forbidden("你没有权限操作.") unless @project.operator?(current_user)
if params[:title].nil? if params[:title].nil?
normal_status(-1, "名称不能为空") normal_status(-1, "名称不能为空")
elsif params[:issue_tag_ids].nil? elsif params[:issue_tag_ids].nil?
@ -85,15 +92,11 @@ class PullRequestsController < ApplicationController
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
merge_params merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank? reviewers = User.where(id: params[:reviewer_ids])
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists? @pull_request.reviewers = reviewers
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
IssueTagsRelate.create(issue_id: @issue.id, issue_tag_id: tag)
end
end
if @issue.update_attributes(@issue_params) if @issue.update_attributes(@issue_params)
if @pull_request.update_attributes(@local_params.compact) if @pull_request.update_attributes(@local_params.compact)
@ -102,8 +105,15 @@ class PullRequestsController < ApplicationController
if gitea_pull[:status] === :success if gitea_pull[:status] === :success
if params[:issue_tag_ids].present? if params[:issue_tag_ids].present?
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
return normal_status(-1, "最多只能创建一个标记。")
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag| params[:issue_tag_ids].each do |tag|
IssueTagsRelate.create(issue_id: @issue.id, issue_tag_id: tag) IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end
else
return normal_status(-1, "请输入正确的标记。")
end end
end end
if params[:status_id].to_i == 5 if params[:status_id].to_i == 5
@ -136,6 +146,8 @@ class PullRequestsController < ApplicationController
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user) colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
if colsed === true if colsed === true
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE) @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
# 合并请求下issue处理为关闭
@issue&.update_attributes!({status_id:5})
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
normal_status(1, "已拒绝") normal_status(1, "已拒绝")
else else
@ -157,6 +169,7 @@ class PullRequestsController < ApplicationController
@issue_assign_to = @issue.get_assign_user @issue_assign_to = @issue.get_assign_user
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
# @last_review = @pull_request.reviews.take
end end
def pr_merge def pr_merge
@ -180,6 +193,8 @@ class PullRequestsController < ApplicationController
# @pull_request.project_trend_status! # @pull_request.project_trend_status!
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE) @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id) @issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
# 合并请求下issue处理为关闭
@issue&.update_attributes!({status_id:5})
SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
normal_status(1, "合并成功") normal_status(1, "合并成功")
else else
@ -197,7 +212,7 @@ class PullRequestsController < ApplicationController
def check_can_merge def check_can_merge
target_head = params[:head] #源分支 target_head = params[:head] #源分支
target_base = params[:base] #目标分支 target_base = params[:base] #目标分支
is_original = params[:is_original] is_original = params[:is_original] || false
if target_head.blank? || target_base.blank? if target_head.blank? || target_base.blank?
normal_status(-2, "请选择分支") normal_status(-2, "请选择分支")
elsif target_head === target_base && !is_original elsif target_head === target_base && !is_original
@ -228,11 +243,11 @@ class PullRequestsController < ApplicationController
private private
def load_pull_request def load_pull_request
@pull_request = PullRequest.find params[:id] @pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
end end
def find_pull_request def find_pull_request
@pull_request = PullRequest.find_by_id(params[:id]) @pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
@issue = @pull_request&.issue @issue = @pull_request&.issue
if @pull_request.blank? if @pull_request.blank?
normal_status(-1, "合并请求不存在") normal_status(-1, "合并请求不存在")
@ -243,7 +258,7 @@ class PullRequestsController < ApplicationController
def get_relatived def get_relatived
@project_tags = @project.issue_tags&.select(:id,:name, :color).as_json @project_tags = @project.issue_tags&.select(:id,:name, :color).as_json
@project_versions = @project.versions&.select(:id,:name, :status).as_json @project_versions = @project.versions.opening&.select(:id,:name, :status).as_json
@project_members = @project.all_developers @project_members = @project.all_developers
@project_priories = IssuePriority&.select(:id,:name, :position).as_json @project_priories = IssuePriority&.select(:id,:name, :position).as_json
end end
@ -256,12 +271,12 @@ class PullRequestsController < ApplicationController
base: params[:base], #目标分支 base: params[:base], #目标分支
milestone: 0, #里程碑,未与本地的里程碑关联 milestone: 0, #里程碑,未与本地的里程碑关联
} }
assignee_login = User.find_by_id(params[:assigned_to_id])&.login
@requests_params = @local_params.merge({ @requests_params = @local_params.merge({
assignee: current_user.try(:login),
# assignees: ["#{params[:assigned_login].to_s}"], # assignees: ["#{params[:assigned_login].to_s}"],
assignees: ["#{current_user.try(:login).to_s}"], assignees: ["#{assignee_login.to_s}"],
labels: params[:issue_tag_ids], labels: params[:issue_tag_ids]
due_date: Time.now # due_date: Time.now
}) })
@issue_params = { @issue_params = {
author_id: current_user.id, author_id: current_user.id,
@ -271,7 +286,7 @@ class PullRequestsController < ApplicationController
assigned_to_id: params[:assigned_to_id], assigned_to_id: params[:assigned_to_id],
fixed_version_id: params[:fixed_version_id], fixed_version_id: params[:fixed_version_id],
issue_tags_value: params[:issue_tag_ids].present? ? params[:issue_tag_ids].join(",") : "", issue_tags_value: params[:issue_tag_ids].present? ? params[:issue_tag_ids].join(",") : "",
priority_id: params[:priority_id] || "2", priority_id: params[:priority_id],
issue_classify: "pull_request", issue_classify: "pull_request",
issue_type: params[:issue_type] || "1", issue_type: params[:issue_type] || "1",
tracker_id: 2, tracker_id: 2,

View File

@ -9,7 +9,7 @@ class RepositoriesController < ApplicationController
before_action :load_repository before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive] before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] 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_ref, only: %i[entries sub_entries top_counts files archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts] before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts] before_action :get_statistics, only: %i[top_counts]
@ -47,14 +47,19 @@ class RepositoriesController < ApplicationController
end end
def entries def entries
@week_project_visit_record, @month_project_visit_record = TimeableVisitRecord.build(@project.id)
if @week_project_visit_record.visits < 300 && @month_project_visit_record.visits < 1000
@week_project_visit_record.increment!(:visits)
@month_project_visit_record.increment!(:visits)
@project.increment!(:visits) @project.increment!(:visits)
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id) CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
end
if @project.educoder? if @project.educoder?
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name) @entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
else else
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
end end
end end
@ -63,8 +68,7 @@ class RepositoriesController < ApplicationController
end end
def sub_entries def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) file_path_uri = URI.escape(URI.encode(params[:filepath].to_s.strip))
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
if @project.educoder? if @project.educoder?
if params[:type] === 'file' if params[:type] === 'file'
@ -72,18 +76,35 @@ class RepositoriesController < ApplicationController
logger.info "######### sub_entries: #{@sub_entries}" logger.info "######### sub_entries: #{@sub_entries}"
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
tmp_entries = [{ tmp_entries = {
"content" => @sub_entries['data']['content'], "content" => @sub_entries['data']['content'],
"type" => "blob" "type" => "blob"
}] }
@sub_entries = { @sub_entries = {
"trees"=>tmp_entries, "trees"=>tmp_entries,
"commits" => [{}] "commits" => [{}]
} }
else else
begin
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri}) @sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
if @sub_entries.blank? || @sub_entries['status'].to_i === -1
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
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" => [{}]
}
end
rescue
return render_error('该文件暂未开放,敬请期待.')
end
end end
else else
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref) interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success? if interactor.success?
result = interactor.result result = interactor.result
@ -95,13 +116,17 @@ class RepositoriesController < ApplicationController
end end
def commits def commits
if @project.educoder?
@commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name)
else
if params[:filepath].present? if params[:filepath].present?
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) file_path_uri = URI.escape(URI.encode(params[:filepath].to_s.strip))
@hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri, @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 sha: params[:sha], page: params[:page], limit: params[:limit], token: @owner&.gitea_token).call
else else
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier, @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 sha: params[:sha], page: params[:page], limit: params[:limit], token: @owner&.gitea_token).call
end
end end
end end
@ -112,22 +137,40 @@ class RepositoriesController < ApplicationController
def commit def commit
@sha = params[:sha] @sha = params[:sha]
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token) if @project.educoder?
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true}) return render_error('暂未开放,敬请期待.')
else
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, @owner&.gitea_token)
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, @owner&.gitea_token, {diff: true})
render_error(@commit[:message], @commit[:status]) if @commit.has_key?(:status) || @commit_diff.has_key?(:status)
end
end end
def tags def tags
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) if params[:only_name].present?
result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
else
name_result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
@tag_names = result.is_a?(Hash) && result.key?(:status) ? [] : name_result
result = Gitea::Repository::Tags::ListService.call(@owner&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result @tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
end end
end
def contributors def contributors
if params[:filepath].present? if params[:filepath].present? || @project.educoder?
@contributors = [] @contributors = []
else else
@contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier) result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
end end
rescue
@contributors = []
end end
def edit def edit
@ -191,28 +234,34 @@ class RepositoriesController < ApplicationController
def readme def readme
if params[:filepath].present? if params[:filepath].present?
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token) result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], @owner&.gitea_token)
else else
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token) result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], @owner&.gitea_token)
end end
@path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
@readme = result[:status] === :success ? result[:body] : nil @readme = result[:status] === :success ? result[:body] : nil
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref]) @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha") @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
rescue rescue
render json: nil render json: nil
end end
def languages def languages
if @project.educoder?
render json: {}
else
render json: languages_precentagable render json: languages_precentagable
end end
end
def archive def archive
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}" archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
file_path = [domain, api_url, archive_url].join file_path = [domain, api_url, archive_url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? file_path = [file_path, "access_token=#{@owner&.gitea_token}"].join("?")
return render_not_found if !request.format.zip? && !request.format.gzip? return render_not_found if !request.format.zip? && !request.format.gzip?
@ -220,14 +269,14 @@ class RepositoriesController < ApplicationController
end end
def raw def raw
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{params[:filepath]}?ref=#{params[:ref]}" url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{CGI.escape(params[:filepath])}?ref=#{CGI.escape(params[:ref])}"
file_path = [domain, api_url, url].join file_path = [domain, api_url, url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") if @repository.hidden? file_path = [file_path, "access_token=#{@owner&.gitea_token}"].join("&")
redirect_to URI.escape(file_path) redirect_to file_path
end end
private private
@ -251,18 +300,18 @@ class RepositoriesController < ApplicationController
# TODO 获取最新commit信息 # TODO 获取最新commit信息
def project_commits def project_commits
if params[:filepath].present? if params[:filepath].present?
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) file_path_uri = URI.escape(URI.encode(params[:filepath].to_s.strip))
Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri, 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 sha: get_ref, page: 1, limit: 1, token: @project&.owner&.gitea_token).call
else else
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier, Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call sha: get_ref, page: 1, limit: 1, token: @project&.owner&.gitea_token).call
end end
end end
def get_statistics def get_statistics
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size @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 @tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(@project&.owner&.gitea_token, @project.owner.login, @project.identifier).call&.size
end end
def get_ref def get_ref
@ -347,7 +396,7 @@ class RepositoriesController < ApplicationController
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id)) 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 if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call 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"]) 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") local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end end
end end

View File

@ -0,0 +1,20 @@
class ReviewsController < ApplicationController
before_action :require_login
before_action :load_project
before_action :load_pull_request
def create
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
end
private
def review_params
params.require(:review).permit(:content, :commit_id, :status)
end
def load_pull_request
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
end
end

View File

@ -1,13 +1,23 @@
class SettingsController < ApplicationController class SettingsController < ApplicationController
def show def show
@old_projects_url = nil @old_projects_url = nil
get_navbar
get_add_menu get_add_menu
get_common_menu get_common_menu
get_personal_menu get_personal_menu
get_top_system_notification get_top_system_notification
get_banner
end end
private private
def get_navbar
@navbar = default_laboratory.navbar
if User.current.logged?
pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false}
@navbar << pernal_index
end
end
def get_add_menu def get_add_menu
@add = [] @add = []
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site| Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
@ -58,4 +68,14 @@ class SettingsController < ApplicationController
def append_http(url) def append_http(url)
url.to_s.start_with?("http") ? url : [request.protocol, request.host_with_port, url].join('') url.to_s.start_with?("http") ? url : [request.protocol, request.host_with_port, url].join('')
end end
def get_banner
@banner = {
title: EduSetting.get("banner_title") || '大学开源',
sub_title: EduSetting.get("banner_sub_title") || '让大学绽放开源之花',
content: EduSetting.get("banner_content") || "Powered by Trustie and GitLink"
}
@banner
end
end end

View File

@ -0,0 +1,41 @@
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)
tip_exception(-1, "代码未检测,请点击开始检测按钮检测!") if @sonar_task.blank?
if @sonar_task.complete_status == 0
service = Sonar::ApiService.new(@project.id)
service.task_result(@sonar_task.task_id)
end
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? || current_user.business? || educoder_auth_teacher?(current_user)
render_forbidden('你没有权限操作')
end
def educoder_auth_teacher?(user)
user.user_extension&.identity == 'teacher' && user.professional_certification?
end
end

View File

@ -2,24 +2,24 @@ class StatisticController < ApplicationController
# 平台概况 # 平台概况
def platform_profile def platform_profile
@platform_user_query = Statistic::PlatformUserQuery.new(params).call @platform_user_query = Statistic::PlatformUserQuery.new(params).call rescue [0, 0, 0]
@platform_project_query = Statistic::PlatformProjectQuery.new(params).call @platform_project_query = Statistic::PlatformProjectQuery.new(params).call rescue [0, 0, 0]
@platform_course_query = Statistic::PlatformCourseQuery.new(params).call @platform_course_query = Statistic::PlatformCourseQuery.new(params).call rescue [0, 0, 0]
end end
# 平台代码提交数据 # 平台代码提交数据
def platform_code def platform_code
@platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call @platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call rescue [0, 0]
@platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call @platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call rescue [0, 0]
end end
# 项目案例活跃度排行榜 # 项目案例活跃度排行榜
def active_project_rank def active_project_rank
@active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call @active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call rescue []
end end
# 开发者活跃度排行榜 # 开发者活跃度排行榜
def active_developer_rank def active_developer_rank
@active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call @active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call rescue []
end end
end end

View File

@ -0,0 +1,26 @@
class Traces::BaseController < ApplicationController
helper_method :observed_logged_user?, :observed_user
before_action :check_trace_system
def observed_user
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
end
def observed_logged_user?
observed_user.id == User.current&.id
end
protected
def check_auth
return render_forbidden unless current_user.admin? || observed_logged_user?
end
def check_trace_system
code, data, error = Trace::SystemInfoService.call(current_user.trace_token)
return render_ok({code: 501, data: {operate_time: data['operate_time']}, message: '系统维护中'}) if data['status'] === 0
rescue
# 这里根据需求跳转到404
return render_not_found
end
end

View File

@ -1,7 +1,10 @@
class Users::IsPinnedProjectsController < Users::BaseController class Users::IsPinnedProjectsController < Users::BaseController
before_action :private_user_resources!, only: [:pin] before_action :private_user_resources!, only: [:pin]
def index def index
@is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc) @is_pinned_projects = observed_user.pinned_projects.left_joins(:project)
.where("projects.is_public = TRUE")
.order(position: :desc, created_at: :asc)
.includes(project: [:project_category, :project_language, :repository]).order(position: :desc)
@is_pinned_projects = kaminari_paginate(@is_pinned_projects) @is_pinned_projects = kaminari_paginate(@is_pinned_projects)
end end

View File

@ -12,7 +12,7 @@ class Users::StatisticsController < Users::BaseController
@commit_data = [] @commit_data = []
date_range.each do |date| date_range.each do |date|
@date_data << date.strftime("%Y.%m.%d") @date_data << date.strftime("%Y.%m.%d")
@issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size @issue_data << observed_user.issues.issue_issue.where("DATE(created_on) = ?", date).size
@pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", 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.blank? ? nil : 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) @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i)

View File

@ -23,6 +23,8 @@ class Users::TemplateMessageSettingsController < Users::BaseController
def get_current_setting def get_current_setting
@current_setting = @_observed_user.user_template_message_setting @current_setting = @_observed_user.user_template_message_setting
@current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil? @current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil?
@current_setting.notification_body.merge!(UserTemplateMessageSetting.init_notification_body.except(*@current_setting.notification_body.keys))
@current_setting.email_body.merge!(UserTemplateMessageSetting.init_email_body.except(*@current_setting.email_body.keys))
end end
def setting_params def setting_params

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 :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 :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 :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update] before_action :convert_image!, only: [:update]
skip_before_action :check_sign, only: [:attachment_show] skip_before_action :check_sign, only: [:attachment_show]
@ -51,8 +51,6 @@ class UsersController < ApplicationController
@projects_common_count = user_projects.common.size @projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size @projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size @projects_sync_mirrior_count = user_projects.sync_mirror.size
# 为了缓存活跃用户的基本信息,后续删除
Cache::V2::OwnerCommonService.new(@user.id).read
end end
def watch_users def watch_users
@ -85,6 +83,24 @@ class UsersController < ApplicationController
end end
end end
def update_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
Util.write_file(@image, avatar_path(@user))
return render_ok({message: '头像修改成功'})
rescue Exception => e
uid_logger_error(e.message)
render_error(-1, '头像修改失败!')
end
def get_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
redirect_to Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(@user).to_s
end
def me def me
@user = current_user @user = current_user
end end
@ -193,7 +209,7 @@ class UsersController < ApplicationController
def trustie_related_projects def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = [] projects_json = []
domain_url = EduSetting.get('host_name') domain_url = EduSetting.get('host_name') + '/projects'
if projects.present? if projects.present?
projects.each do |p| projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}" project_url = "/#{p.owner.login}/#{p.identifier}"
@ -262,25 +278,69 @@ class UsersController < ApplicationController
render_ok render_ok
end end
def sync_user_info # TODO: For Educoder
def change_password
user = User.find_by_login params[:login] user = User.find_by_login params[:login]
return render_forbidden unless user === current_user return render_error("用户 #{params[:login]} 不存在.") if user.nil?
form_params= {
login: params[:login],
email: user&.mail,
password: params[:password],
user: user
}
Gitea::User::ChangePasswordForm.new(form_params).validate!
sync_params = { sync_params = {
email: params[:email], password: params[:password].to_s,
password: params[:password] email: user.mail,
login_name: user.login,
source_id: 0
} }
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate! if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success? if interactor.success?
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO) user.update!(password: params[:password], is_sync_pwd: true)
render_ok render_ok
else else
render_error(interactor.error) render_error(interactor.error)
end end
end end
end
# TODO: For Educoder
def change_email
user = User.find_by_login params[:login]
return render_error("用户 #{rq_params[:login]} 不存在.") if user.nil?
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
def email_search
return render_error('请输入email') if params[:email].blank?
@user = User.find_by(mail: params[:email])
end
private private
def load_user def load_user
@ -294,6 +354,7 @@ class UsersController < ApplicationController
:occupation, :technical_title, :occupation, :technical_title,
:school_id, :department_id, :province, :city, :school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description, :custom_department, :identity, :student_id, :description,
:show_super_description, :super_description,
:show_email, :show_location, :show_department] :show_email, :show_location, :show_department]
) )
end end

View File

@ -14,7 +14,7 @@ class VersionReleasesController < ApplicationController
def new def new
#获取所有的分支 #获取所有的分支
@all_branches = [] @all_branches = []
get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier)).call get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier), params[:branch_name]).call
if get_all_branches && get_all_branches.size > 0 if get_all_branches && get_all_branches.size > 0
get_all_branches.each do |b| get_all_branches.each do |b|
@all_branches.push(b["name"]) @all_branches.push(b["name"])

View File

@ -1,13 +1,13 @@
--- ---
title: Trustie API Reference title: GitLink API Reference
language_tabs: # must be one of https://git.io/vQNgJ language_tabs: # must be one of https://git.io/vQNgJ
- shell: Shell - shell: Shell
- javascript: JavaScript - javascript: JavaScript
toc_footers: toc_footers:
- <a href='https://www.trustie.net/login?login=false'>Sign Up for a User</a> - <a href='https://www.gitlink.org.cn/login'>Sign In for a User</a>
- <a href='https://www.trustie.net'>Powered by Trustie</a> - <a href='https://www.gitlink.org.cn'>Powered by GitLink</a>
includes: includes:
- licenses - licenses
@ -30,8 +30,8 @@ code_clipboard: true
# Introduction # Introduction
Welcome to the Trustie API! You can use our API to access Trustie API endpoints, which can get information on projects, repository, and users in our platform. Welcome to the GitLink API! You can use our API to access GitLink API endpoints, which can get information on projects, repository, and users in our platform.
We have language bindings in Shell,avaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right. We have language bindings in Shell,avaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
This example API documentation page was created with [Trustie](https://www.trustie.net). Feel free to edit it and use it as a base for your own API's documentation. This example API documentation page was created with [GitLink](https://www.gitlink.org.cn). Feel free to edit it and use it as a base for your own API's documentation.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,4 +1,278 @@
# Projects # Projects
## 获取项目邀请链接(项目管理员)
当前登录管理员用户获取项目邀请链接的接口第一次请求会默认生成role类型为developer和is_apply为true的链接
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/current_link.json
```
```javascript
await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json')
```
### HTTP 请求
`GET /api/:owner/:repo/project_invite_links/current_link.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限reporter: 报告者, developer: 开发者manager管理员 |
|is_apply |是| |boolean |是否需要审核 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 生成项目邀请链接(项目管理员)
当前登录管理员用户生成的项目邀请链接可选role和is_apply参数
> 示例:
```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/generate_link.json
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/generate_link.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限reporter: 报告者, developer: 开发者manager管理员 |
|is_apply |是| |boolean |是否需要审核 |
> 请求的JSON示例
```json
{
"role": "developer",
"is_apply": false
}
```
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 获取邀请链接信息(被邀请用户)
用户请求邀请链接时,通过该接口来获取链接的信息
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/show_link.json?invite_sign=xxx`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 接受项目邀请链接(被邀请用户)
当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核
> 示例:
```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/redirect_link.json?invite_sign=xxx`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
## 申请加入项目 ## 申请加入项目
申请加入项目 申请加入项目
@ -280,7 +554,7 @@ repo |是| |string |项目标识identifier
### 返回字段说明 ### 返回字段说明
参数 | 类型 | 字段说明 参数 | 类型 | 字段说明
--------- | ----------- | ----------- --------- | ----------- | -----------
menu_name |string|导航名称, home:主页,code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置 menu_name |string|导航名称, home:主页,code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置
> 返回的JSON示例: > 返回的JSON示例:
@ -408,7 +682,7 @@ await octokit.request('POST /api/yystopf/ceshi/project_units')
### 请求参数 ### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ---------- --------- | ------- | ------- | -------- | ----------
|unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑 | |unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑 |
### 返回字段说明: ### 返回字段说明:
@ -850,3 +1124,35 @@ await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.j
"time_ago": "1分钟前" "time_ago": "1分钟前"
} }
``` ```
## 退出项目
供项目成员(开发者、报告者)退出项目用
> 示例:
```shell
curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/quit.json
```
```javascript
await octokit.request('POST /api/:owner/:repo/quit.json')
```
### HTTP 请求
`POST /api/:owner/:repo/quit.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```

File diff suppressed because it is too large Load Diff

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