Compare commits

...

326 Commits

Author SHA1 Message Date
yystopf d4d00b30bf Merge branch 'standalone_develop' into pre_trustie_server 2022-05-25 11:47:55 +08:00
yystopf 19ec81e975 Merge branch 'develop' into standalone_develop 2022-05-25 11:47:44 +08:00
yystopf 2ea78b4f20 增加: 已登录用户对用户名、邮箱、电话进行校验 2022-05-25 11:47:35 +08:00
yystopf 4c066b30ef Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 18:10:28 +08:00
yystopf ad9bb8e542 修复: 合并从develop 2022-05-24 18:10:20 +08:00
yystopf e36c7a4b6a 修复: 邮箱搜索不需要return 404 2022-05-24 18:09:36 +08:00
yystopf 18c4c6ae2f Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 17:38:21 +08:00
yystopf 9979c87d0c 修复: 合并从develop 2022-05-24 17:27:24 +08:00
yystopf 8e8ec821f2 新增: 根据邮箱来获取用户 2022-05-24 17:26:10 +08:00
xiaoxiaoqiong 774b1bc79e Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 15:24:43 +08:00
xiaoxiaoqiong 94166a363c fixed 增加自动登录,gitea注册 2022-05-24 15:24:15 +08:00
xiaoxiaoqiong 0219a1fdde Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 14:34:29 +08:00
xiaoxiaoqiong ebe5fad7dd fixed 增加自动登录,gitea注册 2022-05-24 14:33:23 +08:00
xiaoxiaoqiong b2e7491ade Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 14:15:21 +08:00
xiaoxiaoqiong 85a36ca2e7 fixed 增加自动登录,gitea注册 2022-05-24 14:14:57 +08:00
xiaoxiaoqiong b0f80012ab Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 14:08:58 +08:00
xiaoxiaoqiong 75cef14605 fixed 增加自动登录,gitea注册 2022-05-24 14:08:33 +08:00
xiaoxiaoqiong 0fc96026c8 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 14:01:01 +08:00
xiaoxiaoqiong 93f8b659a1 fixed 增加自动登录,gitea注册 2022-05-24 14:00:15 +08:00
xiaoxiaoqiong b45ee11239 fixed 增加自动登录,gitea注册 2022-05-24 13:46:58 +08:00
xiaoxiaoqiong 553d3a019f Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 11:50:30 +08:00
xiaoxiaoqiong 33fa55bcb6 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-05-24 11:49:01 +08:00
xiaoxiaoqiong 643a99fdf1 fixed 增加自动登录,gitea注册 2022-05-24 11:48:56 +08:00
yystopf 38c5432c2a Merge branch 'develop' into standalone_develop 2022-05-24 11:46:26 +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 e8bfd0c955 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 11:10:13 +08:00
yystopf 183eb15c7d Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-05-24 11:03:59 +08:00
yystopf fb43268444 fix: merge from develop 2022-05-24 11:03:54 +08:00
yystopf c27cc063e6 add: new update user info simple and sync gitea 2022-05-24 10:59:52 +08:00
xiaoxiaoqiong 6f6fe61a9d Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 10:47:37 +08:00
xiaoxiaoqiong b673909f9e fixed 增加自动登录,手机号先记录,后续用 2022-05-24 10:47:17 +08:00
xiaoxiaoqiong bd4dbd577b Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 10:34:54 +08:00
xiaoxiaoqiong ee3a14fa28 fixed 增加自动登录 2022-05-24 10:34:31 +08:00
xiaoxiaoqiong 26bfc2c0bf fixed 增加自动登录 2022-05-24 10:33:21 +08:00
xiaoxiaoqiong eb2d976876 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-24 10:29:00 +08:00
xiaoxiaoqiong 56721930a2 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-05-24 10:26:06 +08:00
xiaoxiaoqiong 2959414d56 fixed 增加自动登录 2022-05-24 10:25:58 +08:00
yystopf 008fdbaf5a Merge branch 'standalone_develop' into pre_trustie_server 2022-05-23 18:24:06 +08:00
yystopf 6223cf41e2 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-05-23 18:10:54 +08:00
yystopf 1d3f79e777 Merge branch 'develop' into standalone_develop 2022-05-23 18:10:47 +08:00
yystopf b0092487e6 fix: is readme use regex 2022-05-23 18:10:41 +08:00
xiaoxiaoqiong 0ae3544235 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop
# Conflicts:
#	app/controllers/users_controller.rb
#	app/helpers/application_helper.rb
2022-05-23 18:06:24 +08:00
xiaoxiaoqiong 05b3f2a2fb fixed timego时间差 2022-05-23 18:05:13 +08:00
yystopf 97fe157279 Merge branch 'develop' into standalone_develop 2022-05-23 09:27:16 +08:00
yystopf fbebd0a623 fix 2022-05-23 09:27:09 +08:00
yystopf 25487368e5 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-21 17:06:41 +08:00
yystopf 02681abaee Merge branch 'develop' into standalone_develop 2022-05-21 16:46:14 +08:00
yystopf fe23c2afbf fix: replace content next if blank 2022-05-21 16:45:42 +08:00
yystopf dc0d31330a Merge branch 'standalone_develop' into pre_trustie_server 2022-05-20 17:28:25 +08:00
yystopf b06ad71082 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-05-20 17:06:10 +08:00
yystopf 3212bc4842 fix: merge from develop 2022-05-20 17:06:00 +08:00
yystopf 779c86108a fix: readme relative delay and replace_content 2022-05-20 17:00:02 +08:00
yystopf e4779926bd Merge pull request '代码溯源部分代码' (#9) from yystopf/forgeplus:standalone_develop into standalone_develop 2022-05-20 14:46:33 +08:00
yystopf 803fdfc49e fix: merge from develop 2022-05-20 11:44:56 +08:00
yystopf 83e43f0c97 add: new readme delay function 2022-05-20 11:43:22 +08:00
yystopf ccec3494bc merge from develop 2022-05-18 11:38:07 +08:00
yystopf e237fd46f7 fix: not found user return 404 2022-05-18 11:37:23 +08:00
yystopf 6dc2f0b062 Merge branch 'develop' into standalone_develop 2022-05-18 11:03:47 +08:00
yystopf ca3c564529 fix: not found user return 404 2022-05-18 11:03:39 +08:00
yystopf f79e4f8e81 Merge branch 'develop' into standalone_develop 2022-05-18 10:11:22 +08:00
yystopf 9cd18397f7 fix: import user login length required 2022-05-18 10:11:09 +08:00
yystopf bfd3298cd0 fix 2022-05-17 11:42:43 +08:00
yystopf 077926de18 fix 2022-05-17 11:39:57 +08:00
yystopf 4fade5d0b7 fix: project trace tasks name rule change 2022-05-17 11:34:08 +08:00
yystopf f51ebaad67 fix 2022-05-16 17:08:52 +08:00
yystopf 8ae6a0deb2 fix: some feature about permission 2022-05-16 17:02:38 +08:00
yystopf d9b3711e08 Merge branch 'develop' into standalone_develop 2022-05-16 16:59:36 +08:00
yystopf 77620f7735 add: download and import user template xlsx 2022-05-16 16:59:25 +08:00
yystopf acbd0d376c fix: change trace user post valid 2022-05-16 14:26:21 +08:00
yystopf 2f4ffe3d8e fix: change trace user post valid 2022-05-16 14:25:54 +08:00
yystopf a6efae8b10 fix 2022-05-16 10:48:23 +08:00
yystopf 5a728e7d4d fix: trace user exist and compact tasks create params 2022-05-16 09:58:47 +08:00
yystopf 04a733d99f fix: check user trace tasks count 2022-05-13 16:57:41 +08:00
yystopf 9e8c576ff6 fix: remove require manager operate 2022-05-13 15:38:04 +08:00
yystopf 94881dd72a add: user trace tasks record 2022-05-13 14:31:59 +08:00
yystopf 2c7bb1b5cd fix: remove project tasks_count 2022-05-13 14:00:21 +08:00
yystopf 0e4c0a46c2 fix 2022-05-13 13:56:12 +08:00
yystopf 7fcbbb7922 fix: remove project tasks_count 2022-05-13 13:53:25 +08:00
yystopf 3d9fe5bba5 add: download pdf from trace server 2022-05-12 17:52:19 +08:00
yystopf 4dccdfde97 fix 2022-05-12 17:15:19 +08:00
yystopf 00fc83235f download file use redirect 2022-05-12 17:11:16 +08:00
yystopf 498ee26f59 fix 2022-05-12 11:14:17 +08:00
yystopf 5d771c824b add: operate permission and request timeout 2022-05-12 11:12:34 +08:00
yystopf 3eccd6be64 add: user has trace user field 2022-05-12 09:45:37 +08:00
yystopf 9b3336c0a0 fix: reload task need increment tasks count 2022-05-12 09:43:55 +08:00
yystopf 12c961d70d fix 2022-05-12 09:43:55 +08:00
yystopf 7750cbe272 add: project trace tasks count 2022-05-12 09:43:55 +08:00
yystopf 1f13bba52e add: trace user tasks_count 2022-05-12 09:43:55 +08:00
yystopf 5dcee1b4dc add: traces api document 2022-05-12 09:43:55 +08:00
yystopf cf09b28f5e add: project menu services 2022-05-12 09:43:54 +08:00
yystopf f31796f344 add: branch valid for tasks 2022-05-12 09:43:52 +08:00
yystopf 2d9bde134a fix 2022-05-12 09:43:00 +08:00
yystopf 59db914bcc change route position 2022-05-12 09:42:59 +08:00
yystopf a0a7f908f4 rename namespace 2022-05-12 09:42:59 +08:00
yystopf 17ccf3d576 rename namespace 2022-05-12 09:42:59 +08:00
yystopf 72a32ed8c4 rename namespace 2022-05-12 09:42:59 +08:00
yystopf c64fa5135b fix 2022-05-12 09:42:59 +08:00
yystopf 12cc37443e add: trace controller and router 2022-05-12 09:42:59 +08:00
yystopf 5edea8960d Merge branch 'standalone_develop' into pre_trustie_server 2022-05-07 14:07:41 +08:00
yystopf f5efbcfc04 Merge branch 'develop' into standalone_develop 2022-05-07 14:06:58 +08:00
yystopf 50dc5cce5d fix 2022-05-07 14:06:48 +08:00
yystopf 0d377943d5 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-07 11:58:24 +08:00
yystopf 0afac46778 Merge branch 'develop' into standalone_develop 2022-05-07 11:58:13 +08:00
yystopf a6cee63d17 fix: change owner must fix foreign_key 2022-05-07 11:57:58 +08:00
yystopf 77797fb1f7 Merge branch 'standalone_develop' into pre_trustie_server 2022-05-07 10:04:29 +08:00
yystopf 20af4a7d82 Merge branch 'develop' into standalone_develop 2022-05-06 17:25:52 +08:00
yystopf 000197b0d1 fix: issues and pull_request length calculate 2022-05-06 17:25:34 +08:00
yystopf 67b386d947 Merge branch 'develop' into standalone_develop 2022-05-06 14:29:15 +08:00
yystopf 6aa3321d17 fix: pr title description validate 2022-05-06 14:29:05 +08:00
yystopf 82df2fd6d8 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-05-06 09:57:40 +08:00
yystopf 9d8df2b4d9 Merge branch 'develop' into standalone_develop 2022-05-06 09:57:23 +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 071542bcb4 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-05-05 10:42:23 +08:00
xiaoxiaoqiong 676024b6db fork_users加入组织 2022-05-05 10:42:08 +08:00
xiaoxiaoqiong 55c74de8e4 fork_users加入组织 2022-05-05 10:41:02 +08:00
yystopf 52c94effdc Merge branch 'develop' into standalone_develop 2022-05-05 10:18:19 +08:00
yystopf 7c88ea3d67 add: quit repo 2022-05-05 10:00:02 +08:00
yystopf d799d329ff add: compare add paginate 2022-04-28 18:54:56 +08:00
yystopf f15cd44dff add: compare add paginate 2022-04-28 18:53:33 +08:00
yystopf 91ea5ca96a Merge branch 'develop' into standalone_develop 2022-04-28 11:12:35 +08:00
yystopf 3abd6037d9 fix: show super description aways desplay 2022-04-28 11:12:16 +08:00
yystopf 11724bf63f Merge branch 'develop' into standalone_develop 2022-04-28 11:04:01 +08:00
yystopf ec3a556a6f fix: default value for show super description 2022-04-28 11:03:42 +08:00
yystopf 1d7c7eba24 Merge branch 'develop' into standalone_develop 2022-04-28 10:54:02 +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 e1b4622ede Merge branch 'develop' into standalone_develop 2022-04-26 17:17:05 +08:00
yystopf 088c617cc1 add: name query for branches 2022-04-26 17:15:59 +08:00
yystopf 121e04f751 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-21 16:59:55 +08:00
yystopf 246b484ad8 fix merge from develop 2022-04-18 14:14:48 +08:00
yystopf fc3cf01d3f add: get user image action 2022-04-18 13:49:08 +08:00
yystopf 345fd31834 Merge branch 'develop' into standalone_develop 2022-04-18 10:52:59 +08:00
yystopf 8f5bb0e2d9 fix: organization gitea_token read by associations 2022-04-18 10:52:48 +08:00
yystopf 7aea481ccf add: glcc_apply_infomations admin navbar 2022-04-18 10:24:54 +08:00
yystopf 37317f82bf Merge branch 'develop' into standalone_develop 2022-04-11 16:09:08 +08:00
yystopf 2dfd69ae21 fix: response data result 2022-04-11 16:08:50 +08:00
yystopf a132154136 Merge branch 'develop' into standalone_develop 2022-04-11 15:48:54 +08:00
yystopf 720c073f32 fix 2022-04-11 15:48:47 +08:00
yystopf 185cb308ac Merge branch 'develop' into standalone_develop 2022-04-11 15:30:44 +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
xiaoxiaoqiong 6e86f9d9f3 竞赛配置子赛项 2022-04-08 23:07:23 +08:00
xiaoxiaoqiong e97e7aa550 竞赛配置子赛项 2022-04-08 21:59:35 +08:00
xiaoxiaoqiong ffb3b26d3c Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 18:51:16 +08:00
xiaoxiaoqiong 6d280ed8f2 竞赛配置子赛项 2022-04-08 18:51:01 +08:00
xiaoxiaoqiong 47b3816e4f Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 18:46:46 +08:00
xiaoxiaoqiong 3f85f88c92 竞赛配置子赛项 2022-04-08 18:46:14 +08:00
xiaoxiaoqiong 1477811782 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 18:41:17 +08:00
xiaoxiaoqiong f60cd409b6 竞赛配置子赛项 2022-04-08 18:40:52 +08:00
xiaoxiaoqiong 04b2a9b358 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 17:45:38 +08:00
xiaoxiaoqiong 9d46f2743d 竞赛配置子赛项 2022-04-08 17:45:15 +08:00
xiaoxiaoqiong 000a4f8019 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 17:39:47 +08:00
xiaoxiaoqiong aaf2b43986 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-04-08 17:38:59 +08:00
xiaoxiaoqiong 75a9a65b9b 竞赛配置子赛项 2022-04-08 17:38:26 +08:00
yystopf 49afc0e20a Merge branch 'develop' into pre_trustie_server 2022-04-08 16:39:19 +08:00
yystopf 17f2436118 Merge branch 'develop' into standalone_develop 2022-04-08 15:03:52 +08:00
yystopf eac7331070 fix: settings need prefix 2022-04-08 15:03:40 +08:00
yystopf 2243697184 Merge branch 'develop' into standalone_develop 2022-04-08 14:53:06 +08:00
yystopf 551f333261 fix 2022-04-08 14:52:56 +08:00
yystopf 18cf1d3ecb Merge branch 'glcc_news_develop' into standalone_develop 2022-04-08 13:23:49 +08:00
yystopf 7c1160b247 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-08 11:59:51 +08:00
yystopf 4cefaa7e92 Merge branch 'develop' into standalone_develop 2022-04-08 11:59:25 +08:00
yystopf dec264d169 fix: sync user pwd 2022-04-07 16:28:40 +08:00
yystopf 8aa935ad5c add: glcc news management and api data 2022-04-07 16:13:32 +08:00
xiaoxiaoqiong f082819496 Merge branch 'standalone_develop' into pre_trustie_server 2022-04-06 20:32:31 +08:00
xiaoxiaoqiong 4bdff8313a Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-04-06 20:32:06 +08:00
xiaoxiaoqiong c4f91fb054 搜索用户增加email和单位 2022-04-06 20:32:02 +08:00
yystopf a33be8850e Merge branch 'standalone_develop' into pre_trustie_server 2022-04-06 17:05:05 +08:00
yystopf fde01e62ef Merge branch 'develop' into standalone_develop 2022-04-06 17:04:52 +08:00
yystopf 7055974443 fix 2022-04-06 17:04:31 +08:00
xiaoxiaoqiong e0022647ed Merge branch 'standalone_develop' into pre_trustie_server 2022-04-06 14:35:11 +08:00
xiaoxiaoqiong 1f6ac05bad 允许非登录搜索用户 2022-04-06 14:33:47 +08:00
yystopf 70dd2768e5 Merge branch 'standalone_develop' into pre_trustie_server 2022-03-31 18:30:00 +08:00
yystopf c5dd099169 Merge branch 'develop' into standalone_develop 2022-03-31 16:18:25 +08:00
yystopf 3536918938 fix 2022-03-31 16:18:16 +08:00
yystopf d56da6d020 Merge branch 'develop' into standalone_develop 2022-03-31 16:08:43 +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 234f5b900c Merge branch 'develop' into standalone_develop 2022-03-31 14:25:02 +08:00
yystopf db4031b8bf fix 2022-03-31 14:24:47 +08:00
yystopf dd3236e310 Merge branch 'develop' into standalone_develop 2022-03-31 13:18:46 +08:00
yystopf ecfc39565c fix 2022-03-31 13:18:38 +08:00
yystopf 7fd41e13e4 Merge branch 'develop' into standalone_develop 2022-03-31 13:04:02 +08:00
yystopf 9ced678f91 fix: user trace token 2022-03-31 13:03:54 +08:00
yystopf b25db9d37f fix: merge from develop 2022-03-31 13:00:36 +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 a5be4a9502 fix: readme image regex error rescued 2022-03-28 11:25:13 +08:00
yystopf d0d906d04c fix: readme image regex error rescued 2022-03-28 11:05:21 +08:00
xiaoxiaoqiong 4c69c4d20f Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2022-03-24 10:25:31 +08:00
xiaoxiaoqiong 183315bbd9 万能验证码,用于测试 2022-03-24 10:25:24 +08:00
yystopf 4dc3546124 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-03-22 10:45:55 +08:00
yystopf d796d59557 Merge branch 'develop' into standalone_develop 2022-03-22 10:45:45 +08:00
yystopf bc639488aa fix: issues filter error 2022-03-22 10:45:14 +08:00
xiaoxiaoqiong 930805704a fixed: 文件目录加载性能优化 2022-03-18 17:32:29 +08:00
xiaoxiaoqiong 9912ad0779 fixed: 1.readme加载不正常 2022-03-18 17:09:06 +08:00
xiaoxiaoqiong d9ae4e4ba0 fixed: 1.readme加载不正常, 2.文件目录加载性能优化 2022-03-18 16:52:23 +08:00
xiaoxiaoqiong 23dc2d7fb6 目录树加载图片不需要Content 2022-03-18 14:55:42 +08:00
xiaoxiaoqiong fe5c18c019 readme.md支持图片相对路径 2022-03-18 14:24:03 +08:00
xiaoxiaoqiong fa6f015128 readme.md支持图片相对路径 2022-03-18 14:21:12 +08:00
xiaoxiaoqiong 7f1b95c7d7 readme.md支持图片相对路径 2022-03-18 14:03:59 +08:00
xiaoxiaoqiong 2346b0f848 readme.md支持图片相对路径 2022-03-18 11:41:26 +08:00
xiaoxiaoqiong ea070d4e23 gitea 请求延长到20分钟 2022-03-11 14:10:43 +08:00
xiaoxiaoqiong c0e97409cb gitea 请求延长到20分钟 2022-03-11 14:07:39 +08:00
xiaoxiaoqiong 99fbecc834 gitea 请求延长到20分钟 2022-03-11 14:06:12 +08:00
yystopf 4cc8dd70f4 Merge branch 'develop' into standalone_develop 2022-03-10 10:47:20 +08:00
yystopf 8d0a6d267a fix: download escape 2022-03-10 10:47:06 +08:00
yystopf 0db1820557 Merge branch 'develop' into standalone_develop 2022-03-10 09:52:12 +08:00
yystopf b1c03ed5e8 fix: activity issues must only issue 2022-03-10 09:51:46 +08:00
yystopf 1c660213a7 fix: claims is losed 2022-03-10 09:36:51 +08:00
yystopf 748f6cdd4d Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2022-03-07 11:20:58 +08:00
yystopf 1fe8d1defc Merge branch 'develop' into standalone_develop 2022-03-07 11:20:23 +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 386c90592e Merge branch 'standalone_develop' into pre_trustie_server 2022-03-03 15:07:24 +08:00
xiaoxiaoqiong 664b806c0a routes合并 2022-03-03 15:06:56 +08:00
xiaoxiaoqiong b530de4ddc Merge branch 'standalone_develop' into pre_trustie_server 2022-03-03 14:21:22 +08:00
xiaoxiaoqiong 1dd3fbc69a fixed fork列表中存在组织时显示错误 2022-03-03 14:16:57 +08:00
xiaoxiaoqiong 94d259ea03 fixed fork列表中存在组织时显示错误 2022-03-03 14:16:05 +08:00
yystopf 3091593d14 add: standalone admin menu 2022-03-02 10:48:21 +08:00
yystopf c5d2fad913 Merge branch 'develop' into standalone_develop 2022-03-02 10:34:16 +08:00
yystopf b97c42d0ae fix: email logo 2022-03-02 10:33:35 +08:00
yystopf c76466a883 Merge branch 'pre_trustie_server' into trustie_server 2022-02-24 18:10:06 +08:00
yystopf 217e0fdd97 Merge branch 'standalone_develop' into pre_trustie_server 2022-02-24 18:09:53 +08:00
yystopf f0b8489828 Merge branch 'develop' into standalone_develop 2022-02-24 18:09:20 +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 70ade7b27b Merge branch 'pre_trustie_server' into trustie_server 2022-02-24 16:45:12 +08:00
yystopf 57c60b2fe9 Merge branch 'standalone_develop' into pre_trustie_server 2022-02-24 16:44:58 +08:00
yystopf aa643430fa Merge branch 'develop' into standalone_develop 2022-02-24 14:27:31 +08:00
yystopf 1a93477635 fix: forked templete delay 2022-02-24 14:26:04 +08:00
yystopf 8f9aedd7d6 Merge branch 'pre_trustie_server' into trustie_server 2022-02-24 11:47:38 +08:00
yystopf ab989ed7d7 Merge branch 'standalone_develop' into pre_trustie_server 2022-02-24 11:46:44 +08:00
xiaoxiaoqiong 28d07d5c54 fixed 合并冲突 2022-02-22 17:49:14 +08:00
yystopf 53d094784b Merge branch 'develop' into standalone_develop 2022-02-22 11:03:47 +08:00
yystopf 7c664addbd fix 2022-02-22 11:03:28 +08:00
yystopf 6167834bfa Merge branch 'pre_trustie_server' into trustie_server 2022-02-22 10:40:11 +08:00
yystopf 1bb754e9d8 Merge branch 'standalone_develop' into pre_trustie_server 2022-02-22 10:39:47 +08:00
yystopf f2f2ce8252 merge from develop 2022-02-22 10:38:42 +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 1100309038 Merge branch 'develop' into standalone_develop 2022-02-17 11:12:58 +08:00
yystopf b11f5fd228 fix: cache rollback 2022-02-17 11:12:50 +08:00
yystopf af5f2b2fe3 Merge branch 'develop' into standalone_develop 2022-02-17 10:59:29 +08:00
yystopf 90dbe0730a fix: job not affect 2022-02-17 10:59:18 +08:00
yystopf f39e8b7668 Merge branch 'develop' into standalone_develop 2022-02-17 09:43:52 +08:00
yystopf d6633cb73a fix 2022-02-17 09:43:44 +08:00
yystopf 86ef890f8b Merge branch 'develop' into standalone_develop 2022-02-17 09:40:54 +08:00
yystopf a7a6abd22a fix: add rule for issue expire 2022-02-17 09:40:44 +08:00
yystopf 6fd47b56a5 Merge branch 'develop' into standalone_develop 2022-02-17 09:37:00 +08:00
yystopf c956667ce0 fix 2022-02-17 09:36:49 +08:00
yystopf 898453c88c Merge branch 'develop' into standalone_develop 2022-02-16 15:10:19 +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 0bd274f813 Merge branch 'develop' into standalone_develop 2022-02-16 11:17:15 +08:00
yystopf 4aac05d4e1 fix: build user template message data must fronted 2022-02-16 11:17:03 +08:00
yystopf b028a70646 Merge branch 'pre_trustie_server' into trustie_server 2022-02-16 09:35:56 +08:00
yystopf 3c7da85bee Merge branch 'standalone_develop' into pre_trustie_server 2022-02-16 09:35:42 +08:00
yystopf 9751c954df Merge branch 'develop' into standalone_develop 2022-02-16 09:35:22 +08:00
yystopf 84b56bfcb8 fix: project milestone create notice template 2022-02-16 09:34:31 +08:00
yystopf ac07c88f84 Merge branch 'develop' into standalone_develop 2022-02-15 18:30:25 +08:00
yystopf 7485564bb9 add: template message platform varible 2022-02-15 18:30:13 +08:00
yystopf 5e696ae905 Merge branch 'develop' into standalone_develop 2022-02-15 17:33:55 +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 d262da7c65 通过配置确定github克隆方式 2022-02-14 16:56:12 +08:00
xiaoxiaoqiong 2050559077 通过配置确定github克隆方式 2022-02-14 16:54:24 +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 52bde548fa Merge branch 'pre_trustie_server' into trustie_server 2022-02-11 16:28:07 +08:00
yystopf ea11672fff Merge branch 'standalone_develop' into pre_trustie_server 2022-02-11 16:27:56 +08:00
yystopf 09c4f8db0e Merge branch 'develop' into standalone_develop 2022-02-11 16:27:42 +08:00
yystopf 29dc3fff39 fix: migrate use old rule 2022-02-11 16:27:22 +08:00
yystopf da863c3963 Merge branch 'pre_trustie_server' into trustie_server 2022-02-10 14:11:25 +08:00
yystopf 8d18149537 Merge branch 'standalone_develop' into pre_trustie_server 2022-02-10 14:11:06 +08:00
yystopf 8050af23fc Merge branch 'develop' into standalone_develop 2022-02-10 14:10:54 +08:00
yystopf 298abdd1b1 fix: devops organization bug 2022-02-10 14:08:14 +08:00
yystopf eb0ced39f5 Merge branch 'pre_trustie_server' into trustie_server 2022-01-26 13:47:26 +08:00
yystopf 2738d950d4 Merge branch 'standalone_develop' into pre_trustie_server 2022-01-26 13:47:14 +08:00
yystopf 3ce9b2d145 Merge branch 'develop' into standalone_develop 2022-01-25 14:26:20 +08:00
yystopf 26f87fba16 fix: edit transfer need change fork info 2022-01-25 14:26:11 +08:00
yystopf 465f38bca7 Merge branch 'develop' into standalone_develop 2022-01-25 11:39:15 +08:00
yystopf 1e9a32a93e fix: issues select count paginator 2022-01-25 11:39:06 +08:00
yystopf 04bc6d363f Merge branch 'develop' into standalone_develop 2022-01-25 10:34:33 +08:00
yystopf 2dc79052c2 fix: create project trend when status is closed 2022-01-25 10:34:20 +08:00
yystopf f6ff8ac209 Merge branch 'pre_trustie_server' into trustie_server 2022-01-24 17:27:30 +08:00
yystopf b9e2a6edf1 Merge branch 'standalone_develop' into pre_trustie_server 2022-01-24 17:27:21 +08:00
yystopf e0f5337fdd Merge branch 'develop' into standalone_develop 2022-01-24 14:26:36 +08:00
yystopf 380ca3a066 fix: projects query rule 2022-01-24 14:26:24 +08:00
yystopf 7d19849968 Merge branch 'develop' into standalone_develop 2022-01-24 10:44:59 +08:00
yystopf 237b0afb08 fix: team user build use find or create by 2022-01-24 10:44:46 +08:00
yystopf 67914201bf merge from develop 2022-01-24 10:06:20 +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 1760b42127 Merge branch 'pre_trustie_server' into trustie_server 2022-01-14 17:38:27 +08:00
yystopf 9f7725b097 Merge branch 'standalone_develop' into pre_trustie_server 2022-01-14 17:38:16 +08:00
yystopf 612101498c Merge branch 'develop' into standalone_develop 2022-01-14 17:38:09 +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 ab6ac05a7d Merge branch 'pre_trustie_server' into trustie_server 2022-01-11 10:53:40 +08:00
yystopf cf69628f85 Merge branch 'standalone_develop' into pre_trustie_server 2022-01-11 10:53:29 +08:00
yystopf 4a8f8af896 Merge branch 'develop' into standalone_develop 2022-01-11 10:48:56 +08:00
yystopf f9bc2258ec fix: migrate repo github use another addr 2022-01-11 10:48:29 +08:00
187 changed files with 4987 additions and 2580 deletions

3
.gitignore vendored
View File

@ -84,4 +84,5 @@ redis_data/
Dockerfile
dump.rdb
.tags*
ceshi_user.xlsx
ceshi_user.xlsx
public/trace_task_results

View File

@ -1,6 +1,25 @@
class AccountsController < ApplicationController
before_action :require_login, only: [:login_check, :simple_update]
include ApplicationHelper
#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
render json: session
end
@ -192,7 +211,9 @@ class AccountsController < ApplicationController
sync_params = {
password: params[:password].to_s,
email: @user.mail
email: @user.mail,
login_name: @user.name,
source_id: 0
}
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
@ -313,6 +334,11 @@ class AccountsController < ApplicationController
Register::CheckColumnsForm.new(check_params).validate!
render_ok
end
def login_check
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
render_ok
end
private
@ -381,4 +407,7 @@ class AccountsController < ApplicationController
params.permit(:username, :email, :password, :platform)
end
def simple_update_params
params.permit(:username, :email, :password, :platform)
end
end

View File

@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
def create
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)
rescue Admins::ImportUserService::Error => ex
render_error(ex)

View File

@ -0,0 +1,57 @@
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
before_action :find_glcc, only: [:edit, :update, :destroy]
def index
q = ::Topic::GlccNews.ransack(title_cont: params[:search])
glcc_news = q.result(distinct: true)
@glcc_news = paginate(glcc_news)
end
def new
@glcc = ::Topic::GlccNews.new
end
def create
@glcc = ::Topic::GlccNews.new(glcc_params)
if @glcc.save
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "新增新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "新增新闻稿失败"
end
end
def edit
end
def update
@glcc.attributes = glcc_params
if @glcc.save
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "更新新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "更新新闻稿失败"
end
end
def destroy
if @glcc.destroy
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "删除新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "删除新闻稿失败"
end
end
private
def find_glcc
@glcc = ::Topic::GlccNews.find_by_id(params[:id])
end
def glcc_params
params.require(:topic_glcc_news).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -217,7 +217,7 @@ class AttachmentsController < ApplicationController
if @file.container && current_user.logged?
if @file.container.is_a?(Issue)
course = @file.container.project
candown = course.member?(current_user)
candown = course.member?(current_user) || course.is_public
elsif @file.container.is_a?(Journal)
course = @file.container.issue.project
candown = course.member?(current_user)

View File

@ -8,7 +8,7 @@ class Ci::BaseController < ApplicationController
namespace = params[:owner]
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
def load_all_repo

View File

@ -46,7 +46,7 @@ class Ci::SecretsController < Ci::BaseController
end
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
end

View File

@ -9,6 +9,10 @@ class CompareController < ApplicationController
load_compare_params
compare
@merge_status, @merge_message = get_merge_message
@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
@ -16,6 +20,7 @@ class CompareController < ApplicationController
if @base.blank? || @head.blank?
return -2, "请选择分支"
else
return -2, "目标仓库未开启合并请求PR功能" unless @project.has_menu_permission("pulls")
if @head.include?(":")
fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take
return -2, "请选择正确的仓库" unless fork_project.present?
@ -50,6 +55,14 @@ class CompareController < ApplicationController
end
def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, CGI.escape(base), CGI.escape(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

View File

@ -179,7 +179,7 @@ module Ci::CloudAccountManageable
def drone_oauth_user!(url, state)
logger.info "[drone] drone_oauth_user url: #{url}"
conn = Faraday.new(url: url) do |req|
conn = Faraday.new(url: "#{Gitea.gitea_config[:domain]}#{url}") do |req|
req.request :url_encoded
req.adapter Faraday.default_adapter
req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}"
@ -188,7 +188,8 @@ module Ci::CloudAccountManageable
response = conn.get
logger.info "[drone] response headers: #{response.headers}"
response.headers['location'].include?('error') ? false : true
true
# response.headers['location'].include?('error') ? false : true
end
private

View File

@ -108,7 +108,11 @@ module LoginHelper
def sync_pwd_to_gitea!(user, hash={})
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))
if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"

View File

@ -58,4 +58,32 @@ module RegisterHelper
end
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

View File

@ -4,7 +4,7 @@ module RenderHelper
end
def render_error(message = '')
render json: { status: -1, message: message }
render json: { status: status, message: message }
end
def render_not_acceptable(message = '请求已拒绝')

View File

@ -24,13 +24,13 @@ class IssuesController < ApplicationController
@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(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)
@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")
@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)
respond_to do |format|
@ -109,7 +109,7 @@ class IssuesController < ApplicationController
def create
issue_params = issue_send_params(params)
Issues::CreateForm.new({subject:issue_params[:subject]}).validate!
Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
@issue = Issue.new(issue_params)
if @issue.save!
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
@ -149,6 +149,8 @@ class IssuesController < ApplicationController
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: ProjectTrend::CLOSE) if params[:status_id].to_i == 5
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
@ -178,6 +180,7 @@ class IssuesController < ApplicationController
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|
next if tag == [""]
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end
else
@ -220,7 +223,7 @@ class IssuesController < ApplicationController
normal_status(-1, "不允许修改为关闭状态")
else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate!
Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
if @issue.update_attributes(issue_params)
if @issue&.pull_request.present?
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
@ -244,7 +247,7 @@ class IssuesController < ApplicationController
end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@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.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))

View File

@ -23,6 +23,7 @@ class JournalsController < ApplicationController
normal_status(-1, "评论内容不能为空")
else
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 = {
journalized_id: @issue.id ,
journalized_type: "Issue",
@ -53,6 +54,9 @@ class JournalsController < ApplicationController
end
end
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def destroy
@ -70,7 +74,8 @@ class JournalsController < ApplicationController
def update
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)
normal_status(0, "更新成功")
else
@ -79,7 +84,9 @@ class JournalsController < ApplicationController
else
normal_status(-1, "评论的内容不能为空")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def get_children_journals

View File

@ -0,0 +1,21 @@
class NoticesController < ApplicationController
def create
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)
else
tip_exception("#{params["source"]}未配置")
end
render_ok
end
end

View File

@ -5,7 +5,11 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
def index
@organization_users = @organization.organization_users.includes(:user)
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
@organization_users = kaminari_paginate(@organization_users)
end

View File

@ -44,7 +44,7 @@ class Organizations::TeamsController < Organizations::BaseController
def create
ActiveRecord::Base.transaction do
if @organization.teams.count >= 50
return render_forbidden("组织的团队数量已超过限制!")
return tip_exception("组织的团队数量已超过限制!")
else
Organizations::CreateTeamForm.new(team_params).validate!
@team = Organizations::Teams::CreateService.call(current_user, @organization, team_params)

View File

@ -12,7 +12,7 @@ class OwnersController < ApplicationController
def show
@owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
return render_ok(type: 'User') unless @owner.present?
return render_not_found unless @owner.present?
# 组织
if @owner.is_a?(Organization)
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition

View File

@ -12,6 +12,7 @@ class PraiseTreadController < ApplicationController
begin
return normal_status(2, "你已点过赞了") if current_user.liked?(@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)})
rescue Exception => e
uid_logger_error(e.message)

View File

@ -13,6 +13,8 @@ class ProjectsController < ApplicationController
def menu_list
menu = []
user_is_admin = current_user.admin? || @project.manager?(current_user)
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("issues")) if @project.has_menu_permission("issues")
@ -20,9 +22,11 @@ class ProjectsController < ApplicationController
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge?
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && (current_user.admin? || @project.member?(current_user.id))
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("settings")) if (current_user.admin? || @project.manager?(current_user)) && @project.forge?
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
end
@ -59,7 +63,7 @@ class ProjectsController < ApplicationController
Projects::MigrateForm.new(mirror_params).validate!
@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]
uid_logger("########## 已动加速器 ##########")
result = Gitea::Accelerator::MigrateService.call(mirror_params)
@ -71,6 +75,11 @@ class ProjectsController < ApplicationController
else
Projects::MigrateService.call(current_user, mirror_params)
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
Projects::MigrateService.call(current_user, mirror_params)
end
@ -83,7 +92,7 @@ class ProjectsController < ApplicationController
return @branches = [] unless @project.forge?
# result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier)
result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name])
@branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result
end
@ -130,7 +139,7 @@ class ProjectsController < ApplicationController
validate_params = project_params.slice(:name, :description,
: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
@ -172,6 +181,22 @@ class ProjectsController < ApplicationController
tip_exception(e.message)
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
watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct
@watchers_count = watchers.size
@ -185,7 +210,7 @@ class ProjectsController < ApplicationController
end
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
@fork_users = paginate(fork_users)
end

View File

@ -2,7 +2,7 @@ class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show, :files, :commits]
before_action :require_profile_completed, only: [:create]
before_action :load_repository
before_action :check_menu_authorize
before_action :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 :load_pull_request, only: [:files, :commits]
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))
@all_issues = issues.distinct
@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})
@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})
@ -29,7 +29,7 @@ class PullRequestsController < ApplicationController
end
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?
@projects_names = [{
project_user_login: @owner.try(:login),
@ -50,7 +50,7 @@ class PullRequestsController < ApplicationController
end
def get_branches
branch_result = Branches::ListService.call(@owner, @project)
branch_result = Branches::ListService.call(@owner, @project, params[:name])
render json: branch_result
# return json: branch_result
end
@ -58,6 +58,7 @@ class PullRequestsController < ApplicationController
def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
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)
if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
@ -89,7 +90,7 @@ class PullRequestsController < ApplicationController
else
ActiveRecord::Base.transaction do
begin
return normal_status(-1, "title不能超过255个字符") if params[:title].length > 255
Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
@ -274,12 +275,12 @@ class PullRequestsController < ApplicationController
base: params[:base], #目标分支
milestone: 0, #里程碑,未与本地的里程碑关联
}
assignee_login = User.find_by_id(params[:assigned_to_id])&.login
@requests_params = @local_params.merge({
assignee: current_user.try(:login),
# assignees: ["#{params[:assigned_login].to_s}"],
assignees: ["#{current_user.try(:login).to_s}"],
labels: params[:issue_tag_ids],
due_date: Time.now
assignees: ["#{assignee_login.to_s}"],
labels: params[:issue_tag_ids]
# due_date: Time.now
})
@issue_params = {
author_id: current_user.id,

View File

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

View File

@ -1,14 +1,24 @@
class SettingsController < ApplicationController
def show
@old_projects_url = nil
get_navbar
get_add_menu
get_common_menu
get_sub_competitions
get_personal_menu
get_third_party
get_top_system_notification
end
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
@add = []
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
@ -20,6 +30,15 @@ class SettingsController < ApplicationController
end
end
def get_sub_competitions
@sub_competitions = []
Site.competition.pluck(:key).uniq.each do |key|
hash = {"identifier": "#{key.to_s}"}
hash.merge!("list": Site.competition.where(key: key).select(:id, :name, :url, :key).to_a.map(&:serializable_hash))
@sub_competitions << hash
end
end
def get_common_menu
@common = {}
Site.common.select(:url, :key).each do |site|

View File

@ -0,0 +1,18 @@
class Traces::BaseController < ApplicationController
helper_method :observed_logged_user?, :observed_user
def observed_user
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
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
end

View File

@ -0,0 +1,83 @@
class Traces::ProjectsController < Traces::BaseController
include OperateProjectAbilityAble
before_action :require_login
before_action :load_project
before_action :authorizate_user_can_edit_project!, except: [:task_results]
def tasks
branch_name = params[:branch_name]
return render_error("无可用检测次数") if @project.user_trace_tasks.size >= 5
return render_error("分支名不能为空!") if branch_name.blank?
@all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier)
return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name)
code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name)
if code == 200
UserTraceTask.create!(
user_id: current_user.id,
project_id: @project.id,
branch_tag: branch_name,
task_id: data["task_id"]
)
render_ok
else
render_error("检测失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def task_results
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil?
code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit)
if code == 200
render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size, data: data}
else
render_error("获取检测记录失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def reload_task
return render_error("project_id错误") if params[:project_id].blank?
branch_name = params[:branch_name]
return render_error("分支名不能为空!") if branch_name.blank?
@all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier)
return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name)
code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id])
if code == 200
UserTraceTask.create!(
user_id: current_user.id,
project_id: @project.id,
branch_tag: branch_name,
task_id: data["task_id"]
)
render_ok
else
render_error("重新检测失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def task_pdf
return render_error("task_id错误") if params[:task_id].blank?
result = Trace::PdfReportService.call(current_user.trace_token, params[:task_id])
if result.is_a?(Hash) && result[:code] == 200
redirect_to result[:download_url]
else
render_error("下载报告失败!")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
end

View File

@ -0,0 +1,14 @@
class Traces::TraceUsersController < Traces::BaseController
before_action :require_login
def create
if current_user.trace_token.present?
render_ok
else
render_error(-1, "代码溯源用户初始化失败")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
end

View File

@ -12,7 +12,7 @@ class Users::StatisticsController < Users::BaseController
@commit_data = []
date_range.each do |date|
@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
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)

View File

@ -23,6 +23,8 @@ class Users::TemplateMessageSettingsController < Users::BaseController
def get_current_setting
@current_setting = @_observed_user.user_template_message_setting
@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
def setting_params

View File

@ -1,324 +1,399 @@
class UsersController < ApplicationController
include ApplicationHelper
include Ci::DbConnectable
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me list sync_user_info]
before_action :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update, :update_image]
skip_before_action :check_sign, only: [:attachment_show]
def connect_to_ci_db(options={})
if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?)
return
end
if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE
connect_to_trustie_ci_database(options)
else
connect_to_ci_database(options)
end
end
def list
scope = User.active.recent.like(params[:search]).includes(:user_extension)
@total_count = scope.size
@users = paginate(scope)
end
def show
#待办事项,现在未做
if User.current.admin? || User.current.login == @user.login
@waiting_applied_messages = @user.applied_messages.waiting
@common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common
@common_applied_projects = AppliedProject.where(project_id: @user.full_admin_projects).common
#@undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size
@undo_events = @common_applied_transfer_projects.size + @common_applied_projects.size
else
@waiting_applied_messages = AppliedMessage.none
@common_applied_transfer_projects = AppliedTransferProject.none
@common_applied_projects = AppliedProject.none
@undo_events = 0
end
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 0
user_organizations = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)) + @user.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @user.organizations.with_visibility("common")
@user_org_count = user_organizations.size
normal_projects = Project.members_projects(@user.id).to_sql
org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @user.id}).to_sql
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? projects : projects.visible
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size
# 为了缓存活跃用户的基本信息,后续删除
Cache::V2::OwnerCommonService.new(@user.id).read
end
def watch_users
watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc")
if params[:search].present?
search_user_ids = User.where(id: watchers.pluck(:watchable_id)).like(params[:search]).pluck(:id)
watchers = watchers.where(watchable_id: search_user_ids)
end
@watchers_count = watchers.size
@watchers = paginate(watchers)
end
def fan_users
watchers = @user.watchers.includes(:user).order("watchers.created_at desc")
watchers = watchers.joins(:user).merge(User.like(params[:search]))
@watchers_count = watchers.size
@watchers = paginate(watchers)
end
def hovercard
end
def update
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)) if user_params[:image].present?
@user.attributes = user_params.except(:image)
unless @user.save
render_error(-1, @user.errors.full_messages.join(", "))
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 me
@user = current_user
end
# 贴吧获取用户信接口
def get_user_info
begin
@user = current_user
begin
result = Notice::Read::CountService.call(current_user.id)
@message_unread_total = result.nil? ? 0 : result[2]["unread_notification"]
rescue
@message_unread_total = 0
end
# TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
rescue Exception => e
uid_logger_error(e.message)
missing_template
end
end
def attachment_show
file_name = params[:file_name]
path = params[:path] || file_storage_directory
send_file "#{path}/#{file_name}", :filename => "#{file_name}",
:type => 'game',
:disposition => 'attachment' #inline can open in browser
end
def html_show
@contents = File.read("#{params[:path]}")
respond_to do |format|
format.html {render :layout => false}
end
end
# Redo: 消息总数缓存
def get_navigation_info
# @old_domain = edu_setting('old_edu_host')
# @user = current_user
# # 新消息数
# @new_message = @user.tidings.where("created_at > '#{@user.click_time}'").count > 0 || @user.private_messages.where("created_at > '#{@user.click_time}'").count > 0
#
# @user_url = "/users/#{@user.login}"
# @career = Career.where(status: true).order("created_at asc").pluck(:id, :name)
# @auth = User.current.ec_school.present? ? "#{@old_domain}/ecs/department?school_id=#{User.current.ec_school}" : nil
end
# 用户回复功能
def reply_message
message = JournalsForMessage.new(reply_message_params)
message.user_id = current_user.id
message.save!
render_ok(id: message.id)
end
# 搜索用户具有管理员角色的项目
def search_user_projects
projects = Project.where.not(status: 9)
projects = projects.joins(members: :member_roles).where(member_roles: { role_id: 3 })
projects = projects.where(members: { user_id: current_user.id })
search = params[:search].to_s.strip
projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present?
@projects = projects.select(:id, :name)
end
#TODO 个人主页信息forge上弃用-hs, 0602
def homepage_info
#待办事项,现在未做
@undo_events = 10
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 10
end
def brief_introduction
content = params[:content].to_s.strip
current_user.user_extension.update!(brief_introduction: content)
render_ok
end
def attendance
attendance = Users::AttendanceService.call(current_user)
render_ok(grade: current_user.grade, next_gold: attendance.next_gold)
rescue Users::AttendanceService::Error => ex
render_error(ex.message)
end
# 其他平台登录后必须将token同步到forge平台实现sso登录功能
def sync_token
return render_error('未找相关用户!') unless @user
token = Token.get_or_create_permanent_login_token(@user, 'autologin')
token.update_column(:value, params[:token])
render_ok
end
def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = []
domain_url = EduSetting.get('host_name')
if projects.present?
projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}"
pj = {
id: p.id,
name: p.name,
is_public: p.is_public,
updated_on: p.updated_on.strftime("%Y-%m-%d"),
status: p.status,
is_member: p.member?(current_user.try(:id)),
owner: {
name: p.owner.try(:show_real_name),
login: p.owner.login
},
members_count: p&.members.size,
issues_count: p.issues_count - p.pull_requests_count,
commits_count: p&.project_score&.changeset_num.to_i,
http_url: domain_url + project_url,
http_collaborator_url: domain_url + project_url + "/setting/collaborator",
http_issues_url: domain_url + project_url + "/issues",
http_commits_url: domain_url + project_url + "/commits",
project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {}
}
projects_json.push(pj)
end
end
Rails.logger.info("==========projects_json========+########{projects_json}")
render json: { projects: projects_json.present? ? projects_json : {} }
end
def trustie_projects
user_id = User.select(:id, :login).where(login: params[:login])&.first&.id
projects = Project.visible
projects = projects.joins(:members).where(members: { user_id: user_id })
search = params[:search].to_s.strip
projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present?
projects = projects.select(:id, :name).limit(10).as_json
render json: { projects: projects }
end
def projects
is_current_admin_user = User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
scope = Projects::ListMyQuery.call(params, @user,is_current_admin_user)
@total_count = scope.size
@projects = paginate(scope)
end
# TODO 其他平台登录时同步修改gitea平台对应用户的密码
# 该方法主要用于别的平台初次部署对接forge平台同步用户后gitea平台对应的用户密码与forge平台用户密码不一致是问题
def sync_gitea_pwd
return render_error("未找到相关的用户") if @user.blank?
flag = sync_pwd_to_gitea!(@user, {password: params[:password].to_s})
flag ? render_ok : render_error('同步失败!')
end
# TODO
# 同步trusite平台用户的salt信息只需同步一次同步完成后该方法可以删除
def sync_salt
user = User.find_by_login params[:login]
return if user.blank?
user.update_column(:salt, params[:salt])
render_ok
end
def sync_user_info
user = User.find_by_login params[:login]
return render_forbidden unless user === current_user
sync_params = {
email: params[:email],
password: params[:password]
}
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate!
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE)
render_ok
else
render_error(interactor.error)
end
end
private
def load_user
@user = User.find_by_login(params[:id]) || User.find_by(id: params[:id])
end
def user_params
params.require(:user).permit(:nickname, :image,
user_extension_attributes: [
:gender, :location, :location_city,
:occupation, :technical_title,
:school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description,
:show_email, :show_location, :show_department]
)
end
def reply_message_params
normal_status(-1, "参数不对") if params[:journals_for_message][:jour_type].nil? || params[:journals_for_message][:jour_id].nil? ||
params[:journals_for_message][:notes].nil? || params[:journals_for_message][:reply_id].nil?
params.require(:journals_for_message).permit(:jour_type, :jour_id, :notes, :m_parent_id, :reply_id)
end
def check_user_exist
return if @user.present?
render_not_found
end
end
class UsersController < ApplicationController
include ApplicationHelper
include Ci::DbConnectable
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me sync_user_info]
before_action :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update, :update_image]
skip_before_action :check_sign, only: [:attachment_show]
before_action :sso_login, only: [:get_user_info]
def connect_to_ci_db(options={})
if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?)
return
end
if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE
connect_to_trustie_ci_database(options)
else
connect_to_ci_database(options)
end
end
def list
scope = User.active.recent.like(params[:search]).includes(:user_extension)
@total_count = scope.size
@users = paginate(scope)
end
def show
#待办事项,现在未做
if User.current.admin? || User.current.login == @user.login
@waiting_applied_messages = @user.applied_messages.waiting
@common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common
@common_applied_projects = AppliedProject.where(project_id: @user.full_admin_projects).common
#@undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size
@undo_events = @common_applied_transfer_projects.size + @common_applied_projects.size
else
@waiting_applied_messages = AppliedMessage.none
@common_applied_transfer_projects = AppliedTransferProject.none
@common_applied_projects = AppliedProject.none
@undo_events = 0
end
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 0
user_organizations = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)) + @user.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @user.organizations.with_visibility("common")
@user_org_count = user_organizations.size
normal_projects = Project.members_projects(@user.id).to_sql
org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @user.id}).to_sql
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? projects : projects.visible
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size
# 为了缓存活跃用户的基本信息,后续删除
Cache::V2::OwnerCommonService.new(@user.id).read
end
def watch_users
watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc")
if params[:search].present?
search_user_ids = User.where(id: watchers.pluck(:watchable_id)).like(params[:search]).pluck(:id)
watchers = watchers.where(watchable_id: search_user_ids)
end
@watchers_count = watchers.size
@watchers = paginate(watchers)
end
def fan_users
watchers = @user.watchers.includes(:user).order("watchers.created_at desc")
watchers = watchers.joins(:user).merge(User.like(params[:search]))
@watchers_count = watchers.size
@watchers = paginate(watchers)
end
def hovercard
end
def update
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)) if user_params[:image].present?
@user.attributes = user_params.except(:image)
unless @user.save
render_error(-1, @user.errors.full_messages.join(", "))
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
@user = current_user
end
# 贴吧获取用户信接口
def get_user_info
begin
@user = current_user
begin
result = Notice::Read::CountService.call(current_user.id)
@message_unread_total = result.nil? ? 0 : result[2]["unread_notification"]
rescue
@message_unread_total = 0
end
# TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
rescue Exception => e
uid_logger_error(e.message)
missing_template
end
end
def attachment_show
file_name = params[:file_name]
path = params[:path] || file_storage_directory
send_file "#{path}/#{file_name}", :filename => "#{file_name}",
:type => 'game',
:disposition => 'attachment' #inline can open in browser
end
def html_show
@contents = File.read("#{params[:path]}")
respond_to do |format|
format.html {render :layout => false}
end
end
# Redo: 消息总数缓存
def get_navigation_info
# @old_domain = edu_setting('old_edu_host')
# @user = current_user
# # 新消息数
# @new_message = @user.tidings.where("created_at > '#{@user.click_time}'").count > 0 || @user.private_messages.where("created_at > '#{@user.click_time}'").count > 0
#
# @user_url = "/users/#{@user.login}"
# @career = Career.where(status: true).order("created_at asc").pluck(:id, :name)
# @auth = User.current.ec_school.present? ? "#{@old_domain}/ecs/department?school_id=#{User.current.ec_school}" : nil
end
# 用户回复功能
def reply_message
message = JournalsForMessage.new(reply_message_params)
message.user_id = current_user.id
message.save!
render_ok(id: message.id)
end
# 搜索用户具有管理员角色的项目
def search_user_projects
projects = Project.where.not(status: 9)
projects = projects.joins(members: :member_roles).where(member_roles: { role_id: 3 })
projects = projects.where(members: { user_id: current_user.id })
search = params[:search].to_s.strip
projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present?
@projects = projects.select(:id, :name)
end
#TODO 个人主页信息forge上弃用-hs, 0602
def homepage_info
#待办事项,现在未做
@undo_events = 10
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 10
end
def brief_introduction
content = params[:content].to_s.strip
current_user.user_extension.update!(brief_introduction: content)
render_ok
end
def attendance
attendance = Users::AttendanceService.call(current_user)
render_ok(grade: current_user.grade, next_gold: attendance.next_gold)
rescue Users::AttendanceService::Error => ex
render_error(ex.message)
end
# 其他平台登录后必须将token同步到forge平台实现sso登录功能
def sync_token
return render_error('未找相关用户!') unless @user
token = Token.get_or_create_permanent_login_token(@user, 'autologin')
token.update_column(:value, params[:token])
render_ok
end
def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = []
domain_url = EduSetting.get('host_name')
if projects.present?
projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}"
pj = {
id: p.id,
name: p.name,
is_public: p.is_public,
updated_on: p.updated_on.strftime("%Y-%m-%d"),
status: p.status,
is_member: p.member?(current_user.try(:id)),
owner: {
name: p.owner.try(:show_real_name),
login: p.owner.login
},
members_count: p&.members.size,
issues_count: p.issues_count - p.pull_requests_count,
commits_count: p&.project_score&.changeset_num.to_i,
http_url: domain_url + project_url,
http_collaborator_url: domain_url + project_url + "/setting/collaborator",
http_issues_url: domain_url + project_url + "/issues",
http_commits_url: domain_url + project_url + "/commits",
project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {}
}
projects_json.push(pj)
end
end
Rails.logger.info("==========projects_json========+########{projects_json}")
render json: { projects: projects_json.present? ? projects_json : {} }
end
def trustie_projects
user_id = User.select(:id, :login).where(login: params[:login])&.first&.id
projects = Project.visible
projects = projects.joins(:members).where(members: { user_id: user_id })
search = params[:search].to_s.strip
projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present?
projects = projects.select(:id, :name).limit(10).as_json
render json: { projects: projects }
end
def projects
is_current_admin_user = User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
scope = Projects::ListMyQuery.call(params, @user,is_current_admin_user)
@total_count = scope.size
@projects = paginate(scope)
end
# TODO 其他平台登录时同步修改gitea平台对应用户的密码
# 该方法主要用于别的平台初次部署对接forge平台同步用户后gitea平台对应的用户密码与forge平台用户密码不一致是问题
def sync_gitea_pwd
return render_error("未找到相关的用户") if @user.blank?
flag = sync_pwd_to_gitea!(@user, {password: params[:password].to_s})
flag ? render_ok : render_error('同步失败!')
end
# TODO
# 同步trusite平台用户的salt信息只需同步一次同步完成后该方法可以删除
def sync_salt
user = User.find_by_login params[:login]
return if user.blank?
user.update_column(:salt, params[:salt])
render_ok
end
def sync_user_info
user = User.find_by_login params[:login]
return render_forbidden unless user === current_user
sync_params = {
email: params[:email],
password: params[:password]
}
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate!
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE)
render_ok
else
render_error(interactor.error)
end
end
def email_search
return render_error('请输入email') if params[:email].blank?
@user = User.find_by(mail: params[:email])
end
private
def load_user
@user = User.find_by_login(params[:id]) || User.find_by(id: params[:id])
end
def user_params
params.require(:user).permit(:nickname, :image,
user_extension_attributes: [
:gender, :location, :location_city,
:occupation, :technical_title,
:school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description,
:show_super_description, :super_description,
:show_email, :show_location, :show_department]
)
end
def reply_message_params
normal_status(-1, "参数不对") if params[:journals_for_message][:jour_type].nil? || params[:journals_for_message][:jour_id].nil? ||
params[:journals_for_message][:notes].nil? || params[:journals_for_message][:reply_id].nil?
params.require(:journals_for_message).permit(:jour_type, :jour_id, :notes, :m_parent_id, :reply_id)
end
def check_user_exist
return if @user.present?
render_not_found
end
def sso_login
if params[:login].present? && !current_user.logged? && params[:websiteName].present?
user = User.where("login = ?", "#{params[:login].presence}").first
# 已同步注册,直接登录
if user.present?
successful_authentication(user)
else
autologin_register_by_educoder(params[:login].presence)
end
end
end
# 通过login参数查询头歌账号信息注册并登录
def autologin_register_by_educoder(edu_login)
req_params = { "login" => "#{edu_login}", "private_token" => "hriEn3UwXfJs3PmyXnSH" }
api_url= "https://data.educoder.net"
client = Faraday.new(url: api_url)
response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params)
result = JSON.parse(response.body)
#查询
return nil if result["status"].to_s != "0"
# login 邮箱 手机号 姓名 学校/单位
user_info = result["data"]
Rails.logger.info("user_info====== #{user_info}")
login = user_info["login"]
email = user_info["mail"]
phone = user_info["phone"]
real_name = user_info["username"]
department_name = user_info["school"]
password = "12345678"
# 没有用户时,新建用户并登录
user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first
if user.present?
# 手机号先记录,后续用
user.update_column(:phone, "#{phone}") if phone.present?
else
ActiveRecord::Base.transaction do
email = "#{login}@gitlink.org.cn" if email.blank?
user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}",
nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0,
password: "#{password}", phone: "#{phone}", profile_completed: 1 }
user = User.create!(user_params)
UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}")
interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: password})
if interactor.success?
gitea_user = interactor.result
Rails.logger.info("Gitea::RegisterInteractor.call result====== #{gitea_user}")
result = Gitea::User::GenerateTokenService.call(login, password)
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
user.save!
else
Rails.logger.info("Gitea::RegisterInteractor.call error====== #{interactor.error}")
end
end
end
successful_authentication(user) if user.present?
end
end

View File

@ -14,7 +14,7 @@ class VersionReleasesController < ApplicationController
def new
#获取所有的分支
@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
get_all_branches.each do |b|
@all_branches.push(b["name"])

View File

@ -16,6 +16,7 @@ includes:
- users
- projects
- repositories
- traces
- pulls
- issues
- organizations

View File

@ -280,7 +280,7 @@ repo |是| |string |项目标识identifier
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置
menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,services:服务,activity:动态,setting:仓库设置
> 返回的JSON示例:
@ -408,7 +408,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:里程碑,wiki:维基,resources:资源库,services:服务 |
### 返回字段说明:

View File

@ -0,0 +1,217 @@
# Traces
## 代码溯源初始化
用户同意协议后请求的接口,创建代码溯源的账号
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/traces/trace_users.json
```
```javascript
await octokit.request('POST /api/traces/trace_users.json')
```
### HTTP 请求
`POST api/traces/trace_users.json`
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 代码分析结果列表
查询项目下代码分析的结果
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/task_results.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/task_results.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/task_results.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner|是|否|string | 项目所有者标识|
repo|是 | 否|string | 项目标识 |
page |否| 1 | int | 页码 |
limit |否| 15 | int | 每页数量 |
### 返回字段说明(暂缺)
<!-- 参数 | 类型 | 字段说明
--------- | ----------- | -----------
total_count |int |总数 |
public_keys.id |int |ID|
public_keys.name |string|密钥标题|
public_keys.content |string|密钥内容|
public_keys.fingerprint |string|密钥标识|
public_keys.created_time |string|密钥创建时间| -->
> 返回的JSON示例:
```json
{
"data": [
{
"accuracy": "20",
"code_type": "C",
"depth": "2",
"detect_flag": "快速-组件级",
"detect_rule": "快速-组件级,2,20,,开源软件,50,10",
"detect_startdate": "2022-05-10 15:59:46 ",
"detect_status": "fail",
"detectflag": "快速-组件级",
"fail_reason": "Invalid package type",
"file_name": "many_branch.zip",
"license_process": "100",
"licenseparam": "开源软件",
"package_type": "",
"product_name": "84727546110",
"project_id": "6dbc3e42-5857-4ca4-a54d-58fd9dbf6dc5",
"sim_process": "100",
"similarity_process": "2",
"task_id": "15139171-091b-4316-98b1-6068970efa44",
"totalsize": 5,
"uid": "78",
"vuln_process": "",
"vulnlevel": ""
}
]
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 新建分析
用户选择仓库分支进行代码分析的接口
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/traces/yystopf/many_branch/tasks.json
```
```javascript
await octokit.request('POST /api/traces/:owner/:repo/tasks.json')
```
### HTTP 请求
`POST api/traces/:owner/:repo/tasks.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
branch_name|是 | 否| string | 分支名称 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 重新扫描
对代码分析结果进行再次分析
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/reload_task.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/reload_task.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/reload_task.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
project_id|是 | 否| string | 代码分析结果里的project_id |
branch_name|是 | 否| string | 分支名称 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 下载报告
把代码分析的结果下载到本地
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/task_pdf.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/task_pdf.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/task_pdf.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
task_id|是 | 否| string | 代码分析结果里的task_id |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>

View File

@ -91,10 +91,9 @@ await octokit.request('GET /api/users/:login/messages.json')
类型|说明
--------- | -----------
|IssueAssigned | 有新指派给我的疑修 |
|IssueAssignerExpire | 我负责的疑修截止日期到达最后一天 |
|IssueExpire | 我创建或负责的疑修截止日期到达最后一天 |
|IssueAtme | 在疑修中@我 |
|IssueChanged | 我创建或负责的疑修状态变更 |
|IssueCreatorExpire | 我创建的疑修截止日期到达最后一天 |
|IssueDeleted | 我创建或负责的疑修删除 |
|IssueJournal | 我创建或负责的疑修有新的评论 |
|LoginIpTip | 登录异常提示 |
@ -109,6 +108,7 @@ await octokit.request('GET /api/users/:login/messages.json')
|ProjectLeft | 账号被移出项目 |
|ProjectMemberJoined | 我管理的仓库有成员加入 |
|ProjectMemberLeft | 我管理的仓库有成员移出 |
|ProjectMilestoneCompleted | 我管理的仓库有里程碑完成度100% |
|ProjectMilestone | 我管理的仓库有新的里程碑 |
|ProjectPraised | 我管理的仓库被点赞 |
|ProjectPullRequest | 我管理/关注的仓库有新的合并请求 |

View File

@ -49,7 +49,7 @@ class BaseForm
def check_verifi_code(verifi_code, code)
code = strip(code)
# return if code == "123123" # TODO 万能验证码,用于测试
return if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试
raise VerifiCodeError, "验证码已失效" if !verifi_code&.effective?
raise VerifiCodeError, "验证码不正确" if verifi_code&.code != code
end

View File

@ -4,7 +4,7 @@ class Gitea::User::UpdateForm
attr_accessor :username, :email, :admin, :allow_create_organization, :allow_git_hook, :allow_import_local,
:full_name, :location, :login_name, :max_repo_creation, :must_change_password, :password, :prohibit_login,
:source_id, :website
:source_id, :website, :new_name
validates :username, presence: true
validates :email, presence: true, format: { with: EMAIL_REGEX, multiline: true }

View File

@ -1,11 +1,11 @@
class Issues::CreateForm
include ActiveModel::Model
attr_accessor :subject
attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -1,10 +1,12 @@
class Issues::UpdateForm
include ActiveModel::Model
attr_accessor :subject
attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -0,0 +1,7 @@
class Journals::CreateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -0,0 +1,8 @@
class Journals::UpdateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -1,5 +1,5 @@
class Projects::UpdateForm < BaseForm
attr_accessor :name, :description, :project_category_id, :project_language_id, :private, :identifier, :user_id, :project_identifier
attr_accessor :name, :description, :project_category_id, :project_language_id, :private, :identifier, :user_id, :project_identifier, :project_name
validates :name, presence: true
validates :name, length: { maximum: 50 }
validates :description, length: { maximum: 200 }
@ -10,6 +10,7 @@ class Projects::UpdateForm < BaseForm
check_project_language(project_language_id)
check_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier
check_project_name(user_id, name) unless name.blank? || name == project_name
end
end

View File

@ -3,28 +3,40 @@ module Register
include ActiveModel::Model
private
def check_login(login)
def check_login(login, user=nil)
login = strip(login)
raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN
login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login)
raise LoginError, '登录名已被使用' if login_exist
if user.present?
raise LoginError, '登录名已被使用' if login_exist && login != user&.login
else
raise LoginError, '登录名已被使用' if login_exist
end
end
def check_mail(mail)
def check_mail(mail, user=nil)
mail = strip(mail)
raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL
mail_exist = Owner.exists?(mail: mail)
raise EmailError, '邮箱已被使用' if mail_exist
if user.present?
raise EmailError, '邮箱已被使用' if mail_exist && mail != user&.mail
else
raise EmailError, '邮箱已被使用' if mail_exist
end
end
def check_phone(phone)
def check_phone(phone, user=nil)
phone = strip(phone)
raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE
phone_exist = Owner.exists?(phone: phone)
raise PhoneError, '手机号已被使用' if phone_exist
if user.present?
raise PhoneError, '手机号已被使用' if phone_exist && phone != user&.phone
else
raise PhoneError, '手机号已被使用' if phone_exist
end
end
end
end

View File

@ -9,11 +9,9 @@ module Register
validate :check!
def check!
Rails.logger.info "Register::Form params: code: #{code}; login: #{login};
namespace: #{namespace}; password: #{password}; password_confirmation: #{password_confirmation}"
Rails.logger.info "Register::Form params: code: #{code}; login: #{login}; namespace: #{namespace}; password: #{password}; type: #{type}"
type = phone_mail_type(strip(login))
db_verifi_code =
db_verifi_code =
if type == 1
check_phone(login)
VerificationCode.where(phone: login, code: code, code_type: 1).last

View File

@ -0,0 +1,19 @@
module Register
class LoginCheckColumnsForm < Register::BaseForm
attr_accessor :type, :value, :user
validates :type, presence: true, numericality: true
validates :value, presence: true
validate :check!
def check!
# params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号)
case strip(type).to_i
when 1 then check_login(strip(value), user)
when 2 then check_mail(strip(value), user)
when 3 then check_phone(strip(value), user)
else raise("type值无效")
end
end
end
end

View File

@ -1,477 +1,486 @@
# 所有的方法请按首字母的顺序依次列出
module ApplicationHelper
include Gitlink::I18n
include GitHelper
ONE_MINUTE = 60 * 1000
ONE_HOUR = 60 * ONE_MINUTE
ONE_DAY = 24 * ONE_HOUR
ONE_MONTH = 30 * ONE_DAY
ONE_YEAR = 12 * ONE_MONTH
# 全局参数配置
def edu_setting name
EduSetting.get(name)
end
# xss共计问题
def content_safe content
tags = %w(
a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl
dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark
ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td
tfoot th thead time tr u ul var wbr div span
)
attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style)
sanitize content, tags: tags, attributes: attributes
end
def graduation_navigation graduation
graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务"
end
def graduation_navigation_id course
course.course_modules.find_by(module_type: "graduation").try(:id)
end
# git用户
# git用户命名规则login+"@educoder.net"
def git_username(email)
User.find_by_mail(email) || User.find_by_login(email.split("@").first)
end
# 不同的类型扩展不同的目录
def relative_path
"avatars"
end
def replace_bytes_to_b(size_string)
return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B")
end
def storage_path
File.join(Rails.root, "public", "images", relative_path)
end
# 推荐实训
def recommend_shixun(shixun)
tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0
shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and
shixun_id != #{shixun.id}").pluck(:shixun_id)
shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",")
Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id
in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3)
end
# shixun开启挑战对应的行为名及url
def task_operation_url current_myshixun, shixun
if current_myshixun.blank?
name = shixun.status == 0 ? "模拟实战" : "开启挑战"
url = "/shixuns/#{shixun.identifier}/shixun_exec"
else
identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier)
if current_myshixun.status == 1
name = "查看实战"
else
name = "继续挑战"
end
url = identifier
end
[name, url]
end
# 获取当前时间
def time_from_now(time)
if String === time
time = Time.parse(time)
end
lastUpdateTime = time.to_i*1000
currentTime = Time.now.to_i*1000
timePassed = currentTime - lastUpdateTime
timeIntoFormat = 0
updateAtValue = ""
if timePassed < 0
updateAtValue = "刚刚"
elsif timePassed < ONE_MINUTE
updateAtValue = "1分钟前"
elsif timePassed < ONE_HOUR
timeIntoFormat = timePassed / ONE_MINUTE
updateAtValue = timeIntoFormat.to_s + "分钟前"
elsif (timePassed < ONE_DAY)
timeIntoFormat = timePassed / ONE_HOUR
updateAtValue = timeIntoFormat.to_s + "小时前"
elsif (timePassed < ONE_MONTH)
timeIntoFormat = timePassed / ONE_DAY
updateAtValue = timeIntoFormat.to_s + "天前"
elsif (timePassed < ONE_YEAR)
timeIntoFormat = timePassed / ONE_MONTH
updateAtValue = timeIntoFormat.to_s + "个月前"
else
timeIntoFormat = timePassed / ONE_YEAR
updateAtValue = timeIntoFormat.to_s + "年前"
end
updateAtValue
end
# 计算到结束还有多长时间 **天**小时**分
def how_much_time(time)
if time.nil? || time < Time.now #6.21 -hs 增加小于time.now
''
else
result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + ""
result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 "
result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + ""
end
end
def format_time(time)
time.present? ? time.strftime("%Y-%m-%d %H:%M") : ''
end
# 用户图像url如果不存在的话source为匿名用户即默认使用匿名用户图像
def url_to_avatar(source)
if File.exist?(disk_filename(source&.class, source&.id))
ctime = File.ctime(disk_filename(source.class, source.id)).to_i
if %w(User Organization).include?(source.class.to_s)
File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
else
File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
end
elsif source.class.to_s == 'User'
source.get_letter_avatar_url
end
end
# 主页banner图
def banner_img(source_type)
if File.exist?(disk_filename(source_type, "banner"))
ctime = File.ctime(disk_filename(source_type, "banner")).to_i
File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}"
end
end
def disk_filename(source_type,source_id,image_file=nil)
File.join(storage_path, "#{source_type}", "#{source_id}")
end
def disk_auth_filename(source_type, source_id, type)
File.join(storage_path, "#{source_type}", "#{source_id}#{type}")
end
def disk_real_name_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'ID')
end
def auth_file_url(source_type, source_id, type)
File.join('/images', relative_path, source_type, "#{source_id}#{type}")
end
def real_name_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'ID')
end
def disk_professional_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'PRO')
end
def professional_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'PRO')
end
def shixun_url_to_avatar(shixun)
if File.exist?(disk_filename(shixun.class, shixun.id))
File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}")
else
File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg")
end
end
# 选用实训的学校情况
def school_user_detail shixun
user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据
school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq
school_names = School.where(id: school_ids[0..1]).pluck(:name)
school_size = school_ids.size
str = school_size > 0 ? "#{school_names.join("")}#{school_size}" : "0所"
end
# 普通/分组 作业作品状态数组
def student_work_status homework, user_id, course, work
status = []
homework_setting = homework.homework_group_setting user_id, true
work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id)
late_time = homework.late_time || course.end_date
if course.is_end && work && work.work_status > 0
status << "查看作品"
elsif !course.is_end
if homework_setting.publish_time && homework_setting.publish_time < Time.now
# 作业未截止时
if homework_setting.end_time > Time.now
if homework.homework_type == "group" && homework.homework_detail_group.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "提交作品"
else
status << "修改作品"
end
else
if work.work_status == 0
status << "提交作品"
else
status << "修改作品"
end
end
# 补交阶段
elsif homework.allow_late && (late_time.nil? || late_time > Time.now)
if homework.homework_type == "group" && homework.homework_detail_group.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
else
if work.work_status == 0
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
end
# 匿评阶段
elsif work.work_status != 0
if homework.homework_detail_manual.comment_status == 3
work_ids = homework.student_works.has_committed.pluck(:id)
if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0
status << "匿评作品"
end
end
status << "查看作品"
end
end
end
end
def commit_des_status work, homework
status = []
homework_setting = homework.homework_group_setting work.user_id
# 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结
if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 &&
((homework_setting.end_time && homework_setting.end_time > Time.now) ||
(homework.allow_late && homework.late_time && homework.late_time > Time.now))
work.description.present? ? status << "修改总结" : status << "提交总结"
end
end
def download_url attachment,options={}
attachment_path(attachment,options)
end
# 耗时:天、小时、分、秒
# 小于1分钟则不显示
def game_spend_time time
day = time / 86400
hour = time % (24*60*60) / (60*60)
min = time % (24*60*60) % (60*60) / 60
sec = time % (24*60*60) % (60*60) % 60
if day < 1
if hour < 1
if min < 1
if sec < 1
time = "--"
else
time = "#{sec}"
end
else
time = "#{min}分钟 #{sec}"
end
else
time = "#{hour}小时 #{min}分钟 #{sec}"
end
else
time = "#{day}#{hour}小时 #{min}分钟 #{sec}"
end
return time
end
def absolute_path(file_path)
file_root_directory + File.join(edu_setting('attachment_folder'), file_path)
end
def file_root_directory
Rails.root.to_s
end
def file_storage_directory
file_root_directory + edu_setting('attachment_folder')
end
def local_path(file)
File.join(file.disk_directory, file.disk_filename)
end
def update_downloads(file)
file.update_attributes(:downloads => file.downloads + 1)
end
# 项目信息,
def project_info work, current_user, course_identity
project = work.project
if project
if project.status == 9
{id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count}
else
project_score = project.project_score
if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT
{id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count,
all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score,
attachment_score: project_score.attachment_score, message_score: project_score.message_score}
else
{id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count,
all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score,
attachment_score: project_score.attachment_score, message_score: project_score.message_score}
end
end
else
{id: -1, name: "--", title: "--"}
end
end
def message_content(content)
content = (strip_html content).strip
content = content.gsub(/\s+/, " ")
if content.gsub(" ", "") == ""
content = "[非文本消息]"
end
content
end
def strip_html(text, len=0, endss="...")
ss = ""
if !text.nil? && text.length>0
ss=text.gsub(/<\/?.*?>/, '').strip
ss = ss.gsub(/&nbsp;*/, '')
ss = ss.gsub(/\r\n/,'') #新增
ss = ss.gsub(/\n/,'') #新增
if len > 0 && ss.length > len
ss = ss[0, len] + endss
elsif len > 0 && ss.length <= len
ss = ss
#ss = truncate(ss, :length => len)
end
end
ss
end
def strip_export_title(content)
con_ = ""
if content.length > 0
con_ = strip_tags(content)
con_ = con_.gsub(/\r\n/,'').gsub(/&nbsp;*/, '').strip
end
con_
end
def pdf_load_sources(*arg)
arr = arg.map do |path|
content_tag(:script) do
File.open(Rails.root.join('public', path)).read.to_s.html_safe
end
end
raw arr.join('')
end
# 导出pdf时转化markdown为html
def to_markdown(text,origin_url)
return nil if text.blank?
options = {
:autolink => true,
:no_intra_emphasis => true,
:fenced_code_blocks => true,
:lax_html_blocks => true,
:strikethrough => true,
:superscript => false,
:tables => true
}
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
m_t = markdown.render(text)
m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t
end
def shixun_status_class(shixun)
case shixun.status
when 0 then 'text-info'
when 1 then 'text-warning'
when 2 then 'text-success'
when 3 then 'text-secondary'
end
end
def render_unix_time(date)
date.to_time.to_i
end
def find_user_by_login(login)
User.find_by_login login
end
def find_user_by_login_and_mail(login, mail)
User.find_by(login: login, mail: mail)
end
def find_user_by_gitea_uid(gitea_uid)
User.find_by(gitea_uid: gitea_uid)
end
def find_user_in_redis_cache(login, email)
$redis_cache.hgetall("v2-owner-common:#{login}-#{email}")
end
def find_user_in_redis_cache_by_id(id)
$redis_cache.hgetall("v2-owner-common:#{id}")
end
def render_base64_decoded(str)
return nil if str.blank?
Base64.decode64 str
end
def render_admin_statistics_item
url = Rails.application.config_for(:configuration)["admin_statistics_url"]
return if url.blank?
content_tag(:li) do
sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root')
end
end
# 1 手机类型0 邮箱类型
# 注意新版的login是自动名生成的
def phone_mail_type value
value =~ /^1\d{10}$/ ? 1 : 0
end
def strip(str)
str.to_s.strip.presence
end
end
# 所有的方法请按首字母的顺序依次列出
module ApplicationHelper
include Gitlink::I18n
include GitHelper
ONE_MINUTE = 60 * 1000
ONE_HOUR = 60 * ONE_MINUTE
ONE_DAY = 24 * ONE_HOUR
ONE_MONTH = 30 * ONE_DAY
ONE_YEAR = 12 * ONE_MONTH
# 全局参数配置
def edu_setting name
EduSetting.get(name)
end
# xss共计问题
def content_safe content
tags = %w(
a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl
dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark
ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td
tfoot th thead time tr u ul var wbr div span
)
attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style)
sanitize content, tags: tags, attributes: attributes
end
def graduation_navigation graduation
graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务"
end
def graduation_navigation_id course
course.course_modules.find_by(module_type: "graduation").try(:id)
end
# git用户
# git用户命名规则login+"@educoder.net"
def git_username(email)
User.find_by_mail(email) || User.find_by_login(email.split("@").first)
end
# 不同的类型扩展不同的目录
def relative_path
"avatars"
end
def replace_bytes_to_b(size_string)
return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B")
end
def storage_path
File.join(Rails.root, "public", "images", relative_path)
end
# 推荐实训
def recommend_shixun(shixun)
tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0
shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and
shixun_id != #{shixun.id}").pluck(:shixun_id)
shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",")
Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id
in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3)
end
# shixun开启挑战对应的行为名及url
def task_operation_url current_myshixun, shixun
if current_myshixun.blank?
name = shixun.status == 0 ? "模拟实战" : "开启挑战"
url = "/shixuns/#{shixun.identifier}/shixun_exec"
else
identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier)
if current_myshixun.status == 1
name = "查看实战"
else
name = "继续挑战"
end
url = identifier
end
[name, url]
end
# 获取当前时间
def time_from_now(time)
if String === time
time = Time.parse(time)
end
lastUpdateTime = time.to_i*1000
currentTime = Time.now.to_i*1000
timePassed = currentTime - lastUpdateTime
timeIntoFormat = 0
updateAtValue = ""
if timePassed < 0
updateAtValue = "刚刚"
elsif timePassed < ONE_MINUTE
updateAtValue = "1分钟前"
elsif timePassed < ONE_HOUR
timeIntoFormat = timePassed / ONE_MINUTE
updateAtValue = timeIntoFormat.to_s + "分钟前"
elsif (timePassed < ONE_DAY)
timeIntoFormat = (timePassed.to_f / ONE_HOUR).ceil
updateAtValue = timeIntoFormat.to_s + "小时前"
elsif (timePassed < ONE_MONTH)
timeIntoFormat = (timePassed.to_f / ONE_DAY).ceil
updateAtValue = timeIntoFormat.to_s + "天前"
elsif (timePassed < ONE_YEAR)
timeIntoFormat = (timePassed.to_f / ONE_MONTH).ceil
updateAtValue = timeIntoFormat.to_s + "个月前"
else
timeIntoFormat = timePassed / ONE_YEAR
updateAtValue = timeIntoFormat.to_s + "年前"
end
updateAtValue
end
# 计算到结束还有多长时间 **天**小时**分
def how_much_time(time)
if time.nil? || time < Time.now #6.21 -hs 增加小于time.now
''
else
result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + ""
result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 "
result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + ""
end
end
def format_time(time)
time.present? ? time.strftime("%Y-%m-%d %H:%M") : ''
end
# 用户图像url如果不存在的话source为匿名用户即默认使用匿名用户图像
def url_to_avatar(source)
if File.exist?(disk_filename(source&.class, source&.id))
ctime = File.ctime(disk_filename(source.class, source.id)).to_i
if %w(User Organization).include?(source.class.to_s)
File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
else
File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
end
elsif source.class.to_s == 'User'
source.get_letter_avatar_url
end
end
def url_to_avatar_with_platform_url(source)
platform_url = Rails.application.config_for(:configuration)['platform_url']
if platform_url
return Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(source).to_s
else
return url_to_avatar(source).to_s
end
end
# 主页banner图
def banner_img(source_type)
if File.exist?(disk_filename(source_type, "banner"))
ctime = File.ctime(disk_filename(source_type, "banner")).to_i
File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}"
end
end
def disk_filename(source_type,source_id,image_file=nil)
File.join(storage_path, "#{source_type}", "#{source_id}")
end
def disk_auth_filename(source_type, source_id, type)
File.join(storage_path, "#{source_type}", "#{source_id}#{type}")
end
def disk_real_name_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'ID')
end
def auth_file_url(source_type, source_id, type)
File.join('/images', relative_path, source_type, "#{source_id}#{type}")
end
def real_name_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'ID')
end
def disk_professional_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'PRO')
end
def professional_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'PRO')
end
def shixun_url_to_avatar(shixun)
if File.exist?(disk_filename(shixun.class, shixun.id))
File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}")
else
File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg")
end
end
# 选用实训的学校情况
def school_user_detail shixun
user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据
school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq
school_names = School.where(id: school_ids[0..1]).pluck(:name)
school_size = school_ids.size
str = school_size > 0 ? "#{school_names.join("")}#{school_size}" : "0所"
end
# 普通/分组 作业作品状态数组
def student_work_status homework, user_id, course, work
status = []
homework_setting = homework.homework_group_setting user_id, true
work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id)
late_time = homework.late_time || course.end_date
if course.is_end && work && work.work_status > 0
status << "查看作品"
elsif !course.is_end
if homework_setting.publish_time && homework_setting.publish_time < Time.now
# 作业未截止时
if homework_setting.end_time > Time.now
if homework.homework_type == "group" && homework.homework_detail_group.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "提交作品"
else
status << "修改作品"
end
else
if work.work_status == 0
status << "提交作品"
else
status << "修改作品"
end
end
# 补交阶段
elsif homework.allow_late && (late_time.nil? || late_time > Time.now)
if homework.homework_type == "group" && homework.homework_detail_group.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
else
if work.work_status == 0
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
end
# 匿评阶段
elsif work.work_status != 0
if homework.homework_detail_manual.comment_status == 3
work_ids = homework.student_works.has_committed.pluck(:id)
if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0
status << "匿评作品"
end
end
status << "查看作品"
end
end
end
end
def commit_des_status work, homework
status = []
homework_setting = homework.homework_group_setting work.user_id
# 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结
if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 &&
((homework_setting.end_time && homework_setting.end_time > Time.now) ||
(homework.allow_late && homework.late_time && homework.late_time > Time.now))
work.description.present? ? status << "修改总结" : status << "提交总结"
end
end
def download_url attachment,options={}
attachment_path(attachment,options)
end
# 耗时:天、小时、分、秒
# 小于1分钟则不显示
def game_spend_time time
day = time / 86400
hour = time % (24*60*60) / (60*60)
min = time % (24*60*60) % (60*60) / 60
sec = time % (24*60*60) % (60*60) % 60
if day < 1
if hour < 1
if min < 1
if sec < 1
time = "--"
else
time = "#{sec}"
end
else
time = "#{min}分钟 #{sec}"
end
else
time = "#{hour}小时 #{min}分钟 #{sec}"
end
else
time = "#{day}#{hour}小时 #{min}分钟 #{sec}"
end
return time
end
def absolute_path(file_path)
file_root_directory + File.join(edu_setting('attachment_folder'), file_path)
end
def file_root_directory
Rails.root.to_s
end
def file_storage_directory
file_root_directory + edu_setting('attachment_folder')
end
def local_path(file)
File.join(file.disk_directory, file.disk_filename)
end
def update_downloads(file)
file.update_attributes(:downloads => file.downloads + 1)
end
# 项目信息,
def project_info work, current_user, course_identity
project = work.project
if project
if project.status == 9
{id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count}
else
project_score = project.project_score
if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT
{id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count,
all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score,
attachment_score: project_score.attachment_score, message_score: project_score.message_score}
else
{id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count,
all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score,
attachment_score: project_score.attachment_score, message_score: project_score.message_score}
end
end
else
{id: -1, name: "--", title: "--"}
end
end
def message_content(content)
content = (strip_html content).strip
content = content.gsub(/\s+/, " ")
if content.gsub(" ", "") == ""
content = "[非文本消息]"
end
content
end
def strip_html(text, len=0, endss="...")
ss = ""
if !text.nil? && text.length>0
ss=text.gsub(/<\/?.*?>/, '').strip
ss = ss.gsub(/&nbsp;*/, '')
ss = ss.gsub(/\r\n/,'') #新增
ss = ss.gsub(/\n/,'') #新增
if len > 0 && ss.length > len
ss = ss[0, len] + endss
elsif len > 0 && ss.length <= len
ss = ss
#ss = truncate(ss, :length => len)
end
end
ss
end
def strip_export_title(content)
con_ = ""
if content.length > 0
con_ = strip_tags(content)
con_ = con_.gsub(/\r\n/,'').gsub(/&nbsp;*/, '').strip
end
con_
end
def pdf_load_sources(*arg)
arr = arg.map do |path|
content_tag(:script) do
File.open(Rails.root.join('public', path)).read.to_s.html_safe
end
end
raw arr.join('')
end
# 导出pdf时转化markdown为html
def to_markdown(text,origin_url)
return nil if text.blank?
options = {
:autolink => true,
:no_intra_emphasis => true,
:fenced_code_blocks => true,
:lax_html_blocks => true,
:strikethrough => true,
:superscript => false,
:tables => true
}
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
m_t = markdown.render(text)
m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t
end
def shixun_status_class(shixun)
case shixun.status
when 0 then 'text-info'
when 1 then 'text-warning'
when 2 then 'text-success'
when 3 then 'text-secondary'
end
end
def render_unix_time(date)
date.to_time.to_i
end
def find_user_by_login(login)
User.find_by_login login
end
def find_user_by_login_and_mail(login, mail)
User.find_by(login: login, mail: mail)
end
def find_user_by_gitea_uid(gitea_uid)
User.find_by(gitea_uid: gitea_uid)
end
def find_user_in_redis_cache(login, email)
$redis_cache.hgetall("v2-owner-common:#{login}-#{email}")
end
def find_user_in_redis_cache_by_id(id)
$redis_cache.hgetall("v2-owner-common:#{id}")
end
def render_base64_decoded(str)
return nil if str.blank?
Base64.decode64 str
end
def render_admin_statistics_item
url = Rails.application.config_for(:configuration)["admin_statistics_url"]
return if url.blank?
content_tag(:li) do
sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root')
end
end
# 1 手机类型0 邮箱类型
# 注意新版的login是自动名生成的
def phone_mail_type value
value =~ /^1\d{10}$/ ? 1 : 0
end
def strip(str)
str.to_s.strip.presence
end
end

View File

@ -11,7 +11,7 @@ module RepositoriesHelper
def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv)
default_type.include?(str&.downcase)
default_type.include?(str&.downcase) || str.blank?
end
def image_type?(str)
@ -22,7 +22,7 @@ module RepositoriesHelper
def is_readme?(type, str)
return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase)
readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end
def render_commit_author(author_json)
@ -36,7 +36,6 @@ module RepositoriesHelper
end
def render_cache_commit_author(author_json)
Rails.logger.info author_json['Email']
if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email'])
end
@ -45,36 +44,56 @@ module RepositoriesHelper
end
end
def readme_render_decode64_content(str, owner, repo, ref)
def readme_render_decode64_content(str, owner, repo, ref, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
src2_regex = /src='(.*?)'/
ss = content.to_s.scan(c_regex)
ss_src = content.to_s.scan(src_regex)
total_images = ss + ss_src
ss_src = content.scan(src_regex)
ss_src2 = content.scan(src2_regex)
total_images = ss + ss_src + ss_src2
if total_images.length > 0
total_images.each do |s|
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
if remove_title.length > 0
r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
begin
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
# if remove_title.length > 0
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# end
path_last = r_content
path_current = ""
# 相对路径处理
if r_content.start_with?("../")
relative_path_length = r_content.split("../").size - 1
path_pre = path.split("/").size - 1 - relative_path_length
path_pre = 0 if path_pre < 0
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_last = r_content.split("../").last
elsif r_content.start_with?("/") # 根路径处理
path_last = r_content[1..r_content.size]
else
path_current = path
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# new_r_content = "#{path}" + new_r_content
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{r_content}&ref=#{ref}"].join
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# new_r_content = "#{path}" + new_r_content
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
end
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
rescue
next
end
content = content.gsub(/#{r_content}/, new_r_content)
end
end
@ -84,6 +103,46 @@ module RepositoriesHelper
end
end
# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if image_type?(ext) || download_type(ext)
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}")
end
rescue
next
end
end
return content
rescue
return str
end
# unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
@ -94,10 +153,21 @@ module RepositoriesHelper
date.to_time.strftime("%Y-%m-%d %H:%M")
end
def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
readme_render_decode64_content(content, owner, repo, ref)
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
return Base64.decode64(content).force_encoding('UTF-8')
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)

View File

@ -0,0 +1,15 @@
class Admins::NewImportUserFromExcel < BaseImportXlsx
UserData = Struct.new(:login, :email, :password, :nickname)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
data = row.map(&method(:cell_value))[0..3]
block.call UserData.new(*data)
end
end
private
def cell_value(obj)
obj&.cell_value
end
end

View File

@ -13,7 +13,7 @@ module Gitea
end
def success?
@error.nil?
@error.nil? && @result[:status].to_s == "success"
end
def result

View File

@ -7,6 +7,8 @@ class CacheAsyncClearJob < ApplicationJob
Cache::V2::ProjectCommonService.new(id).clear
when "owner_common_service"
Cache::V2::OwnnerCommonService.new(id).clear
when "project_rank_service"
Cache::V2::ProjectRankService.new(id).clear
end
end
end

View File

@ -3,8 +3,7 @@ class DelayExpiredIssueJob < ApplicationJob
def perform
Issue.where(due_date: Date.today + 1.days).find_each do |issue|
SendTemplateMessageJob.perform_later('IssueAssignerExpire', issue.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueCreatorExpire', issue.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueExpire', issue.id) if Site.has_notice_menu?
end
end

View File

@ -24,13 +24,6 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueAssigned.get_email_message_content(receiver, operator, issue)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'IssueAssignerExpire'
issue_id = args[0]
issue = Issue.find_by_id(issue_id)
return unless issue.present?
receivers = User.where(id: issue&.assigned_to_id)
receivers_string, content, notification_url = MessageTemplate::IssueAssignerExpire.get_message_content(receivers, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
when 'IssueAtme'
receivers, operator_id, issue_id = args[0], args[1], args[2]
operator = User.find_by_id(operator_id)
@ -52,13 +45,17 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'IssueCreatorExpire'
when 'IssueExpire'
issue_id = args[0]
issue = Issue.find_by_id(issue_id)
return unless issue.present?
receivers = User.where(id: issue&.author_id)
receivers_string, content, notification_url = MessageTemplate::IssueCreatorExpire.get_message_content(receivers, issue)
receivers = User.where(id: [issue&.assigned_to_id, issue&.author_id])
receivers_string, content, notification_url = MessageTemplate::IssueExpire.get_message_content(receivers, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::IssueExpire.get_email_message_content(receiver, issue)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'IssueDeleted'
operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3]
operator = User.find_by_id(operator_id)
@ -94,6 +91,14 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectForked'
operator_id, project_id = args[0], args[1]
operator = User.find_by_id(operator_id)
project = Project.find_by_id(project_id)
return unless operator.present? && project.present?
receivers = project&.all_managers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::ProjectForked.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectIssue'
operator_id, issue_id = args[0], args[1]
operator = User.find_by_id(operator_id)
@ -163,6 +168,37 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberLeft.get_email_message_content(receiver, user, project)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectMilestoneCompleted'
milestone_id = args[0]
milestone = Version.find_by_id(milestone_id)
return unless milestone.present? && milestone&.project.present?
receivers = milestone&.project&.all_managers
receivers_string, content, notification_url = MessageTemplate::ProjectMilestoneCompleted.get_message_content(receivers, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestoneCompleted.get_email_message_content(receiver, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectMilestone'
milestone_id, operator_id = args[0], args[1]
milestone = Version.find_by_id(milestone_id)
operator = User.find_by_id(operator_id)
return unless milestone.present? && milestone&.project.present? && operator.present?
receivers = milestone&.project&.all_managers.where.not(id: operator_id)
receivers_string, content, notification_url = MessageTemplate::ProjectMilestone.get_message_content(receivers, operator, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id, operator_id: operator_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestone.get_email_message_content(receiver, operator, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectPraised'
operator_id, project_id = args[0], args[1]
operator = User.find_by_id(operator_id)
project = Project.find_by_id(project_id)
return unless operator.present? && project.present?
receivers = project&.all_managers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::ProjectPraised.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectPullRequest'
operator_id, pull_request_id = args[0], args[1]
operator = User.find_by_id(operator_id)
@ -290,6 +326,30 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::TeamLeft.get_email_message_content(receiver, organization, team)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'CompetitionBegin'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionBegin.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
when 'CompetitionReview'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionReview.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
when 'CompetitionResult'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionResult.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
end
end
end

View File

@ -1,7 +1,7 @@
module CustomRegexp
PHONE = /1\d{10}/
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
@ -11,5 +11,5 @@ module CustomRegexp
URL_REGEX = /\A(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\z/i
REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
MD_REGEX = /^.+(\.[m|M][d|D])$/
end

View File

@ -7,7 +7,7 @@ module Notice
config = Rails.application.config_for(:configuration).symbolize_keys!
notice_config = config[:notice].symbolize_keys!
raise 'notice config missing' if notice_config.blank?
rescue => exception
rescue => ex
raise ex if Rails.env.production?
puts %Q{\033[33m [warning] gitea config or configuration.yml missing,

21
app/libs/trace.rb Normal file
View File

@ -0,0 +1,21 @@
module Trace
class << self
def trace_config
trace_config = {}
begin
config = Rails.application.config_for(:configuration).symbolize_keys!
trace_config = config[:trace].symbolize_keys!
raise 'trace config missing' if trace_config.blank?
rescue => ex
raise ex if Rails.env.production?
puts %Q{\033[33m [warning] gitea config or configuration.yml missing,
please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
trace_config = {}
end
trace_config
end
end
end

View File

@ -5,10 +5,10 @@ class Ci::Repo < Ci::RemoteBase
has_one :perm, foreign_key: :perm_repo_uid
has_many :builds, foreign_key: :build_repo_id, dependent: :destroy
def self.find_with_namespace(namespace_path, identifier)
def self.find_with_namespace(namespace_path, identifier, user_login)
logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} "
user = Ci::User.find_by_user_login namespace_path
user_login = user_login || namespace_path
user = Ci::User.find_by(user_login: user_login)
repo = Ci::Repo.where(repo_namespace: namespace_path, repo_name: identifier).first
[user, repo]

View File

@ -5,7 +5,7 @@ module Matchable
scope :with_project_category, ->(category_id) { where(project_category_id: category_id) unless category_id.blank? }
scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? }
scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) }
scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "#{search.split(" ").join('|')}%") unless search.blank? }
scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "%#{search.split(" ").join('|')}%") unless search.blank? }
end
end

View File

@ -17,7 +17,7 @@
class ForkUser < ApplicationRecord
belongs_to :project
belongs_to :user
belongs_to :owner, class_name: 'Owner', foreign_key: :user_id
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic

View File

@ -76,7 +76,7 @@ class Issue < ApplicationRecord
scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)}
scope :closed, ->{where(status_id: 5)}
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
after_update :change_versions_count
after_save :change_versions_count, :send_update_message_to_notice_system
after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic
def incre_project_common
@ -171,11 +171,25 @@ class Issue < ApplicationRecord
end
def change_versions_count
if self.version.present? && self.saved_change_to_status_id?
if self.saved_change_to_fixed_version_id?
before_version = Version.find_by_id(self.fixed_version_id_before_last_save)
Rails.logger.info self.fixed_version_id_before_last_save
if before_version.present?
Rails.logger.info self.status_id
Rails.logger.info self.status_id_before_last_save
# 更改前状态为完成 或者 更改前后都为完成状态
if self.status_id_before_last_save == 5
percent = before_version.issues_count == 0 ? 0.0 : ((before_version.closed_issues_count - 1).to_f / before_version.issues_count)
before_version.update_attributes(closed_issues_count: (before_version.closed_issues_count - 1), percent: percent)
end
end
end
if self.version.present? && (self.saved_change_to_status_id? || self.saved_change_to_fixed_version_id?)
if self.status_id == 5
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count + 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count + 1), percent: percent)
elsif self.status_id_before_last_save == 5
elsif self.status_id_before_last_save == 5 && !self.saved_change_to_fixed_version_id?
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count - 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count - 1), percent: percent)
end
@ -183,7 +197,11 @@ class Issue < ApplicationRecord
end
def update_closed_issues_count_in_project!
self.project.decrement!(:closed_issues_count)
self.project.decrement!(:closed_issues_count) if self.status_id == 5
end
def send_update_message_to_notice_system
SendTemplateMessageJob.perform_later('IssueExpire', self.id) if Site.has_notice_menu? && self.due_date == Date.today + 1.days
end
end

View File

@ -6,7 +6,7 @@
# journalized_id :integer default("0"), not null
# journalized_type :string(30) default(""), not null
# user_id :integer default("0"), not null
# notes :text(65535)
# notes :text(4294967295)
# created_on :datetime not null
# private_notes :boolean default("0"), not null
# parent_id :integer

View File

@ -13,61 +13,72 @@
#
class MessageTemplate < ApplicationRecord
PLATFORM = 'GitLink'
def self.build_init_data
MessageTemplate::IssueAssignerExpire.destroy_all
MessageTemplate::IssueCreatorExpire.destroy_all
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修')
self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修")
self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在疑修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_changed.html")
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: "#{PLATFORM}: 疑修 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_expire.html")
self.create(type: 'MessageTemplate::IssueExpire', sys_notice: '疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: 疑修截止日期到达最后一天")
email_html = File.read("#{email_template_html_dir}/issue_deleted.html")
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将疑修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将疑修 <b>{title}</b> 删除', email: email_html, email_title: "#{PLATFORM}: 疑修 {title} 有状态变更", notification_url: '')
self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论疑修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::LoginIpTip', sys_notice: '您的账号{nickname}于{login_time)在非常用的IP地址{ip}登录,如非本人操作,请立即修改密码', notification_url: '')
email_html = File.read("#{email_template_html_dir}/organization_joined.html")
self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: 'GitLink: 你已加入 {organization} 组织')
self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: "#{PLATFORM}: 你已加入 {organization} 组织")
email_html = File.read("#{email_template_html_dir}/organization_left.html")
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织')
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: "#{PLATFORM}: 你已被移出 {organization} 组织")
self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '')
self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '<b>{nickname}</b> 关注了你管理的仓库', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库 <b>{nickname2}/{repository}</b> 到 <b>{nickname1}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_issue.html")
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个疑修')
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 新建了一个疑修")
email_html = File.read("#{email_template_html_dir}/project_joined.html")
self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: 你已加入 {repository} 项目')
self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: "#{PLATFORM}: 你已加入 {repository} 项目")
email_html = File.read("#{email_template_html_dir}/project_left.html")
self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 <b>{repository}</b> 项目', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {repository} 项目')
self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 <b>{repository}</b> 项目', notification_url: '', email: email_html, email_title: "#{PLATFORM}: 你已被移出 {repository} 项目")
email_html = File.read("#{email_template_html_dir}/project_member_joined.html")
self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已加入项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 已加入项目 {nickname2}/{repository}")
email_html = File.read("#{email_template_html_dir}/project_member_left.html")
self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已被移出项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}')
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname}</b> 点赞了你管理的仓库', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 已被移出项目 {nickname2}/{repository}")
email_html = File.read("#{email_template_html_dir}/project_milestone.html")
self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{name}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 新建了一个里程碑")
email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html")
self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 <b>{nickname}/{repository}</b> 仓库,里程碑 <b>{name}</b> 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成")
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname1}</b> 点赞了你管理的仓库 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求')
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求")
email_html = File.read("#{email_template_html_dir}/project_role.html")
self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 <b>{nickname}/{repository}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: 'GitLink: 在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}')
self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 <b>{nickname}/{repository}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: '#{PLATFORM}: 在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_setting_changed.html")
self.create(type: 'MessageTemplate::ProjectSettingChanged', sys_notice: '{nickname1}更改了 <b>{nickname2}/{repository}</b> 仓库设置:{ifname}更改项目名称为"<b>{name}</b>"{endname}{ifidentifier}更改项目标识为"<b>{identifier}</b>"{endidentifier}{ifdescription}更改项目简介为"<b>{description}</b>"{enddescription}{ifcategory}更改项目类别为"<b>{category}</b>"{endcategory}{iflanguage}更改项目语言为"<b>{language}</b>"{endlanguage}{ifpermission}将仓库设为"<b>{permission}</b>"{endpermission}{ifnavbar}将项目导航更改为"<b>{navbar}</b>"{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: 'GitLink: 您管理的仓库 {nickname2}/{repository} 仓库设置已被更改')
self.create(type: 'MessageTemplate::ProjectSettingChanged', sys_notice: '{nickname1}更改了 <b>{nickname2}/{repository}</b> 仓库设置:{ifname}更改项目名称为"<b>{name}</b>"{endname}{ifidentifier}更改项目标识为"<b>{identifier}</b>"{endidentifier}{ifdescription}更改项目简介为"<b>{description}</b>"{enddescription}{ifcategory}更改项目类别为"<b>{category}</b>"{endcategory}{iflanguage}更改项目语言为"<b>{language}</b>"{endlanguage}{ifpermission}将仓库设为"<b>{permission}</b>"{endpermission}{ifnavbar}将项目导航更改为"<b>{navbar}</b>"{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: "#{PLATFORM}: 您管理的仓库 {nickname2}/{repository} 仓库设置已被更改")
self.create(type: 'MessageTemplate::ProjectTransfer', sys_notice: '你关注的仓库{nickname1}/{repository1}已被转移至{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
self.create(type: 'MessageTemplate::ProjectVersion', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了发行版:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/releases')
email_html = File.read("#{email_template_html_dir}/pull_request_assigned.html")
self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个合并请求:<b>{title}<b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求')
self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个合并请求:<b>{title}<b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求")
self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '<b>{nickname}</b> 在合并请求 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_changed.html")
self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 <b>{title}</b> 中:{ifassigner}{nickname1}将审查成员从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 <b>{title}</b> 中:{ifassigner}{nickname1}将审查成员从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}', email: email_html, email_title: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_closed.html")
self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} <b>被拒绝</b>', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} <b>被拒绝</b>', email: email_html, email_title: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '')
self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_merged.html")
self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/team_joined.html")
self.create(type: 'MessageTemplate::TeamJoined', sys_notice: '你已被拉入组织 <b>{organization}</b> 的 <b>{team}</b> 团队,拥有<b>{role}</b>权限', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::TeamJoined', sys_notice: '你已被拉入组织 <b>{organization}</b> 的 <b>{team}</b> 团队,拥有<b>{role}</b>权限', email: email_html, email_title: "#{PLATFORM}: 在 {organization} 组织你的账号有权限变更", notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/team_left.html")
self.create(type: 'MessageTemplate::TeamLeft', sys_notice: '你已被移出组织 <b>{organization}</b> 的 <b>{team}</b> 团队', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::TeamLeft', sys_notice: '你已被移出组织 <b>{organization}</b> 的 <b>{team}</b> 团队', email: email_html, email_title: "#{PLATFORM}: 在 {organization} 组织你的账号有权限变更", notification_url: '{baseurl}/{login}')
# 竞赛通知
self.create(type: 'MessageTemplate::CompetitionBegin', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 已进入比赛进行阶段,可在此期间提交作品', notification_url: '{to_url}')
self.create(type: 'MessageTemplate::CompetitionResult', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 已进入成绩公示阶段,可查看排行榜信息', notification_url: '{to_url}')
self.create(type: 'MessageTemplate::CompetitionReview', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交', notification_url: '{to_url}')
end
def self.sys_notice

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛进入比赛进行阶段
# 触发场景
# 赛队成员报名的竞赛已进入比赛进行阶段
# 通知文案格式
# 你报名的竞赛 xxx 已进入比赛进行阶段,可在此阶段提交作品
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 已进入比赛进行阶段,可在此期间提交作品
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionBegin < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.to_s.gsub('{competition_name}', competition&.name), notification_url.to_s.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
# rescue
# return '', '', ''
end
end

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛进入成绩公示阶段
# 触发场景
# 赛队成员报名的竞赛已进入成绩公示阶段
# 通知文案格式
# 你报名的竞赛 xxx 已进入成绩公示阶段,可查看排行榜信息
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 已进入成绩公示阶段,可查看排行榜信息
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionResult < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
rescue
return '', '', ''
end
end

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛比赛结束时间临近
# 触发场景
# 赛队成员报名的竞赛阶段处于比赛进行中且距比赛结束日期仅剩3天
# 通知文案格式
# 你报名的竞赛 xxx 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionReview < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
rescue
return '', '', ''
end
end

View File

@ -53,6 +53,7 @@ class MessageTemplate::IssueAssigned < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue&.subject)
content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -359,6 +359,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifduedate})(.*)({endduedate})/, '')
end
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -1,29 +1,3 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我创建的疑修截止日期到达最后一天
class MessageTemplate::IssueCreatorExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
def self.get_message_content(receivers, issue)
project = issue&.project
owner = project&.owner
content = sys_notice.gsub('{title}', issue&.subject)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::IssueAssignerExpire.get_message_content [ERROR] #{e}")
return '', '', ''
end
end
end

View File

@ -41,6 +41,7 @@ class MessageTemplate::IssueDeleted < MessageTemplate
content.gsub!('{login}', operator&.login)
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue_title)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -0,0 +1,67 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我创建或负责的疑修截止日期到达最后一天
class MessageTemplate::IssueExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
def self.get_message_content(receivers, issue)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueExpire"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["CreateOrAssign::IssueExpire"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
project = issue&.project
owner = project&.owner
content = sys_notice.gsub('{title}', issue&.subject)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, issue)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["CreateOrAssign::IssueExpire"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["CreateOrAssign::IssueExpire"] : send_setting
return '', '', '' unless send_setting
project = issue&.project
owner = project&.owner
title = email_title
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{repository}', project&.name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue&.subject)
content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -41,6 +41,7 @@ class MessageTemplate::OrganizationJoined < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -41,6 +41,7 @@ class MessageTemplate::OrganizationLeft < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -43,6 +43,7 @@ class MessageTemplate::OrganizationRole < MessageTemplate
content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{role}', role)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -12,11 +12,21 @@
# email_title :string(255)
#
# TODO 我管理的仓库被复刻
# 我管理的仓库被复刻
class MessageTemplate::ProjectForked < MessageTemplate
# MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers)
def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Forked"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Forked"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{owner}', user&.login).gsub('{identifier}', project&.identifier)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}")

View File

@ -56,6 +56,7 @@ class MessageTemplate::ProjectIssue < MessageTemplate
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{title}', issue&.subject)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -44,6 +44,7 @@ class MessageTemplate::ProjectJoined < MessageTemplate
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{nickname}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -43,6 +43,7 @@ class MessageTemplate::ProjectLeft < MessageTemplate
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{nickname}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -48,6 +48,7 @@ class MessageTemplate::ProjectMemberJoined < MessageTemplate
content.gsub!('{nickname1}', user&.real_name)
content.gsub!('{nickname2}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -48,6 +48,7 @@ class MessageTemplate::ProjectMemberLeft < MessageTemplate
content.gsub!('{nickname1}', user&.real_name)
content.gsub!('{nickname2}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -12,14 +12,61 @@
# email_title :string(255)
#
# TODO 我管理的仓库有新的里程碑
# 我管理的仓库有新的里程碑
class MessageTemplate::ProjectMilestone < MessageTemplate
# MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers)
def self.get_message_content(receivers, operator, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Milestone"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Milestone"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Milestone"]
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, operator, milestone)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["ManageProject::Milestone"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::Milestone"] : send_setting
return '', '', '' unless send_setting
project = milestone&.project
owner = project&.owner
title = email_title
title.gsub!('{nickname1}', operator&.real_name)
title.gsub!('{nickname2}', owner&.real_name)
title.gsub!('{repository}', project&.name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{nickname1}', operator&.real_name)
content.gsub!('{nickname2}', owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -0,0 +1,70 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我管理的仓库有里程碑完成
class MessageTemplate::ProjectMilestoneCompleted < MessageTemplate
# MessageTemplate::ProjectMilestoneCompleted.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::MilestoneCompleted"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::MilestoneCompleted"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, milestone)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["ManageProject::MilestoneCompleted"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::MilestoneCompleted"] : send_setting
return '', '', '' unless send_setting
project = milestone&.project
owner = project&.owner
title = email_title
title.gsub!('{nickname}', owner&.real_name)
title.gsub!('{repository}', project&.name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -12,11 +12,21 @@
# email_title :string(255)
#
# TODO 我管理的仓库被点赞
# 我管理的仓库被点赞
class MessageTemplate::ProjectPraised < MessageTemplate
# MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers)
def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Praised"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Praised"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{login}', user&.login)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}")

View File

@ -56,6 +56,7 @@ class MessageTemplate::ProjectPullRequest < MessageTemplate
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{title}', pull_request&.title)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -46,6 +46,7 @@ class MessageTemplate::ProjectRole < MessageTemplate
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{repository}', project&.name)
content.gsub!('{role}', role)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -141,6 +141,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
navbar.gsub!('devops', '工作流')
navbar.gsub!('versions', '里程碑')
navbar.gsub!('resources', '资源库')
navbar.gsub!('services', '服务')
if change_count > 1
content.sub!('{ifnavbar}', '<br/>')
else
@ -290,6 +291,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
navbar.gsub!('devops', '工作流')
navbar.gsub!('versions', '里程碑')
navbar.gsub!('resources', '资源库')
navbar.gsub!('services', '服务')
if change_count > 1
content.sub!('{ifnavbar}', '<br/>')
else
@ -300,6 +302,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
else
content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
end
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -53,6 +53,7 @@ class MessageTemplate::PullRequestAssigned < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -118,6 +118,7 @@ class MessageTemplate::PullRequestChanged < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
change_count = change_params.keys.size
# 合并请求审查成员修改

View File

@ -51,6 +51,7 @@ class MessageTemplate::PullRequestClosed < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -51,6 +51,7 @@ class MessageTemplate::PullRequestMerged < MessageTemplate
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -45,6 +45,7 @@ class MessageTemplate::TeamJoined < MessageTemplate
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -45,6 +45,7 @@ class MessageTemplate::TeamLeft < MessageTemplate
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else

View File

@ -83,6 +83,10 @@ class Organization < Owner
after_save :reset_cache_data
def gitea_token
team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user&.gitea_token
end
def reset_cache_data
Cache::V2::OwnerCommonService.new(self.id).reset
end

View File

@ -124,9 +124,10 @@ class Project < ApplicationRecord
has_many :pinned_projects, dependent: :destroy
has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
has_many :user_trace_tasks, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members, :reset_cache_data
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned
after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
before_destroy :decre_project_common, :decre_forked_from_project_count
after_destroy :decre_user_statistic, :decre_platform_statistic
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
@ -150,7 +151,7 @@ class Project < ApplicationRecord
end
def reset_cache_data
CacheAsyncResetJob.perform_later("project_common_service", self.id)
CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id)
if changes[:user_id].present?
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first)
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last)
@ -163,6 +164,14 @@ class Project < ApplicationRecord
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1})
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1})
end
if changes[:is_public].present?
if changes[:is_public][0] && !changes[:is_public][1]
CacheAsyncClearJob.perform_later('project_rank_service', self.id)
end
if !changes[:is_public][0] && changes[:is_public][1]
$redis_cache.srem("v2-project-rank-deleted", self.id)
end
end
end
def decre_project_common

View File

@ -16,7 +16,7 @@
class ProjectUnit < ApplicationRecord
belongs_to :project
enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7}
enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7, services: 8}
validates :unit_type, uniqueness: { scope: :project_id}

View File

@ -3,8 +3,8 @@
# Table name: pull_requests
#
# id :integer not null, primary key
# pull_request_id :integer
# gpid :integer
# gitea_id :integer
# gitea_number :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
@ -12,7 +12,7 @@
# project_id :integer
# title :string(255)
# milestone :integer
# body :text(65535)
# body :text(4294967295)
# head :string(255)
# base :string(255)
# issue_id :integer

View File

@ -15,7 +15,7 @@ class Site < ApplicationRecord
# add: 添加类链接
# personal: 个人名下类链接,
# common: 普通链接
enum site_type: { add: 0, personal: 1, common: 2 }
enum site_type: { add: 0, personal: 1, common: 2, competition: 3 }
scope :by_search, -> (keyword){ where("name LIKE :keyword OR url LIKE :keyword", keyword: "%#{strip_param(keyword)}%") unless strip_param(keyword).blank? }
scope :by_site_type, -> (site_type){ where(site_type: strip_param(site_type)) unless strip_param(site_type).blank? }

View File

@ -29,6 +29,11 @@ class Team < ApplicationRecord
has_many :team_units, dependent: :destroy
has_many :team_users, dependent: :destroy
scope :like, lambda { |keywords|
sql = "teams.nickname LIKE :search OR teams.name LIKE :search"
where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
}
validates :name, uniqueness: {scope: :organization_id}
enum authorize: {read: 1, write: 2, admin: 3, owner: 4}

View File

@ -29,7 +29,7 @@ class TeamUser < ApplicationRecord
before_destroy :remove_project_member
def self.build(organization_id, user_id, team_id)
self.create!(organization_id: organization_id, user_id: user_id, team_id: team_id)
self.find_or_create_by!(organization_id: organization_id, user_id: user_id, team_id: team_id)
end
def remove_project_member

View File

@ -22,6 +22,7 @@ class TemplateMessageSetting < ApplicationRecord
end
def self.build_init_data
TemplateMessageSetting.destroy_all
TemplateMessageSetting::CreateOrAssign.build_init_data
TemplateMessageSetting::ManageProject.build_init_data
TemplateMessageSetting::Normal.build_init_data

View File

@ -27,5 +27,6 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting
def self.build_init_data
self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged")
self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged")
self.find_or_create_by(name: "疑修截止日期到达最后一天", key: "IssueExpire", notification_disabled: false)
end
end

View File

@ -29,5 +29,9 @@ class TemplateMessageSetting::ManageProject < TemplateMessageSetting
self.find_or_create_by(name: "有新的合并请求", key: "PullRequest")
self.find_or_create_by(name: "有成员变动", key: "Member")
self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged")
self.find_or_create_by(name: "被点赞", key: "Praised", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "被fork", key: "Forked", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "有新的里程碑", key: "Milestone", notification_disabled: false)
self.find_or_create_by(name: "有里程碑已完成", key: "MilestoneCompleted", notification_disabled: false)
end
end

View File

@ -35,6 +35,8 @@ class Topic < ApplicationRecord
'Topic::ExcellentProject'
when 'experience_forum'
'Topic::ExperienceForum'
when "glcc_news"
'Topic::GlccNews'
when 'pinned_forum'
'Topic::PinnedForum'
end

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