diff --git a/.gitignore b/.gitignore
index 6b4fd25c1..19dfa07fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,6 +74,7 @@ vendor/bundle/
/log
/public/admin
/mysql_data
+/public/repo/
.generators
@@ -85,3 +86,4 @@ redis_data/
Dockerfile
dump.rdb
.tags*
+ceshi_user.xlsx
\ No newline at end of file
diff --git a/.merge_file_a17580 b/.merge_file_a17580
deleted file mode 100644
index 47e471767..000000000
--- a/.merge_file_a17580
+++ /dev/null
@@ -1,529 +0,0 @@
-import React, {Component} from 'react';
-import logo from './logo.svg';
-import './App.css';
-import {LocaleProvider} from 'antd'
-import zhCN from 'antd/lib/locale-provider/zh_CN';
-import {
- BrowserRouter as Router,
- Route,
- Switch
-} from 'react-router-dom';
-import axios from 'axios';
-import '@icedesign/base/dist/ICEDesignBase.css';
-
-import '@icedesign/base/index.scss';
-
-import LoginDialog from './modules/login/LoginDialog';
-import Notcompletedysl from './modules/user/Notcompletedysl';
-import Trialapplicationysl from './modules/login/Trialapplicationysl';
-import Trialapplicationreview from './modules/user/Trialapplicationreview';
-import Addcourses from "./modules/courses/coursesPublic/Addcourses";
-import AccountProfile from"./modules/user/AccountProfile";
-
-
-import Trialapplication from './modules/login/Trialapplication'
-
-import NotFoundPage from './NotFoundPage'
-
-import Loading from './Loading'
-
-import Loadable from 'react-loadable';
-
-
-import moment from 'moment'
-
-import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
-
-// import './AppConfig'
-
-import history from './history';
-
-import {SnackbarHOC} from 'educoder'
-import {initAxiosInterceptors} from './AppConfig'
-
-
-// !!!tpi需要这个来加载css
-import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC';
-
-
-const theme = createMuiTheme({
- palette: {
- primary: {
- main: '#4CACFF',
- contrastText: 'rgba(255, 255, 255, 0.87)'
- },
- secondary: {main: '#4CACFF'}, // #11cb5f This is just green.A700 as hex.
- },
-});
-//
-// const Trialapplication= Loadable({
-// loader: () =>import('./modules/login/Trialapplication'),
-// loading:Loading,
-// })
-//登入
-const EducoderLogin = Loadable({
- loader: () => import('./modules/login/EducoderLogin'),
- loading: Loading,
-})
-const TestIndex = Loadable({
- loader: () => import('./modules/test'),
- loading: Loading,
-})
-
-const IndexWrapperComponent = Loadable({
- loader: () => import('./modules/page/IndexWrapper'),
- loading: Loading,
-})
-
-const CommentComponent = Loadable({
- loader: () => import('./modules/comment/CommentContainer'),
- loading: Loading,
-})
-
-const TestMaterialDesignComponent = Loadable({
- loader: () => import('./modules/test/md/TestMaterialDesign'),
- loading: Loading,
-})
-const TestCodeMirrorComponent = Loadable({
- loader: () => import('./modules/test/codemirror/TestCodeMirror'),
- loading: Loading,
-})
-
-const TestComponent = Loadable({
- loader: () => import('./modules/test/TestRC'),
- loading: Loading,
-})
-const TestUrlQueryComponent = Loadable({
- loader: () => import('./modules/test/urlquery/TestUrlQuery'),
- loading: Loading,
-})
-
-const TPMIndexComponent = Loadable({
- loader: () => import('./modules/tpm/TPMIndex'),
- loading: Loading,
-})
-const TPMShixunsIndexComponent = Loadable({
- loader: () => import('./modules/tpm/shixuns/ShixunsIndex'),
- loading: Loading,
-})
-
-//实训课程(原实训路径)
-const ShixunPaths = Loadable({
- loader: () => import('./modules/paths/Index'),
- loading: Loading,
-})
-
-//在线课堂
-const CoursesIndex = Loadable({
- loader: () => import('./modules/courses/Index'),
- loading: Loading,
-})
-const SearchPage = Loadable({
- loader: () => import('./search/SearchPage'),
- loading: Loading,
-})
-
-//教学案例
-const MoopCases = Loadable({
- loader: () => import('./modules/moop_cases/index'),
- loading: Loading,
-})
-
-// 课堂讨论
-// const BoardIndex = Loadable({
-// loader: () => import('./modules/courses/boards/BoardIndex'),
-// loading:Loading,
-// })
-
-// //课堂普通作业&分组作业
-// const CoursesWorkIndex = Loadable({
-// loader: () => import('./modules/courses/busyWork/Index'),
-// loading:Loading,
-// })
-//
-
-// const TPMShixunchildIndexComponent = Loadable({
-// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
-// loading: Loading,
-// })
-
-
-// const TPMshixunfork_listIndexComponent = Loadable({
-// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
-// loading: Loading,
-// })
-
-
-const ForumsIndexComponent = Loadable({
- loader: () => import('./modules/forums/ForumsIndex'),
- loading: Loading,
-})
-
-// trustie plus forum
-// const TPForumsIndexComponent = Loadable({
-// loader: () => import('./modules/tp-forums/TPForumsIndex'),
-// loading: Loading,
-// })
-
-
-// const TestPageComponent = Loadable({
-// loader: () => import('./modules/page/Index'),
-// loading: Loading,
-// })
-
-
-//新建实训
-const Newshixuns = Loadable({
- loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
- loading: Loading,
-})
-
-
-//实训首页
-const ShixunsHome = Loadable({
- loader: () => import('./modules/home/shixunsHome'),
- loading: Loading,
-})
-
-
-const CompatibilityPageLoadable = Loadable({
- loader: () => import('./modules/common/CompatibilityPage'),
- loading: Loading,
-})
-
-//403页面
-const Shixunauthority = Loadable({
- loader: () => import('./modules/403/Shixunauthority'),
- loading: Loading,
-})
-
-
-//404页面
-const Shixunnopage = Loadable({
- loader: () => import('./modules/404/Shixunnopage'),
- loading: Loading,
-})
-
-//500页面
-const http500 = Loadable({
- loader: () => import('./modules/500/http500'),
- loading: Loading,
-})
-
-// 登录注册
-const LoginRegisterPage = Loadable({
- loader: () => import('./modules/user/LoginRegisterPage'),
- loading: Loading,
-})
-const AccountPage = Loadable({
- loader: () => import('./modules/user/AccountPage'),
- loading: Loading,
-})
-
-// 个人主页
-const UsersInfo = Loadable({
- loader: () => import('./modules/user/usersInfo/Infos'),
- loading: Loading,
-})
-
-// 兴趣页面
-const Interestpage = Loadable({
- loader: () => import('./modules/login/EducoderInteresse'),
- loading: Loading,
-})
-
-//众包创新
-const ProjectPackages=Loadable({
- loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
- loading: Loading,
-})
-
-class App extends Component {
- constructor(props) {
- super(props)
- // this.state = {
- // isRenders:false,
- // }
-
- }
-
- componentDidMount() {
- // force an update if the URL changes
- history.listen(() => {
- this.forceUpdate()
- const $ = window.$
- // https://www.trustie.net/issues/21919 可能会有问题
- $("html").animate({ scrollTop: $('html').scrollTop() - 0 })
- });
-
- initAxiosInterceptors(this.props)
-
- //
- // axios.interceptors.response.use((response) => {
- // // console.log("response"+response);
- // if(response!=undefined)
- // // console.log("response"+response.data.statu);
- // if (response&&response.data.status === 407) {
- // this.setState({
- // isRenders: true,
- // })
- // }
- // return response;
- // }, (error) => {
- // //TODO 这里如果样式变了会出现css不加载的情况
- // });
- }
- //修改登录方法
- Modifyloginvalue=()=>{
- this.setState({
- isRender:false,
- })
- }
-
- render() {
-
-
- return (
-
-
-
-
- this.Modifyloginvalue()}>
-
-
-
-
-
- {/*{*/}
- {/* isRender === true?*/}
- {/* : ""*/}
- {/*}*/}
-
- {/*{*/}
- {/* isRenders === true?*/}
- {/* */}
- {/*:""*/}
- {/*}*/}
-
-
-
- {/**/}
-
- {/*众包创新*/}
-
- {/*认证*/}
-
-
- {/*403*/}
-
-
-
-
- {/*404*/}
-
-
-
-
-
- ( )
- }>
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
- {/*列表页*/}
-
-
- {/*
-
-
- */}
-
- {/**/}
- {/* */}
-
-
- {/*实训课程(原实训路径)*/}
-
-
- ( )
- }
- >
-
- {/*课堂*/}
-
-
- {/* 课堂讨论 */}
- {/* */}
-
- {/*
- */}
-
- {/* */}
- {/* 兴趣页面*/}
- {/**/}
-
-
-
-
-
-
-
-
- {/* 教学案例 */}
- ( )
- }/>
-
- {/* */}
- {/*列表页*/}
- {/**/}
- {/*首页*/}
-
-
-
- {/**/}
-
-
-
-
-
- );
- }
-}
-
-// moment国际化,设置为中文
-moment.defineLocale('zh-cn', {
- months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
- monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
- weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
- weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
- weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
- longDateFormat: {
- LT: 'Ah点mm分',
- LTS: 'Ah点m分s秒',
- L: 'YYYY-MM-DD',
- LL: 'YYYY年MMMD日',
- LLL: 'YYYY年MMMD日Ah点mm分',
- LLLL: 'YYYY年MMMD日ddddAh点mm分',
- l: 'YYYY-MM-DD',
- ll: 'YYYY年MMMD日',
- lll: 'YYYY年MMMD日Ah点mm分',
- llll: 'YYYY年MMMD日ddddAh点mm分'
- },
- meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
- meridiemHour: function (hour, meridiem) {
- if (hour === 12) {
- hour = 0;
- }
- if (meridiem === '凌晨' || meridiem === '早上' ||
- meridiem === '上午') {
- return hour;
- } else if (meridiem === '下午' || meridiem === '晚上') {
- return hour + 12;
- } else {
- // '中午'
- return hour >= 11 ? hour : hour + 12;
- }
- },
- meridiem: function (hour, minute, isLower) {
- var hm = hour * 100 + minute;
- if (hm < 600) {
- return '凌晨';
- } else if (hm < 900) {
- return '早上';
- } else if (hm < 1130) {
- return '上午';
- } else if (hm < 1230) {
- return '中午';
- } else if (hm < 1800) {
- return '下午';
- } else {
- return '晚上';
- }
- },
- calendar: {
- sameDay: function () {
- return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
- },
- nextDay: function () {
- return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
- },
- lastDay: function () {
- return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
- },
- nextWeek: function () {
- var startOfWeek, prefix;
- startOfWeek = moment().startOf('week');
- prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]';
- return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
- },
- lastWeek: function () {
- var startOfWeek, prefix;
- startOfWeek = moment().startOf('week');
- prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]';
- return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
- },
- sameElse: 'LL'
- },
- ordinalParse: /\d{1,2}(日|月|周)/,
- ordinal: function (number, period) {
- switch (period) {
- case 'd':
- case 'D':
- case 'DDD':
- return number + '日';
- case 'M':
- return number + '月';
- case 'w':
- case 'W':
- return number + '周';
- default:
- return number;
- }
- },
- relativeTime: {
- future: '%s内',
- past: '%s前',
- s: '几秒',
- m: '1分钟',
- mm: '%d分钟',
- h: '1小时',
- hh: '%d小时',
- d: '1天',
- dd: '%d天',
- M: '1个月',
- MM: '%d个月',
- y: '1年',
- yy: '%d年'
- },
- week: {
- // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
- dow: 1, // Monday is the first day of the week.
- doy: 4 // The week that contains Jan 4th is the first week of the year.
- }
-});
-export default SnackbarHOC()(App);
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5250040e..ecb743b91 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,35 @@
# Changelog
+## [v3.2.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-06-09
+
+### ENHANCEMENTS
+ * ADD 集成邮件和平台站内信等通知系统
+ * Fix 代码库二级页面-优化文件子目录浏览功能(#50388)
+ * Fix 代码库二级页面-优化commit提交详情页页面排版及数据显示(#50372)
+ * Fix 代码库二级页面-优化commit提交信息列表页加载方式和数据排序功能(#50348)
+ * Fix 代码库二级页面-优化创建发行版功能(#50346)
+ * Fix 代码库二级页面-优化标签列表页功能(#50344)
+ * Fix 代码库二级页面-优化发行版本列表页功能(#50345)
+ * Fix 代码库二级页面-优化分支列表页功能(#50343)
+ * Fix 其他问题优化(#51581) (#51343) (#51108)
+
+---
+
+### BUGFIXES
+ * Fix 发行版—标签跳转链接错误(#51666)
+ * Fix 文件预览报错(#51660)
+ * Fix 标签创建时间显示错误(#51658)
+ * Fix 分支列表中头像显示问题(#51656)
+ * Fix 文本信息过长(#51630) (#51626)
+ * Fix 版本库中附件下载400(#51625)
+ * Fix loading页面优化(#51588)
+ * Fix 提交详情页面优化(#51577)
+ * Fix 修复易修复制功能(#51569)
+ * Fix 修复新建发行版用户信息显示错误的问题(#51665)
+ * Fix 修复查看文件详细信息报错的问题(#51561)
+ * Fix 修复提交记录中时间显示格式问题(#51526)
+ * Fix 组织下项目更加更新时间倒序排序(#50833)
+
+
## [v3.1.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-06-09
* ENHANCEMENTS
diff --git a/api_document.md b/api_document.md
index 7620c42a6..a43147bb2 100644
--- a/api_document.md
+++ b/api_document.md
@@ -51,6 +51,51 @@ http://localhost:3000/api/accounts/remote_register | jq
|-- token |string|用户token|
+返回值
+```json
+{
+ "status": 0,
+ "message": "success",
+ "user": {
+ "id": 36400,
+ "token": "8c87a80d9cfacc92fcb2451845104f35119eda96"
+ }
+}
+```
+---
+
+#### 独立注册接口
+```
+POST accounts/register
+```
+*示例*
+```bash
+curl -X POST \
+-d "login=2456233122@qq.com" \
+-d "password=djs_D_00001" \
+-d "namespace=16895620" \
+-d "code=forge" \
+http://localhost:3000/api/accounts/remote_register | jq
+```
+*请求参数说明:*
+
+|参数名|必选|类型|说明|
+|-|-|-|-|
+|login |是|string |邮箱或者手机号 |
+|namespace |是|string |登录名 |
+|password |是|string |密码 |
+|code |是|string |验证码 |
+
+
+*返回参数说明:*
+
+|参数名|类型|说明|
+|-|-|-|
+|user|json object |返回数据|
+|-- id |int |用户id |
+|-- token |string|用户token|
+
+
返回值
```json
{
@@ -338,10 +383,10 @@ http://localhost:3000/api/projects/ | jq
|-|-|-|-|
|user_id |是|int |用户id或者组织id |
|name |是|string |项目名称 |
-|description |是|string |项目描述 |
+|description |否|string |项目描述 |
|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
-|project_category_id|是|int |项目类别id |
-|project_language_id|是|int |项目语言id |
+|project_category_id|否|int |项目类别id |
+|project_language_id|否|int |项目语言id |
|ignore_id |否|int |gitignore相关id |
|license_id |否|int |开源许可证id |
|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 |
@@ -374,9 +419,7 @@ curl -X POST \
-d "user_id=36408" \
-d "clone_addr=https://gitea.com/mx8090alex/golden.git" \
-d "name=golden_mirror1" \
--d "description=golden_mirror" \
--d "project_category_id=1" \
--d "project_language_id=2" \
+-d "repository_name=golden_mirror1" \
http://localhost:3000/api/projects/migrate.json | jq
```
*请求参数说明:*
@@ -388,8 +431,8 @@ http://localhost:3000/api/projects/migrate.json | jq
|clone_addr |是|string |镜像项目clone地址 |
|description |否|string |项目描述 |
|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
-|project_category_id|是|int |项目类别id |
-|project_language_id|是|int |项目语言id |
+|project_category_id|否|int |项目类别id |
+|project_language_id|否|int |项目语言id |
|is_mirror |否|boolean|是否设置为镜像, true:是, false:否,默认为否 |
|auth_username |否|string|镜像源仓库的登录用户名 |
|auth_password |否|string|镜像源仓库的登录秘密 |
diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png
index 436d23490..72505d8a2 100644
Binary files a/app/assets/images/logo.png and b/app/assets/images/logo.png differ
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index 0cab04359..d738e5caa 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -99,3 +99,38 @@ $(document).on("turbolinks:before-cache", function () {
$(function () {
});
+
+$(document).on('turbolinks:load', function() {
+
+ $('.logo-item-left').on("change", 'input[type="file"]', function () {
+ var $fileInput = $(this);
+ var file = this.files[0];
+ var imageType = /image.*/;
+ if (file && file.type.match(imageType)) {
+ var reader = new FileReader();
+ reader.onload = function () {
+ var $box = $fileInput.parent();
+ $box.find('img').attr('src', reader.result).css('display', 'block');
+ $box.addClass('has-img');
+ };
+ reader.readAsDataURL(file);
+ } else {
+ }
+ });
+
+ $('.attachment-item-left').on("change", 'input[type="file"]', function () {
+ var $fileInput = $(this);
+ var file = this.files[0];
+ var imageType = /image.*/;
+ if (file && file.type.match(imageType)) {
+ var reader = new FileReader();
+ reader.onload = function () {
+ var $box = $fileInput.parent();
+ $box.find('img').attr('src', reader.result).css('display', 'block');
+ $box.addClass('has-img');
+ };
+ reader.readAsDataURL(file);
+ } else {
+ }
+ });
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/courses/index.js b/app/assets/javascripts/admins/courses/index.js
index 0e3473dff..82867e3e0 100644
--- a/app/assets/javascripts/admins/courses/index.js
+++ b/app/assets/javascripts/admins/courses/index.js
@@ -1,7 +1,7 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-courses-index-page').length > 0) {
- let searchContainer = $(".course-list-form");
- let searchForm = $("form.search-form",searchContainer);
+ var searchContainer = $(".course-list-form");
+ var searchForm = $("form.search-form",searchContainer);
searchContainer.on('change', '.course-homepage-show', function(){
searchForm.find('input[type="submit"]').trigger('click');
diff --git a/app/assets/javascripts/admins/projects/index.js b/app/assets/javascripts/admins/projects/index.js
new file mode 100644
index 000000000..dbf710ea5
--- /dev/null
+++ b/app/assets/javascripts/admins/projects/index.js
@@ -0,0 +1,141 @@
+/*
+ * @Description: Do not edit
+ * @Date: 2021-08-31 11:16:45
+ * @LastEditors: viletyy
+ * @Author: viletyy
+ * @LastEditTime: 2021-08-31 14:19:46
+ * @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
+ */
+$(document).on('turbolinks:load', function(){
+
+ var showSuccessNotify = function() {
+ $.notify({
+ message: '操作成功'
+ },{
+ type: 'success'
+ });
+ }
+
+ // close user
+ $('.project-list-container').on('click', '.recommend-action', function(){
+ var $closeAction = $(this);
+ var $uncloseAction = $closeAction.siblings('.unrecommend-action');
+ var $editAction = $closeAction.siblings('.edit-recommend-action');
+
+ var keywordID = $closeAction.data('id');
+ customConfirm({
+ content: '确认将该项目设置为推荐项目吗?',
+ ok: function(){
+ $.ajax({
+ url: '/admins/projects/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ project: {
+ recommend: true,
+ recommend_index: 1
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.hide();
+ $uncloseAction.show();
+ $editAction.show();
+ $(".project-item-"+keywordID).children('td').eq(5).text("√")
+ }
+ });
+ }
+ });
+ });
+
+ // unclose user
+ $('.project-list-container').on('click', '.unrecommend-action', function(){
+ var $uncloseAction = $(this);
+ var $closeAction = $uncloseAction.siblings('.recommend-action');
+ var $editAction = $closeAction.siblings('.edit-recommend-action');
+
+ var keywordID = $uncloseAction.data('id');
+ customConfirm({
+ content: '确认取消该推荐项目吗?',
+ ok: function () {
+ $.ajax({
+ url: '/admins/projects/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ project: {
+ recommend: false,
+ recommend_index: 0
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.show();
+ $uncloseAction.hide();
+ $editAction.hide();
+ $(".project-item-"+keywordID).children('td').eq(5).text("")
+ }
+ });
+ }
+ })
+ });
+
+
+ // close user
+ $('.project-list-container').on('click', '.pinned-action', function(){
+ var $closeAction = $(this);
+ var $uncloseAction = $closeAction.siblings('.unpinned-action');
+
+ var keywordID = $closeAction.data('id');
+ customConfirm({
+ content: '确认将该项目设置为精选项目吗?',
+ ok: function(){
+ $.ajax({
+ url: '/admins/projects/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ project: {
+ is_pinned: true,
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.hide();
+ $uncloseAction.show();
+ $(".project-item-"+keywordID).children('td').eq(4).text("√")
+ }
+ });
+ }
+ });
+ });
+
+ // unclose user
+ $('.project-list-container').on('click', '.unpinned-action', function(){
+ var $uncloseAction = $(this);
+ var $closeAction = $uncloseAction.siblings('.pinned-action');
+
+ var keywordID = $uncloseAction.data('id');
+ customConfirm({
+ content: '确认取消该精选项目吗?',
+ ok: function () {
+ $.ajax({
+ url: '/admins/projects/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ project: {
+ is_pinned: false,
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.show();
+ $uncloseAction.hide();
+ $(".project-item-"+keywordID).children('td').eq(4).text("")
+ }
+ });
+ }
+ })
+ });
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/reversed_keywords/index.js b/app/assets/javascripts/admins/reversed_keywords/index.js
new file mode 100644
index 000000000..df14219d2
--- /dev/null
+++ b/app/assets/javascripts/admins/reversed_keywords/index.js
@@ -0,0 +1,76 @@
+/*
+ * @Description: Do not edit
+ * @Date: 2021-08-31 11:16:45
+ * @LastEditors: viletyy
+ * @Author: viletyy
+ * @LastEditTime: 2021-08-31 14:19:46
+ * @FilePath: /forgeplus/app/assets/javascripts/admins/reversed_keywords/index.js
+ */
+$(document).on('turbolinks:load', function(){
+
+ var showSuccessNotify = function() {
+ $.notify({
+ message: '操作成功'
+ },{
+ type: 'success'
+ });
+ }
+
+ // close user
+ $('.reversed-keyword-list-container').on('click', '.close-action', function(){
+ var $closeAction = $(this);
+ var $uncloseAction = $closeAction.siblings('.unclose-action');
+
+ var keywordID = $closeAction.data('id');
+ customConfirm({
+ content: '确认关闭限制吗?',
+ ok: function(){
+ $.ajax({
+ url: '/admins/reversed_keywords/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ reversed_keyword: {
+ closed: true
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.hide();
+ $uncloseAction.show();
+ $(".reversed-keyword-item-"+keywordID).children('td').eq(3).text("")
+ }
+ });
+ }
+ });
+ });
+
+ // unclose user
+ $('.reversed-keyword-list-container').on('click', '.unclose-action', function(){
+ var $uncloseAction = $(this);
+ var $closeAction = $uncloseAction.siblings('.close-action');
+
+ var keywordID = $uncloseAction.data('id');
+ customConfirm({
+ content: '确认开启限制吗?',
+ ok: function () {
+ $.ajax({
+ url: '/admins/reversed_keywords/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ reversed_keyword: {
+ closed: false
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.show();
+ $uncloseAction.hide();
+ $(".reversed-keyword-item-"+keywordID).children('td').eq(3).text("√")
+ }
+ });
+ }
+ })
+ });
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/shixun_settings/index.js b/app/assets/javascripts/admins/shixun_settings/index.js
index cd3445c62..06b0f37e4 100644
--- a/app/assets/javascripts/admins/shixun_settings/index.js
+++ b/app/assets/javascripts/admins/shixun_settings/index.js
@@ -1,7 +1,15 @@
+/*
+ * @Description: Do not edit
+ * @Date: 2021-07-16 11:58:16
+ * @LastEditors: viletyy
+ * @Author: viletyy
+ * @LastEditTime: 2021-08-31 14:48:59
+ * @FilePath: /forgeplus/app/assets/javascripts/admins/shixun_settings/index.js
+ */
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
- let searchContainer = $(".shixun-settings-list-form");
- let searchForm = $("form.search-form",searchContainer);
+ var searchContainer = $(".shixun-settings-list-form");
+ var searchForm = $("form.search-form",searchContainer);
searchContainer.on('change', '.shixun-settings-select', function(){
searchForm.find('input[type="submit"]').trigger('click');
diff --git a/app/assets/javascripts/admins/system_notifications/index.js b/app/assets/javascripts/admins/system_notifications/index.js
new file mode 100644
index 000000000..90809b344
--- /dev/null
+++ b/app/assets/javascripts/admins/system_notifications/index.js
@@ -0,0 +1,76 @@
+/*
+ * @Description: Do not edit
+ * @Date: 2021-08-31 11:16:45
+ * @LastEditors: viletyy
+ * @Author: viletyy
+ * @LastEditTime: 2021-08-31 14:19:46
+ * @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
+ */
+$(document).on('turbolinks:load', function(){
+
+ var showSuccessNotify = function() {
+ $.notify({
+ message: '操作成功'
+ },{
+ type: 'success'
+ });
+ }
+
+ // close user
+ $('.system-notification-list-container').on('click', '.close-action', function(){
+ var $closeAction = $(this);
+ var $uncloseAction = $closeAction.siblings('.unclose-action');
+
+ var keywordID = $closeAction.data('id');
+ customConfirm({
+ content: '确认取消置顶吗?',
+ ok: function(){
+ $.ajax({
+ url: '/admins/system_notifications/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ system_notification: {
+ is_top: false
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.hide();
+ $uncloseAction.show();
+ $(".system-notification-item-"+keywordID).children('td').eq(3).text("")
+ }
+ });
+ }
+ });
+ });
+
+ // unclose user
+ $('.system-notification-list-container').on('click', '.unclose-action', function(){
+ var $uncloseAction = $(this);
+ var $closeAction = $uncloseAction.siblings('.close-action');
+
+ var keywordID = $uncloseAction.data('id');
+ customConfirm({
+ content: '确认置顶吗?',
+ ok: function () {
+ $.ajax({
+ url: '/admins/system_notifications/' + keywordID,
+ method: 'PUT',
+ dataType: 'json',
+ data: {
+ system_notification: {
+ is_top: true
+ }
+ },
+ success: function() {
+ showSuccessNotify();
+ $closeAction.show();
+ $uncloseAction.hide();
+ $(".system-notification-item-"+keywordID).children('td').eq(3).text("√")
+ }
+ });
+ }
+ })
+ });
+})
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index a401fc379..03c3970a6 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -58,3 +58,149 @@ input.form-control {
position: absolute;
}
+.logo-item {
+ display: flex;
+
+ &-img {
+ display: block;
+ width: 80px;
+ height: 80px;
+ background: #e9ecef;
+ }
+
+ &-upload {
+ cursor: pointer;
+ position: absolute;
+ top: 0;
+ width: 80px;
+ height: 80px;
+ background: #e9ecef;
+ border: 1px solid #ced4da;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 27px;
+ left: 39px;
+ width: 2px;
+ height: 26px;
+ background: #495057;
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 39px;
+ left: 27px;
+ width: 26px;
+ height: 2px;
+ background: #495057;
+ }
+ }
+
+ &-left {
+ position: relative;
+ width: 80px;
+ height: 80px;
+
+ &.has-img {
+ .logo-item-upload {
+ display: none;
+ }
+
+ &:hover {
+ .logo-item-upload {
+ display: block;
+ background: rgba(145, 145, 145, 0.8);
+ }
+ }
+ }
+ }
+
+ &-right {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ color: #777777;
+ font-size: 0.8rem;
+ }
+
+ &-title {
+ color: #23272B;
+ font-size: 1rem;
+ }
+}
+
+.attachment-item {
+ display: flex;
+
+ &-img {
+ display: block;
+ width: 160px;
+ height: 160px;
+ background: #e9ecef;
+ }
+
+ &-upload {
+ cursor: pointer;
+ position: absolute;
+ top: 0;
+ width: 160px;
+ height: 160px;
+ background: #e9ecef;
+ border: 1px solid #ced4da;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 54px;
+ left: 78px;
+ width: 2px;
+ height: 52px;
+ background: #495057;
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 78px;
+ left: 54px;
+ width: 52px;
+ height: 2px;
+ background: #495057;
+ }
+ }
+
+ &-left {
+ position: relative;
+ width: 160px;
+ height: 160px;
+
+ &.has-img {
+ .attachment-item-upload {
+ display: none;
+ }
+
+ &:hover {
+ .attachment-item-upload {
+ display: block;
+ background: rgba(145, 145, 145, 0.8);
+ }
+ }
+ }
+ }
+
+ &-right {
+ padding-top: 100px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ color: #777777;
+ font-size: 0.8rem;
+ }
+
+ &-title {
+ color: #23272B;
+ font-size: 1rem;
+ }
+}
\ No newline at end of file
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 0745726b9..b8783c44e 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -1,4 +1,5 @@
class AccountsController < ApplicationController
+ include ApplicationHelper
#skip_before_action :check_account, :only => [:logout]
@@ -9,6 +10,7 @@ class AccountsController < ApplicationController
# 其他平台同步注册的用户
def remote_register
username = params[:username]&.gsub(/\s+/, "")
+ tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
email = params[:email]&.gsub(/\s+/, "")
password = params[:password]
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
@@ -108,60 +110,46 @@ class AccountsController < ApplicationController
# 用户注册
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
# params[:login] 邮箱或者手机号
+ # params[:namespace] 登录名
# params[:code] 验证码
# code_type 1:注册手机验证码 8:邮箱注册验证码
- # 本地forge注册入口
+ # 本地forge注册入口需要重新更改逻辑
def register
+ # type只可能是1或者8
+ user = nil
begin
- # 查询验证码是否正确;type只可能是1或者8
- type = phone_mail_type(params[:login].strip)
- # code = params[:code].strip
+ Register::Form.new(register_params).validate!
- if type == 1
- uid_logger("start register by phone: type is #{type}")
- pre = 'p'
- email = nil
- phone = params[:login]
- # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
- # TODO: 暂时限定邮箱注册
- return normal_status(-1, '只支持邮箱注册')
- else
- uid_logger("start register by email: type is #{type}")
- pre = 'm'
- email = params[:login]
- phone = nil
- return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login])
- return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL
- # verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
- end
- # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
- # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
- # todo 上线前请删除万能验证码"513231"
- return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD
+ user = Users::RegisterService.call(register_params)
+ password = register_params[:password].strip
- code = generate_identifier User, 8, pre
- login = pre + code
- @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User")
- @user.password = params[:password]
- # 现在因为是验证码,所以在注册的时候就可以激活
- @user.activate
- # 必须要用save操作,密码的保存是在users中
-
- interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]})
+ # gitea用户注册, email, username, password
+ interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
if interactor.success?
gitea_user = interactor.result
- result = Gitea::User::GenerateTokenService.new(login, params[:password]).call
- @user.gitea_token = result['sha1']
- @user.gitea_uid = gitea_user[:body]['id']
- if @user.save!
- UserExtension.create!(user_id: @user.id)
- successful_authentication(@user)
- normal_status("注册成功")
+ result = Gitea::User::GenerateTokenService.call(user.login, password)
+ user.gitea_token = result['sha1']
+ user.gitea_uid = gitea_user[:body]['id']
+ if user.save!
+ UserExtension.create!(user_id: user.id)
+ successful_authentication(user)
+ render_ok
end
else
tip_exception(-1, interactor.error)
end
+ rescue Register::BaseForm::EmailError => e
+ render_error(-2, e.message)
+ rescue Register::BaseForm::LoginError => e
+ render_error(-3, e.message)
+ rescue Register::BaseForm::PhoneError => e
+ render_error(-4, e.message)
+ rescue Register::BaseForm::PasswordFormatError => e
+ render_error(-5, e.message)
+ rescue Register::BaseForm::VerifiCodeError => e
+ render_error(-6, e.message)
rescue Exception => e
+ Gitea::User::DeleteService.call(user.login) unless user.nil?
uid_logger_error(e.message)
tip_exception(-1, e.message)
end
@@ -296,7 +284,7 @@ class AccountsController < ApplicationController
# 发送验证码
# params[:login] 手机号或者邮箱号
- # params[:type]为事件通知类型 1:用户注册注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
+ # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱
# 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效
def get_verification_code
@@ -310,19 +298,22 @@ class AccountsController < ApplicationController
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
tip_exception(501, "请求不合理") if sign != params[:smscode]
+ logger.info "########### 验证码:#{verification_code}"
logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ")
# 记录验证码
check_verification_code(verification_code, send_type, value)
- sucess_status
+ render_ok
end
- # 1 手机类型;0 邮箱类型
- # 注意新版的login是自动名生成的
- def phone_mail_type value
- value =~ /^1\d{10}$/ ? 1 : 0
+ # check user's login or email or phone is used
+ # params[:value] 手机号或者邮箱号或者登录名
+ # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号)
+ def check
+ Register::CheckColumnsForm.new(check_params).validate!
+ render_ok
end
-
+
private
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
@@ -368,4 +359,13 @@ class AccountsController < ApplicationController
def account_params
params.require(:account).permit(:login, :password)
end
+
+ def check_params
+ params.permit(:type, :value)
+ end
+
+ def register_params
+ params.permit(:login, :namespace, :password, :code)
+ end
+
end
diff --git a/app/controllers/admins/edu_settings_controller.rb b/app/controllers/admins/edu_settings_controller.rb
new file mode 100644
index 000000000..9d9334b23
--- /dev/null
+++ b/app/controllers/admins/edu_settings_controller.rb
@@ -0,0 +1,55 @@
+class Admins::EduSettingsController < Admins::BaseController
+ before_action :find_setting, only: [:edit,:update, :destroy]
+
+ def index
+ default_sort('id', 'desc')
+
+ edu_settings = Admins::EduSettingQuery.call(params)
+ @edu_settings = paginate edu_settings
+ end
+
+ def new
+ @edu_setting = EduSetting.new
+ end
+
+ def edit
+ end
+
+ def create
+ @edu_setting = EduSetting.new(edu_setting_params)
+ if @edu_setting.save
+ redirect_to admins_edu_settings_path
+ flash[:success] = '创建成功'
+ else
+ redirect_to admins_edu_settings_path
+ flash[:danger] = @edu_setting.errors.full_messages.join(",")
+ end
+ end
+
+ def update
+ if @edu_setting.update!(edu_setting_params)
+ flash[:success] = '更新成功'
+ else
+ flash[:danger] = @edu_setting.errors.full_messages.join(",")
+ end
+ redirect_to admins_edu_settings_path
+ end
+
+ def destroy
+ if @edu_setting.destroy!
+ flash[:success] = '删除成功'
+ else
+ lash[:danger] = '删除失败'
+ end
+ redirect_to admins_edu_settings_path
+ end
+
+ private
+ def find_setting
+ @edu_setting ||= EduSetting.find(params[:id])
+ end
+
+ def edu_setting_params
+ params.require(:edu_setting).permit(:name, :value, :description)
+ end
+end
diff --git a/app/controllers/admins/message_templates_controller.rb b/app/controllers/admins/message_templates_controller.rb
new file mode 100644
index 000000000..23c94e784
--- /dev/null
+++ b/app/controllers/admins/message_templates_controller.rb
@@ -0,0 +1,44 @@
+class Admins::MessageTemplatesController < Admins::BaseController
+ before_action :get_template, only: [:edit, :update, :destroy]
+
+ def index
+ message_templates = MessageTemplate.group(:type).count.keys
+ @message_templates = kaminari_array_paginate(message_templates)
+ end
+
+ def edit
+ end
+
+ def update
+ if @message_template.update_attributes(message_template_params)
+ redirect_to admins_message_templates_path
+ flash[:success] = '消息模版更新成功'
+ else
+ redirect_to admins_message_templates_path
+ flash[:danger] = @message_template.errors.full_messages.join(",")
+ end
+ end
+
+ def init_data
+ if MessageTemplate.build_init_data
+ redirect_to admins_message_templates_path
+ flash[:success] = '消息模版初始化成功'
+ else
+ redirect_to admins_message_templates_path
+ flash[:danger] = '消息模版初始化失败'
+ end
+ end
+
+ private
+ def message_template_params
+ params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
+ end
+
+ def get_template
+ @message_template = MessageTemplate.find_by(id: params[:id])
+ unless @message_template.present?
+ redirect_to admins_message_templates_path
+ flash[:danger] = "消息模版不存在"
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/project_categories_controller.rb b/app/controllers/admins/project_categories_controller.rb
index ba83e841d..72cb833fa 100644
--- a/app/controllers/admins/project_categories_controller.rb
+++ b/app/controllers/admins/project_categories_controller.rb
@@ -22,7 +22,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
max_position_items = ProjectCategory.select(:id, :position).pluck(:position).reject!(&:blank?)
max_position = max_position_items.present? ? max_position_items.max.to_i : 0
- @project_category = ProjectCategory.new(name: @name,position: max_position)
+ @project_category = ProjectCategory.new(name: @name,position: max_position, pinned_index: params[:project_category][:pinned_index].to_i)
if @project_category.save
redirect_to admins_project_categories_path
flash[:success] = '创建成功'
@@ -33,17 +33,18 @@ class Admins::ProjectCategoriesController < Admins::BaseController
end
def update
- if @project_category.update_attribute(:name, @name)
+ if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i})
+ save_image_file(params[:logo], 'logo')
redirect_to admins_project_categories_path
flash[:success] = '更新成功'
else
redirect_to admins_project_categories_path
- flash[:success] = '更新失败'
+ flash[:danger] = '更新失败'
end
end
def destroy
- if @project_language.destroy
+ if @project_category.destroy
redirect_to admins_project_categories_path
flash[:success] = "删除成功"
else
@@ -80,4 +81,12 @@ class Admins::ProjectCategoriesController < Admins::BaseController
flash[:danger] = '分类已存在'
end
end
+
+ def save_image_file(file, type)
+ return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
+
+ file_path = Util::FileManage.source_disk_filename(@project_category, type)
+ File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
+ Util.write_file(file, file_path)
+ end
end
\ No newline at end of file
diff --git a/app/controllers/admins/projects_controller.rb b/app/controllers/admins/projects_controller.rb
index 9e06eb1c9..4175f7250 100644
--- a/app/controllers/admins/projects_controller.rb
+++ b/app/controllers/admins/projects_controller.rb
@@ -1,4 +1,5 @@
class Admins::ProjectsController < Admins::BaseController
+ before_action :find_project, only: [:edit, :update]
def index
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
@@ -8,6 +9,26 @@ class Admins::ProjectsController < Admins::BaseController
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
end
+ def edit ;end
+
+ def update
+ respond_to do |format|
+ if @project.update_attributes(project_update_params)
+ format.html do
+ redirect_to admins_projects_path
+ flash[:sucess] = "更新成功"
+ end
+ format.js {render_ok}
+ else
+ format.html do
+ redirect_to admins_projects_path
+ flash[:danger] = "更新失败"
+ end
+ format.js {render_js_error}
+ end
+ end
+ end
+
def destroy
project = Project.find_by!(id: params[:id])
ActiveRecord::Base.transaction do
@@ -21,4 +42,13 @@ class Admins::ProjectsController < Admins::BaseController
redirect_to admins_projects_path
flash[:danger] = "删除失败"
end
+
+ private
+ def find_project
+ @project = Project.find_by_id(params[:id])
+ end
+
+ def project_update_params
+ params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
+ end
end
\ No newline at end of file
diff --git a/app/controllers/admins/reversed_keywords_controller.rb b/app/controllers/admins/reversed_keywords_controller.rb
new file mode 100644
index 000000000..8a8442f72
--- /dev/null
+++ b/app/controllers/admins/reversed_keywords_controller.rb
@@ -0,0 +1,84 @@
+class Admins::ReversedKeywordsController < Admins::BaseController
+ before_action :get_keyword, only: [:edit,:update, :destroy]
+ # before_action :validate_identifer, only: [:create, :update]
+
+ def index
+ sort_by = ReversedKeyword.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
+ sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
+ q = ReversedKeyword.ransack(identifier_cont: params[:search])
+ keywords = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
+ @keywords = paginate(keywords)
+
+ end
+
+ def new
+ @keyword = ReversedKeyword.new
+ end
+
+ def edit
+ end
+
+ def create
+ @keyword = ReversedKeyword.new(keyword_params)
+ if @keyword.save
+ redirect_to admins_reversed_keywords_path
+ flash[:success] = '系统保留关键词创建成功'
+ else
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = @keyword.errors.full_messages.join(",")
+ end
+ end
+
+ def update
+
+ respond_to do |format|
+ if @keyword.update_attributes(keyword_params)
+ format.html do
+ redirect_to admins_reversed_keywords_path
+ flash[:success] = '系统保留关键词更新成功'
+ end
+ format.js {render_ok}
+ else
+ format.html do
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = @keyword.errors.full_messages.join(",")
+ end
+ format.js {render_js_error}
+ end
+ end
+ end
+
+ def destroy
+ if @keyword.destroy
+ redirect_to admins_reversed_keywords_path
+ flash[:success] = "系统保留关键词删除成功"
+ else
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = "系统保留关键词删除失败"
+ end
+ end
+
+ private
+ def keyword_params
+ params.require(:reversed_keyword).permit!
+ end
+
+ def get_keyword
+ @keyword = ReversedKeyword.find_by(id: params[:id])
+ unless @keyword.present?
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = "系统保留关键词不存在"
+ end
+ end
+
+ def validate_identifer
+ identifer = keyword_params[:identifier].to_s.downcase
+ if identifer.blank?
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = '系统保留关键词标识不能为空'
+ elsif ProjectLanguage.exists?(name: identifer)
+ redirect_to admins_reversed_keywords_path
+ flash[:danger] = '系统保留关键词已存在'
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/sites_controller.rb b/app/controllers/admins/sites_controller.rb
new file mode 100644
index 000000000..f3da4ccf2
--- /dev/null
+++ b/app/controllers/admins/sites_controller.rb
@@ -0,0 +1,56 @@
+class Admins::SitesController < Admins::BaseController
+ before_action :find_site, only: [:edit,:update, :destroy]
+
+ def index
+ default_sort('id', 'desc')
+
+ sites = Admins::SiteQuery.call(params)
+ @sites = paginate sites
+ end
+
+ def new
+ @site = Site.new
+ end
+
+ def edit
+ end
+
+ def create
+ @site = Site.new(site_params)
+ if @site.save
+ redirect_to admins_sites_path
+ flash[:success] = '创建成功'
+ else
+ redirect_to admins_sites_path
+ flash[:danger] = @site.errors.full_messages.join(",")
+ end
+ end
+
+ def update
+ if @site.update!(site_params)
+ flash[:success] = '更新成功'
+ else
+ flash[:danger] = @site.errors.full_messages.join(",")
+ end
+ redirect_to admins_sites_path
+ end
+
+ def destroy
+ if @site.destroy!
+ flash[:success] = '删除成功'
+ else
+ lash[:danger] = '删除失败'
+ end
+ redirect_to admins_sites_path
+ end
+
+ private
+ def find_site
+ @site ||= Site.find(params[:id])
+ end
+
+ def site_params
+ params.require(:site).permit(:name, :url, :key, :site_type)
+ end
+
+end
diff --git a/app/controllers/admins/system_notifications_controller.rb b/app/controllers/admins/system_notifications_controller.rb
new file mode 100644
index 000000000..e2081f1a2
--- /dev/null
+++ b/app/controllers/admins/system_notifications_controller.rb
@@ -0,0 +1,75 @@
+class Admins::SystemNotificationsController < Admins::BaseController
+ before_action :get_notification, only: [:history, :edit,:update, :destroy]
+ # before_action :validate_identifer, only: [:create, :update]
+
+ def index
+ sort_by = SystemNotification.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
+ sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
+ q = SystemNotification.ransack(subject_cont: params[:search])
+ notifications = q.result(distinct: true).reorder("#{sort_by} #{sort_direction},created_at desc")
+ @notifications = paginate(notifications)
+ end
+
+ def history
+ @users = @notification.users
+ end
+
+ def new
+ @notification = SystemNotification.new
+ end
+
+ def edit
+ end
+
+ def create
+ @notification = SystemNotification.new(notification_params)
+ if @notification.save
+ redirect_to admins_system_notifications_path
+ flash[:success] = '系统消息创建成功'
+ else
+ redirect_to admins_system_notifications_path
+ flash[:danger] = @notification.errors.full_messages.join(",")
+ end
+ end
+
+ def update
+ respond_to do |format|
+ if @notification.update_attributes(notification_params)
+ format.html do
+ redirect_to admins_system_notifications_path
+ flash[:success] = '系统消息更新成功'
+ end
+ format.js {render_ok}
+ else
+ format.html do
+ redirect_to admins_system_notifications_path
+ flash[:danger] = @notification.errors.full_messages.join(",")
+ end
+ format.js {render_js_error}
+ end
+ end
+ end
+
+ def destroy
+ if @notification.destroy
+ redirect_to admins_system_notifications_path
+ flash[:success] = "系统消息删除成功"
+ else
+ redirect_to admins_system_notifications_path
+ flash[:danger] = "系统消息删除失败"
+ end
+ end
+
+ private
+ def notification_params
+ params.require(:system_notification).permit!
+ end
+
+ def get_notification
+ @notification = SystemNotification.find_by(id: params[:id])
+ unless @notification.present?
+ redirect_to admins_system_notifications_path
+ flash[:danger] = "系统消息不存在"
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/users_controller.rb b/app/controllers/admins/users_controller.rb
index 98f0a6bfb..07ea8261e 100644
--- a/app/controllers/admins/users_controller.rb
+++ b/app/controllers/admins/users_controller.rb
@@ -1,4 +1,6 @@
class Admins::UsersController < Admins::BaseController
+ before_action :finder_user, except: [:index]
+
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
@@ -8,12 +10,9 @@ class Admins::UsersController < Admins::BaseController
end
def edit
- @user = User.find(params[:id])
end
def update
- @user = User.find(params[:id])
-
Admins::UpdateUserService.call(@user, update_params)
flash[:success] = '保存成功'
redirect_to edit_admins_user_path(@user)
@@ -26,43 +25,47 @@ class Admins::UsersController < Admins::BaseController
end
def destroy
- User.find(params[:id]).destroy!
+ @user.destroy!
+ Gitea::User::DeleteService.call(@user.login)
render_delete_success
end
def lock
- User.find(params[:id]).lock!
+ @user.lock!
render_ok
end
def unlock
- User.find(params[:id]).activate!
+ @user.activate!
render_ok
end
def reward_grade
- user = User.find(params[:user_id])
return render_unprocessable_entity('金币数量必须大于0') if params[:grade].to_i <= 0
- RewardGradeService.call(user, container_id: user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
+ RewardGradeService.call(@user, container_id: @user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
- render_ok(grade: user.grade)
+ render_ok(grade: @user.grade)
end
def reset_login_times
- User.find(params[:id]).reset_login_times!
+ @user.reset_login_times!
render_ok
end
private
+ def finder_user
+ @user = User.find(params[:id])
+ end
+
def update_params
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
mail phone location location_city school_id department_id admin business is_test
- password professional_certification authentication])
+ password professional_certification authentication login])
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8b98a920b..d7707391f 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -70,49 +70,11 @@ class ApplicationController < ActionController::Base
(current_user.professional_certification && (ue.teacher? || ue.professional?))
end
- def shixun_marker
- unless current_user.is_shixun_marker? || current_user.admin_or_business?
- tip_exception(403, "..")
- end
- end
-
- # 实训的访问权限
- def shixun_access_allowed
- if !current_user.shixun_permission(@shixun)
- tip_exception(403, "..")
- end
- end
def admin_or_business?
User.current.admin? || User.current.business?
end
- # 访问课堂时没权限直接弹加入课堂的弹框 :409
- def user_course_identity
- @user_course_identity = current_user.course_identity(@course)
- if @user_course_identity > Course::STUDENT && @course.is_public == 0
- tip_exception(401, "..") unless User.current.logged?
- check_account
- tip_exception(@course.excellent ? 410 : 409, "您没有权限进入")
- end
- if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id
- # 实名认证和职业认证的身份判断
- tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication &&
- @course.professional_certification && (!current_user.authentication && !current_user.professional_certification)
- tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication
- tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification
- end
- uid_logger("###############user_course_identity:#{@user_course_identity}")
- end
-
- # 题库的访问权限
- def bank_visit_auth
- tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public
- tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? ||
- (current_user.certification_teacher? && @bank.is_public)
- end
-
-
# 判断用户的邮箱或者手机是否可用
# params[:type] 1: 注册;2:忘记密码;3:绑定
def check_mail_and_phone_valid login, type
@@ -120,16 +82,16 @@ class ApplicationController < ActionController::Base
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
tip_exception(-2, "请输入正确的手机号或邮箱")
end
- # 考虑到安全参数问题,多一次查询,去掉Union
- user = User.where(phone: login).first || User.where(mail: login).first
- if type.to_i == 1 && !user.nil?
+
+ user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
+ if user_exist && type.to_i == 1
tip_exception(-2, "该手机号码或邮箱已被注册")
- elsif type.to_i == 2 && user.nil?
+ elsif type.to_i == 2 && !user_exist
tip_exception(-2, "该手机号码或邮箱未注册")
- elsif type.to_i == 3 && user.present?
+ elsif type.to_i == 3 && user_exist
tip_exception(-2, "该手机号码或邮箱已绑定")
end
- sucess_status
+ render_ok
end
# 发送及记录激活码
@@ -140,7 +102,7 @@ class ApplicationController < ActionController::Base
when 1, 2, 4, 9
# 手机类型的发送
sigle_para = {phone: value}
- status = Educoder::Sms.send(mobile: value, code: code)
+ status = Gitlink::Sms.send(mobile: value, code: code)
tip_exception(-2, code_msg(status)) if status != 0
when 8, 3, 5
# 邮箱类型的发送
@@ -186,26 +148,6 @@ class ApplicationController < ActionController::Base
end
end
- def find_course
- return normal_status(2, '缺少course_id参数!') if params[:course_id].blank?
- @course = Course.find(params[:course_id])
- tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
- rescue Exception => e
- tip_exception(e.message)
- end
-
- def course_manager
- return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR
- end
-
- def find_board
- return normal_status(2, "缺少board_id参数") if params[:board_id].blank?
- @board = Board.find(params[:board_id])
- rescue Exception => e
- uid_logger_error(e.message)
- tip_exception(e.message)
- end
-
def validate_type(object_type)
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
end
@@ -215,21 +157,6 @@ class ApplicationController < ActionController::Base
@page_size = params[:page_size] || 15
end
- # 课堂教师权限
- def teacher_allowed
- logger.info("#####identity: #{current_user.course_identity(@course)}")
- unless current_user.course_identity(@course) < Course::STUDENT
- normal_status(403, "")
- end
- end
-
- # 课堂教师、课堂管理员、超级管理员的权限(不包含助教)
- def teacher_or_admin_allowed
- unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR
- normal_status(403, "")
- end
- end
-
def require_admin
normal_status(403, "") unless User.current.admin?
end
@@ -246,9 +173,17 @@ class ApplicationController < ActionController::Base
tip_exception(401, "请登录后再操作") unless User.current.logged?
end
+ def require_profile_completed
+ tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
+ end
+
+ def require_user_profile_completed(user)
+ tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
+ end
+
# 异常提醒
def tip_exception(status = -1, message)
- raise Educoder::TipException.new(status, message)
+ raise Gitlink::TipException.new(status, message)
end
def missing_template
@@ -257,7 +192,7 @@ class ApplicationController < ActionController::Base
# 弹框提醒
def tip_show_exception(status = -2, message)
- raise Educoder::TipException.new(status, message)
+ raise Gitlink::TipException.new(status, message)
end
def normal_status(status = 0, message)
@@ -272,7 +207,7 @@ class ApplicationController < ActionController::Base
# 资料是否完善
def check_account
- if !current_user.profile_completed?
+ if !current_user. profile_is_completed?
#info_url = '/account/profile'
tip_exception(402, nil)
end
@@ -337,18 +272,18 @@ class ApplicationController < ActionController::Base
# 测试版前端需求
logger.info("subdomain:#{request.subdomain}")
- if request.subdomain != "www"
- if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
- User.current = User.find 81403
- elsif params[:debug] == 'student'
- User.current = User.find 8686
- elsif params[:debug] == 'admin'
- logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
- user = User.find 36480
- User.current = user
- cookies.signed[:user_id] = user.id
- end
- end
+ # if request.subdomain != "www"
+ # if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
+ # User.current = User.find 81403
+ # elsif params[:debug] == 'student'
+ # User.current = User.find 8686
+ # elsif params[:debug] == 'admin'
+ # logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
+ # user = User.find 36480
+ # User.current = user
+ # cookies.signed[:user_id] = user.id
+ # end
+ # end
# User.current = User.find 81403
end
@@ -438,7 +373,7 @@ class ApplicationController < ActionController::Base
JSON.parse(res)
rescue Exception => e
uid_logger_error("--uri_exec: exception #{e.message}")
- raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)")
+ raise Gitlink::TipException.new("实训平台繁忙(繁忙等级:84)")
end
end
@@ -457,7 +392,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
- raise Educoder::TipException.new(message)
+ raise Gitlink::TipException.new(message)
end
end
@@ -481,7 +416,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
- raise Educoder::TipException.new("服务器繁忙")
+ raise Gitlink::TipException.new("服务器繁忙")
end
end
@@ -653,8 +588,8 @@ class ApplicationController < ActionController::Base
# 获取Oauth Client
def get_client(site)
- client_id = Rails.configuration.educoder['client_id']
- client_secret = Rails.configuration.educoder['client_secret']
+ client_id = Rails.configuration.Gitlink['client_id']
+ client_secret = Rails.configuration.Gitlink['client_secret']
OAuth2::Client.new(client_id, client_secret, site: site)
end
@@ -754,10 +689,10 @@ class ApplicationController < ActionController::Base
if @project and current_user.can_read_project?(@project)
logger.info "###########: has project and can read project"
@project
- elsif @project && current_user.is_a?(AnonymousUser)
- logger.info "###########:This is AnonymousUser"
- @project = nil if !@project.is_public?
- render_forbidden and return
+ # elsif @project && current_user.is_a?(AnonymousUser)
+ # logger.info "###########:This is AnonymousUser"
+ # @project = nil if !@project.is_public?
+ # render_forbidden and return
else
logger.info "###########:project not found"
@project = nil
@@ -771,11 +706,12 @@ class ApplicationController < ActionController::Base
end
def base_url
- request.base_url
+ Rails.application.config_for(:configuration)['platform_url'] || request.base_url
end
def convert_image!
- @image = params[:image] || user_params[:image]
+ @image = params[:image]
+ @image = @image.nil? && params[:user].present? ? params[:user][:image] : @image
return unless @image.present?
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
if @image.class == ActionDispatch::Http::UploadedFile
@@ -846,4 +782,8 @@ class ApplicationController < ActionController::Base
HotSearchKeyword.add(keyword)
end
+ def find_atme_receivers
+ @atme_receivers = User.where(login: params[:receivers_login])
+ end
+
end
diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb
index 14e53b3e2..de5e0a8c3 100644
--- a/app/controllers/attachments_controller.rb
+++ b/app/controllers/attachments_controller.rb
@@ -32,8 +32,17 @@ class AttachmentsController < ApplicationController
def get_file
normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
- response = Faraday.get(url)
- filename = params[:download_url].to_s.split("/").pop()
+ if url.starts_with?(base_url)
+ domain = Gitea.gitea_config[:domain]
+ api_url = Gitea.gitea_config[:base_url]
+ url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
+ request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
+ response = Faraday.get(request_url)
+ filename = url.to_s.split("/").pop()
+ else
+ response = Faraday.get(url)
+ filename = params[:download_url].to_s.split("/").pop()
+ end
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
end
@@ -187,7 +196,7 @@ class AttachmentsController < ApplicationController
end
def file_save_to_ucloud(path, file, content_type)
- ufile = Educoder::Ufile.new(
+ ufile = Gitlink::Ufile.new(
ucloud_public_key: edu_setting('public_key'),
ucloud_private_key: edu_setting('private_key'),
ucloud_public_read: true,
diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb
index 63ca58aa6..8e8e3ec91 100644
--- a/app/controllers/compare_controller.rb
+++ b/app/controllers/compare_controller.rb
@@ -6,26 +6,48 @@ class CompareController < ApplicationController
end
def show
+ load_compare_params
compare
+ @merge_status, @merge_message = get_merge_message
end
private
+ def get_merge_message
+ if @base.blank? || @head.blank?
+ return -2, "请选择分支"
+ else
+ 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?
+ @exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take
+ else
+ @exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take
+ end
+ if @exist_pullrequest.present?
+ return -2, "在这些分支之间的合并请求已存在:#{@exist_pullrequest.try(:title)} "
+ else
+ if @compare_result["Commits"].blank? && @compare_result["Diff"].blank?
+ return -2, "分支内容相同,无需创建合并请求"
+ end
+ end
+ end
+ return 0, "可以合并"
+ end
+
def compare
- base, head = compare_params
# TODO: 处理fork的项目向源项目发送PR的base、head参数问题
@compare_result ||=
- head.include?(":") ? gitea_compare(base, head) : gitea_compare(head, base)
+ @head.include?(":") ? gitea_compare(@base, @head) : gitea_compare(@head, @base)
end
- def compare_params
- base = Addressable::URI.unescape(params[:base])
- head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head]
+ def load_compare_params
+ @base = Addressable::URI.unescape(params[:base])
+ @head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head]
- [base, head]
end
def gitea_compare(base, head)
- Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head)
+ Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token)
end
end
diff --git a/app/controllers/concerns/controller_rescue_handler.rb b/app/controllers/concerns/controller_rescue_handler.rb
index 6ff15cfbc..acd9aa2ea 100644
--- a/app/controllers/concerns/controller_rescue_handler.rb
+++ b/app/controllers/concerns/controller_rescue_handler.rb
@@ -20,7 +20,7 @@ module ControllerRescueHandler
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
- rescue_from Educoder::TipException, with: :tip_show
+ rescue_from Gitlink::TipException, with: :tip_show
rescue_from ::ActionView::MissingTemplate, with: :missing_template
rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from ActionController::ParameterMissing, with: :render_parameter_missing
diff --git a/app/controllers/concerns/git_common.rb b/app/controllers/concerns/git_common.rb
index eab069b8e..fbda95f55 100644
--- a/app/controllers/concerns/git_common.rb
+++ b/app/controllers/concerns/git_common.rb
@@ -36,10 +36,10 @@ module GitCommon
begin
@commits = GitService.commits(repo_path: @repo_path)
logger.info("git first commit is #{@commits.try(:first)}")
- raise Educoder::TipException.new("请先创建版本库") if @commits.nil?
+ raise Gitlink::TipException.new("请先创建版本库") if @commits.nil?
rescue Exception => e
uid_logger_error(e.message)
- raise Educoder::TipException.new("提交记录异常")
+ raise Gitlink::TipException.new("提交记录异常")
end
end
diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb
index d8479d458..ede90dc6c 100644
--- a/app/controllers/concerns/git_helper.rb
+++ b/app/controllers/concerns/git_helper.rb
@@ -34,7 +34,7 @@ module GitHelper
rescue Exception => e
Rails.logger.error(e.message)
- raise Educoder::TipException.new("文档内容获取异常")
+ raise Gitlink::TipException.new("文档内容获取异常")
end
end
@@ -64,7 +64,7 @@ module GitHelper
# 版本库Fork功能
def project_fork(container, original_rep_path, username)
- raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
+ raise Gitlink::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
# 将要生成的仓库名字
new_repo_name = "#{username.try(:strip)}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}"
# uid_logger("start fork container: repo_name is #{new_repo_name}")
diff --git a/app/controllers/concerns/laboratory_helper.rb b/app/controllers/concerns/laboratory_helper.rb
index b231b8484..ea6e00558 100644
--- a/app/controllers/concerns/laboratory_helper.rb
+++ b/app/controllers/concerns/laboratory_helper.rb
@@ -41,7 +41,7 @@ module LaboratoryHelper
my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
my_projects: "/users/#{current_user.try(:login)}/projects",
my_organ: "https://www.trustie.net/users/#{current_user.try(:login)}/user_organizations",
- default_url: "https://www.trustie.net/",
+ default_url: Rails.application.config_for(:configuration)['platform_url'],
tiding_url: "https://www.trustie.net/users/#{current_user.try(:login)}/user_messages",
register_url: "https://www.trustie.net/login?login=false"
}
diff --git a/app/controllers/concerns/render_helper.rb b/app/controllers/concerns/render_helper.rb
index fad401539..81e85d1ce 100644
--- a/app/controllers/concerns/render_helper.rb
+++ b/app/controllers/concerns/render_helper.rb
@@ -3,8 +3,8 @@ module RenderHelper
render json: { status: 0, message: 'success' }.merge(data)
end
- def render_error(message = '')
- render json: { status: -1, message: message }
+ def render_error(status = -1, message = '')
+ render json: { status: status, message: message }
end
def render_not_acceptable(message = '请求已拒绝')
diff --git a/app/controllers/edu_settings_controller.rb b/app/controllers/edu_settings_controller.rb
index d3b796da7..340b03ddc 100644
--- a/app/controllers/edu_settings_controller.rb
+++ b/app/controllers/edu_settings_controller.rb
@@ -29,10 +29,8 @@ class EduSettingsController < ApplicationController
respond_to do |format|
if @edu_setting.save
- format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully created.' }
format.json { render :show, status: :created, location: @edu_setting }
else
- format.html { render :new }
format.json { render json: @edu_setting.errors, status: :unprocessable_entity }
end
end
@@ -43,10 +41,8 @@ class EduSettingsController < ApplicationController
def update
respond_to do |format|
if @edu_setting.update(edu_setting_params)
- format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully updated.' }
format.json { render :show, status: :ok, location: @edu_setting }
else
- format.html { render :edit }
format.json { render json: @edu_setting.errors, status: :unprocessable_entity }
end
end
@@ -57,7 +53,6 @@ class EduSettingsController < ApplicationController
def destroy
@edu_setting.destroy
respond_to do |format|
- format.html { redirect_to edu_settings_url, notice: 'Edu setting was successfully destroyed.' }
format.json { head :no_content }
end
end
diff --git a/app/controllers/forks_controller.rb b/app/controllers/forks_controller.rb
index cb18091c1..409133f06 100644
--- a/app/controllers/forks_controller.rb
+++ b/app/controllers/forks_controller.rb
@@ -1,5 +1,6 @@
class ForksController < ApplicationController
before_action :require_login
+ before_action :require_profile_completed, only: [:create]
before_action :load_project
before_action :authenticate_project!, :authenticate_user!
diff --git a/app/controllers/issue_tags_controller.rb b/app/controllers/issue_tags_controller.rb
index d21d8ed4f..f3691f3d4 100644
--- a/app/controllers/issue_tags_controller.rb
+++ b/app/controllers/issue_tags_controller.rb
@@ -7,7 +7,7 @@ class IssueTagsController < ApplicationController
def index
- issue_tags = @project.issue_tags.order("#{order_name} #{order_type}")
+ issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}")
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
@page = params[:page] || 1
@limit = params[:limit] || 15
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 4b073415a..45a8530a3 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -1,19 +1,21 @@
class IssuesController < ApplicationController
before_action :require_login, except: [:index, :show, :index_chosen]
+ before_action :require_profile_completed, only: [:create]
before_action :load_project
before_action :set_user
+ before_action :check_menu_authorize, except: [:index_chosen]
before_action :check_issue_permission
+ before_action :operate_issue_permission, only:[:create, :update, :destroy, :clean, :series_update, :copy]
before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue]
before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue]
- before_action :check_token_enough, only: [:create, :update]
+ before_action :check_token_enough, :find_atme_receivers, only: [:create, :update]
include ApplicationHelper
include TagChosenHelper
def index
- return render_not_found unless @project.has_menu_permission("issues")
- @user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user))
+ @user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user) || @project.is_public?)
issues = @project.issues.issue_issue.issue_index_includes
issues = issues.where(is_private: false) unless @user_admin_or_member
@@ -109,6 +111,8 @@ class IssuesController < ApplicationController
Issues::CreateForm.new({subject:issue_params[:subject]}).validate!
@issue = Issue.new(issue_params)
if @issue.save!
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @issue&.id) if Site.has_notice_menu?
if params[:attachment_ids].present?
params[:attachment_ids].each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
@@ -138,6 +142,10 @@ class IssuesController < ApplicationController
end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
+
+ Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
+ AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
+
render json: {status: 0, message: "创建成", id: @issue.id}
else
normal_status(-1, "创建失败")
@@ -156,6 +164,7 @@ class IssuesController < ApplicationController
def update
last_token = @issue.token
last_status_id = @issue.status_id
+ @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@@ -200,6 +209,26 @@ class IssuesController < ApplicationController
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate!
if @issue.update_attributes(issue_params)
+ if @issue&.pull_request.present?
+ SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
+ else
+ previous_changes = @issue.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name)
+ if @issue.previous_changes[:start_date].present?
+ previous_changes.merge!(start_date: [@issue.previous_changes[:start_date][0].to_s, @issue.previous_changes[:start_date][1].to_s])
+ end
+ if @issue.previous_changes[:due_date].present?
+ previous_changes.merge!(due_date: [@issue.previous_changes[:due_date][0].to_s, @issue.previous_changes[:due_date][1].to_s])
+ end
+ if @issue.previous_changes[:status_id].present? && @issue.previous_changes[:status_id][1] == 5
+ @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE)
+ end
+ if @issue.previous_changes[:status_id].present? && @issue.previous_changes[:status_id][0] == 5
+ @issue.project_trends.where(action_type: ProjectTrend::CLOSE).destroy_all
+ end
+ SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, @issue&.id, previous_changes) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
+ end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project!
@@ -218,7 +247,11 @@ class IssuesController < ApplicationController
change_type = change_token > 0 ? "add" : "minus"
post_to_chain(change_type, change_token.abs, current_user.try(:login))
end
- @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id)
+ @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) if @issue.previous_changes.present?
+
+ Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
+ AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
+
normal_status(0, "更新成功")
else
normal_status(-1, "更新失败")
@@ -230,7 +263,7 @@ class IssuesController < ApplicationController
end
def show
- @user_permission = current_user.present? && current_user.logged? && (!@issue.is_lock || @project.member?(current_user) || current_user.admin? || @issue.user == current_user)
+ @user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user)
@issue_attachments = @issue.attachments
@issue_user = @issue.user
@issue_assign_to = @issue.get_assign_user
@@ -251,6 +284,7 @@ class IssuesController < ApplicationController
status_id = @issue.status_id
token = @issue.token
login = @issue.user.try(:login)
+ SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigned_to_id, @issue.author_id) if Site.has_notice_menu?
if @issue.destroy
if issue_type == "2" && status_id != 5
post_to_chain("add", token, login)
@@ -270,8 +304,12 @@ class IssuesController < ApplicationController
def clean
#批量删除,暂时只能删除未悬赏的
issue_ids = params[:ids]
- if issue_ids.present?
- if Issue.where(id: issue_ids, issue_type: "1").destroy_all
+ issues = Issue.where(id: issue_ids, issue_type: "1")
+ if issues.present?
+ issues.find_each do |i|
+ SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, i&.subject, i.assigned_to_id, i.author_id) if Site.has_notice_menu?
+ end
+ if issues.destroy_all
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
@@ -301,9 +339,28 @@ class IssuesController < ApplicationController
# update_hash = params[:issue]
issue_ids = params[:ids]
if issue_ids.present?
+ issues = Issue.where(id: issue_ids)
if update_hash.blank?
normal_status(-1, "请选择批量更新内容")
- elsif Issue.where(id: issue_ids).update_all(update_hash)
+ elsif issues&.update(update_hash)
+ issues.each do |i|
+ i.create_journal_detail(false, [], [], current_user&.id) if i.previous_changes.present?
+ previous_changes = i.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name)
+ if i.previous_changes[:start_date].present?
+ previous_changes.merge!(start_date: [i.previous_changes[:start_date][0].to_s, i.previous_changes[:start_date][1].to_s])
+ end
+ if i.previous_changes[:due_date].present?
+ previous_changes.merge!(due_date: [i.previous_changes[:due_date][0].to_s, i.previous_changes[:due_date][1].to_s])
+ end
+ if i.previous_changes[:status_id].present? && i.previous_changes[:status_id][1] == 5
+ i.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE)
+ end
+ if i.previous_changes[:status_id].present? && i.previous_changes[:status_id][0] == 5
+ i.project_trends.where(action_type: ProjectTrend::CLOSE).destroy_all
+ end
+ SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, i&.id, previous_changes) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, i&.id) if i.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
+ end
normal_status(0, "批量更新成功")
else
normal_status(-1, "批量更新失败")
@@ -315,7 +372,10 @@ class IssuesController < ApplicationController
def copy
@new_issue = @issue.dup
+ @new_issue.author_id = current_user.id
if @new_issue.save
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @new_issue&.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @new_issue&.id) if Site.has_notice_menu?
issue_tags = @issue.issue_tags.pluck(:id)
if issue_tags.present?
issue_tags.each do |tag|
@@ -393,25 +453,29 @@ class IssuesController < ApplicationController
def check_project_public
unless @project.is_public || @project.member?(current_user) || current_user.admin? || (@project.user_id == current_user.id)
- normal_status(-1, "您没有权限")
+ return render_forbidden
end
end
def set_issue
@issue = Issue.find_by_id(params[:id])
if @issue.blank?
- normal_status(-1, "标签不存在")
- elsif @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?)
- normal_status(-1, "您没有权限")
+ return render_not_found
+ elsif !(@project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id))))
+ return render_forbidden
end
end
def check_issue_permission
unless @project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id)))
- normal_status(-1, "您没有权限")
+ return render_forbidden
end
end
+ def operate_issue_permission
+ return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || @project.is_public?)
+ end
+
def export_issues(issues)
@table_columns = %w(ID 类型 标题 描述 状态 指派给 优先级 标签 发布人 创建时间 里程碑 开始时间 截止时间 完成度 分类 金额 属于)
@export_issues = []
@@ -491,4 +555,8 @@ class IssuesController < ApplicationController
return normal_status(-1, "您的token值不足") if JSON.parse(response.body)["balance"].to_i < params[:token].to_i
end
end
+
+ def check_menu_authorize
+ return render_not_found unless @project.has_menu_permission("issues")
+ end
end
diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb
index 6917974b8..8fbe46924 100644
--- a/app/controllers/journals_controller.rb
+++ b/app/controllers/journals_controller.rb
@@ -1,5 +1,6 @@
class JournalsController < ApplicationController
before_action :require_login, except: [:index, :get_children_journals]
+ before_action :require_profile_completed, :find_atme_receivers, only: [:create]
before_action :set_issue
before_action :check_issue_permission
before_action :set_journal, only: [:destroy, :edit, :update]
@@ -21,32 +22,35 @@ class JournalsController < ApplicationController
if notes.blank?
normal_status(-1, "评论内容不能为空")
else
- journal_params = {
- journalized_id: @issue.id ,
- journalized_type: "Issue",
- user_id: current_user.id ,
- notes: notes.to_s.strip,
- parent_id: params[:parent_id]
- }
- journal = Journal.new journal_params
- if journal.save
- if params[:attachment_ids].present?
- params[:attachment_ids].each do |id|
- attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
- unless attachment.blank?
- attachment.container = journal
- attachment.author_id = current_user.id
- attachment.description = ""
- attachment.save
+ ActiveRecord::Base.transaction do
+ journal_params = {
+ journalized_id: @issue.id ,
+ journalized_type: "Issue",
+ user_id: current_user.id ,
+ notes: notes.to_s.strip,
+ parent_id: params[:parent_id]
+ }
+ journal = Journal.new journal_params
+ if journal.save
+ if params[:attachment_ids].present?
+ params[:attachment_ids].each do |id|
+ attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
+ unless attachment.blank?
+ attachment.container = journal
+ attachment.author_id = current_user.id
+ attachment.description = ""
+ attachment.save
+ end
end
end
+ Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
+ AtmeService.call(current_user, @atme_receivers, journal) if @atme_receivers.size > 0
+ # @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "journal")
+ render :json => { status: 0, message: "评论成功", id: journal.id}
+ # normal_status(0, "评论成功")
+ else
+ normal_status(-1, "评论失败")
end
-
- # @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "journal")
- render :json => { status: 0, message: "评论成功", id: journal.id}
- # normal_status(0, "评论成功")
- else
- normal_status(-1, "评论失败")
end
end
end
diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb
index 7b7468f93..afe767897 100644
--- a/app/controllers/main_controller.rb
+++ b/app/controllers/main_controller.rb
@@ -23,9 +23,9 @@ class MainController < ApplicationController
# TODO: 这块之后需要整合,者架构重新变化,统一跳转到index后再路由分发
if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
- render file: 'public/h5educoderbuild/index.html', :layout => false
+ render file: 'public/h5educoderbuild/index.html', :layout => false, :content_type=> 'text/html'
else
- render file: 'public/react/build/index.html', :layout => false
+ render file: 'public/react/build/index.html', :layout => false, :content_type=> 'text/html'
end
end
diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb
index 67aba25f4..77087770a 100644
--- a/app/controllers/members_controller.rb
+++ b/app/controllers/members_controller.rb
@@ -2,12 +2,15 @@ class MembersController < ApplicationController
before_action :require_login
before_action :load_project
before_action :find_user_with_id, only: %i[create remove change_role]
+ before_action :check_user_profile_completed, only: [:create]
before_action :operate!, except: %i[index]
before_action :check_member_exists!, only: %i[create]
before_action :check_member_not_exists!, only: %i[remove change_role]
def create
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
+ SendTemplateMessageJob.perform_later('ProjectJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -27,6 +30,8 @@ class MembersController < ApplicationController
def remove
interactor = Projects::DeleteMemberInteractor.call(@project.owner, @project, @user)
+ SendTemplateMessageJob.perform_later('ProjectLeft', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -35,6 +40,7 @@ class MembersController < ApplicationController
def change_role
interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role])
+ SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name) if Site.has_notice_menu?
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -47,7 +53,7 @@ class MembersController < ApplicationController
end
def member_exists?
- @project.members.exists?(params[:user_id])
+ @project.members.exists?(user_id: params[:user_id])
end
def operate!
@@ -55,10 +61,24 @@ class MembersController < ApplicationController
end
def check_member_exists!
- return render_result(1, "user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
+ return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
end
def check_member_not_exists!
- return render_result(1, "user_id为#{params[:user_id]}的用户还不是项目成员") unless @project.member?(params[:user_id])
+ return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
+ end
+
+ def check_user_profile_completed
+ require_user_profile_completed(@user)
+ end
+
+ def message_role_name
+ case params[:role]
+ when 'Manager' then '管理员'
+ when 'Developer' then '开发者'
+ when 'Reporter' then '报告者'
+ else
+ ''
+ end
end
end
diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb
index 104db90ed..b73d1efac 100644
--- a/app/controllers/organizations/organizations_controller.rb
+++ b/app/controllers/organizations/organizations_controller.rb
@@ -1,5 +1,6 @@
class Organizations::OrganizationsController < Organizations::BaseController
before_action :require_login, except: [:index, :show, :recommend]
+ before_action :require_profile_completed, only: [:create]
before_action :convert_image!, only: [:create, :update]
before_action :load_organization, only: [:show, :update, :destroy]
before_action :check_user_can_edit_org, only: [:update, :destroy]
@@ -21,10 +22,12 @@ class Organizations::OrganizationsController < Organizations::BaseController
@can_create_project = @organization.can_create_project?(current_user.id)
@is_admin = can_edit_org?
@is_member = @organization.is_member?(current_user.id)
+ Cache::V2::OwnerCommonService.new(@organization.id).read
end
def create
ActiveRecord::Base.transaction do
+ tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name])
Organizations::CreateForm.new(organization_params).validate!
@organization = Organizations::CreateService.call(current_user, organization_params)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
@@ -41,7 +44,8 @@ class Organizations::OrganizationsController < Organizations::BaseController
@organization.login = organization_params[:name] if organization_params[:name].present?
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
@organization.save!
- @organization.organization_extension.update_attributes!(organization_params.except(:name, :nickname))
+ sync_organization_extension!
+
Gitea::Organization::UpdateService.call(@organization.gitea_token, login, @organization.reload)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
end
@@ -65,8 +69,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
def recommend
recommend = %W(xuos Huawei_Technology openatom_foundation pkecosystem TensorLayer)
- @organizations = Organization.with_visibility(%w(common))
- .where(login: recommend).select(:id, :login, :firstname, :lastname, :nickname)
+ @organizations = Organization.includes(:organization_extension).where(organization_extensions: {recommend: true}).to_a.each_slice(group_size).to_a
end
private
@@ -77,6 +80,10 @@ class Organizations::OrganizationsController < Organizations::BaseController
:max_repo_creation, :nickname)
end
+ def group_size
+ params.fetch(:group_size, 4).to_i
+ end
+
def password
params.fetch(:password, "")
end
@@ -95,4 +102,18 @@ class Organizations::OrganizationsController < Organizations::BaseController
%w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
end
+ def set_max_repo_creation
+ organization_params[:max_repo_creation].blank? ? -1 : organization_params[:max_repo_creation]
+ end
+
+ def organization_extension_params
+ organization_params
+ .except(:name, :nickname)
+ .merge(max_repo_creation: set_max_repo_creation)
+ end
+
+ def sync_organization_extension!
+ @organization.organization_extension.update_attributes!(organization_extension_params)
+ end
+
end
\ No newline at end of file
diff --git a/app/controllers/organizations/team_users_controller.rb b/app/controllers/organizations/team_users_controller.rb
index 752e1f0e5..0a5ff28a1 100644
--- a/app/controllers/organizations/team_users_controller.rb
+++ b/app/controllers/organizations/team_users_controller.rb
@@ -1,6 +1,7 @@
class Organizations::TeamUsersController < Organizations::BaseController
before_action :load_organization, :load_team
before_action :load_operate_user, only: [:create, :destroy]
+ before_action :check_user_profile_completed, only: [:create]
before_action :load_team_user, only: [:destroy]
before_action :check_user_can_edit_org, only: [:create, :destroy]
@@ -17,6 +18,7 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user = TeamUser.build(@organization.id, @operate_user.id, @team.id)
@organization_user = OrganizationUser.build(@organization.id, @operate_user.id)
+ SendTemplateMessageJob.perform_later('OrganizationRole', @operate_user.id, @organization.id, @team.authorize_name) if Site.has_notice_menu?
Gitea::Organization::TeamUser::CreateService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
end
rescue Exception => e
@@ -29,6 +31,11 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user.destroy!
Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, @operate_user.login)
+ org_team_users = @organization.team_users.where(user_id: @operate_user.id)
+ unless org_team_users.present?
+ @organization.organization_users.find_by(user_id: @operate_user.id).destroy!
+ Gitea::Organization::OrganizationUser::DeleteService.call(@organization.gitea_token, @organization.login, @operate_user.login)
+ end
render_ok
end
rescue Exception => e
@@ -43,6 +50,11 @@ class Organizations::TeamUsersController < Organizations::BaseController
ActiveRecord::Base.transaction do
@team_user.destroy!
Gitea::Organization::TeamUser::DeleteService.call(@organization.gitea_token, @team.gtid, current_user.login)
+ org_team_users = @organization.team_users.where(user_id: current_user.id)
+ unless org_team_users.present?
+ @organization.organization_users.find_by(user_id: current_user.id).destroy!
+ Gitea::Organization::OrganizationUser::DeleteService.call(@organization.gitea_token, @organization.login, current_user.login)
+ end
render_ok
end
rescue Exception => e
@@ -73,4 +85,8 @@ class Organizations::TeamUsersController < Organizations::BaseController
tip_exception("组织团队成员不存在") if @team_user.nil?
end
+ def check_user_profile_completed
+ require_user_profile_completed(@operate_user)
+ end
+
end
\ No newline at end of file
diff --git a/app/controllers/owners_controller.rb b/app/controllers/owners_controller.rb
index 97444f7a4..73085e4a9 100644
--- a/app/controllers/owners_controller.rb
+++ b/app/controllers/owners_controller.rb
@@ -1,5 +1,5 @@
class OwnersController < ApplicationController
- before_action :require_login
+ before_action :require_login, only: [:index]
def index
@owners = []
@@ -9,4 +9,53 @@ class OwnersController < ApplicationController
teams: {can_create_org_project: true})
.distinct
end
-end
\ No newline at end of file
+
+ def show
+ @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
+ return render_not_found unless @owner.present?
+ # 组织
+ if @owner.is_a?(Organization)
+ return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition
+ @can_create_project = @owner.can_create_project?(current_user.id)
+ @is_admin = current_user.admin? || @owner.is_owner?(current_user.id)
+ @is_member = @owner.is_member?(current_user.id)
+ # 用户
+ else
+ #待办事项,现在未做
+ if User.current.admin? || User.current.login == @owner.login
+ @waiting_applied_messages = @owner.applied_messages.waiting
+ @common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @owner.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @owner.id}, teams: {authorize: %w(admin owner)} )).common
+ @common_applied_projects = AppliedProject.where(project_id: @owner.full_admin_projects).common
+ @undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size
+ else
+ @waiting_applied_messages = AppliedMessage.none
+ @common_applied_transfer_projects = AppliedTransferProject.none
+ @common_applied_projects = AppliedProject.none
+ @undo_events = 0
+ end
+ #用户的组织数量
+ # @user_composes_count = @user.composes.size
+ @user_composes_count = 0
+ user_organizations = User.current.logged? ? @owner.organizations.with_visibility(%w(common limited)) + @owner.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @owner.organizations.with_visibility("common")
+ @user_org_count = user_organizations.size
+ normal_projects = Project.members_projects(@owner.id).to_sql
+ org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @owner.id}).to_sql
+ projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
+ user_projects = User.current.logged? && (User.current.admin? || User.current.login == @owner.login) ? projects : projects.visible
+ @projects_common_count = user_projects.common.size
+ @projects_mirrior_count = user_projects.mirror.size
+ @projects_sync_mirrior_count = user_projects.sync_mirror.size
+ puts @owner.as_json
+ end
+ end
+
+ private
+ def org_limited_condition
+ @owner.organization_extension.limited? && !current_user.logged?
+ end
+
+ def org_privacy_condition
+ return false if current_user.admin?
+ @owner.organization_extension.privacy? && @owner.organization_users.where(user_id: current_user.id).blank?
+ end
+end
diff --git a/app/controllers/praise_tread_controller.rb b/app/controllers/praise_tread_controller.rb
index 983697e08..c355e8fd2 100644
--- a/app/controllers/praise_tread_controller.rb
+++ b/app/controllers/praise_tread_controller.rb
@@ -1,5 +1,6 @@
class PraiseTreadController < ApplicationController
before_action :require_login, except: %i[index]
+ before_action :require_profile_completed, only: [:like]
before_action :find_project_with_id
def index
diff --git a/app/controllers/project_categories_controller.rb b/app/controllers/project_categories_controller.rb
index 106ff7f22..67a040fef 100644
--- a/app/controllers/project_categories_controller.rb
+++ b/app/controllers/project_categories_controller.rb
@@ -5,6 +5,10 @@ class ProjectCategoriesController < ApplicationController
@project_categories = q.result(distinct: true)
end
+ def pinned_index
+ @project_categories = ProjectCategory.where.not(pinned_index: 0).order(pinned_index: :desc)
+ end
+
def group_list
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
# projects = Project.no_anomory_projects.visible
diff --git a/app/controllers/project_rank_controller.rb b/app/controllers/project_rank_controller.rb
new file mode 100644
index 000000000..7bd62987e
--- /dev/null
+++ b/app/controllers/project_rank_controller.rb
@@ -0,0 +1,26 @@
+class ProjectRankController < ApplicationController
+ # 根据时间获取热门项目
+ def index
+ $redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names)
+ deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
+ $redis_cache.zrem("recent-days-project-rank", deleted_data) unless deleted_data.blank?
+ @project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true)
+ rescue Exception => e
+ @project_rank = []
+ end
+
+ private
+ # 默认显示7天的
+ def time
+ params.fetch(:time, 7).to_i
+ end
+
+ def get_timeable_key_names
+ names_array = []
+ (0...time).to_a.each do |i|
+ date_time_string = (Date.today - i.days).to_s
+ names_array << "v2-project-rank-#{date_time_string}"
+ end
+ names_array
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/project_trends_controller.rb b/app/controllers/project_trends_controller.rb
index dc1ffbdb4..66702608d 100644
--- a/app/controllers/project_trends_controller.rb
+++ b/app/controllers/project_trends_controller.rb
@@ -3,7 +3,7 @@ class ProjectTrendsController < ApplicationController
before_action :check_project_public
def index
- project_trends = @project.project_trends.includes(:user, trend: :user)
+ project_trends = @project.project_trends.preload(:user, trend: :user)
check_time = params[:time] #时间的筛选
check_type = params[:type] #动态类型的筛选,目前已知的有 Issue, PullRequest, Version
@@ -14,20 +14,25 @@ class ProjectTrendsController < ApplicationController
project_trends = project_trends.where("created_at between ? and ?",(Time.now.beginning_of_day - check_time.days), Time.now.end_of_day)
end
- @project_open_issues_count = project_trends.where(trend_type: "Issue", action_type: "create").size
@project_close_issues_count = project_trends.where(trend_type: "Issue", action_type: "close").size
- @project_issues_count = @project_open_issues_count + @project_close_issues_count
-
- @project_pr_count = project_trends.where(trend_type: "PullRequest", action_type: "close").size
- @project_new_pr_count = project_trends.where(trend_type: "PullRequest", action_type: "create").size
- @project_pr_all_count = @project_pr_count + @project_new_pr_count
+ @project_issues_count = project_trends.where(trend_type: "Issue", action_type: "create").size
+ @project_open_issues_count = @project_issues_count - @project_close_issues_count
+ @project_pr_count = project_trends.where(trend_type: "PullRequest", action_type: ["close", "merge"]).size
+ @project_pr_all_count = project_trends.where(trend_type: "PullRequest", action_type: "create").size
+ @project_new_pr_count = @project_pr_all_count - @project_pr_count
if check_type.present?
project_trends = project_trends.where(trend_type: check_type.to_s.strip)
end
if check_status.present?
- project_trends = project_trends.where(action_type: check_status.to_s.strip)
+ if check_status == "delay" || check_status == "close"
+ project_trends = project_trends.where(action_type: ["close", "merge"])
+ else
+ project_trends = project_trends.where(action_type: ["create"]).where.not(trend_id: project_trends.where(action_type: ["close", "merge"]).pluck(:trend_id))
+ end
+ else
+ project_trends = project_trends.where(action_type: "create")
end
project_trends = project_trends.order("created_at desc")
diff --git a/app/controllers/projects/applied_transfer_projects_controller.rb b/app/controllers/projects/applied_transfer_projects_controller.rb
index e62033f21..d46274d88 100644
--- a/app/controllers/projects/applied_transfer_projects_controller.rb
+++ b/app/controllers/projects/applied_transfer_projects_controller.rb
@@ -1,5 +1,6 @@
class Projects::AppliedTransferProjectsController < Projects::BaseController
before_action :check_auth
+ before_action :check_user_profile_completed, only: [:create]
def organizations
@organizations = Organization.includes(:organization_extension).joins(team_users: :team).where(team_users: {user_id: current_user.id}, teams: {authorize: %w(admin owner)})
@@ -23,4 +24,10 @@ class Projects::AppliedTransferProjectsController < Projects::BaseController
def check_auth
return render_forbidden unless current_user.admin? ||@project.owner?(current_user)
end
+
+ def check_user_profile_completed
+ @owner = Owner.find_by(login: params[:owner_name])
+ return if @owner.is_a?(Organization)
+ require_user_profile_completed(@owner)
+ end
end
\ No newline at end of file
diff --git a/app/controllers/projects/base_controller.rb b/app/controllers/projects/base_controller.rb
index 9811a2136..240bc91f1 100644
--- a/app/controllers/projects/base_controller.rb
+++ b/app/controllers/projects/base_controller.rb
@@ -4,4 +4,7 @@ class Projects::BaseController < ApplicationController
before_action :load_project
before_action :load_repository
+ def require_manager!
+ return render_forbidden('你没有权限操作') unless current_user.admin? || @project.manager?(current_user)
+ end
end
diff --git a/app/controllers/projects/members_controller.rb b/app/controllers/projects/members_controller.rb
new file mode 100644
index 000000000..9c78229dd
--- /dev/null
+++ b/app/controllers/projects/members_controller.rb
@@ -0,0 +1,6 @@
+class Projects::MembersController < Projects::BaseController
+ def index
+ users = @project.all_collaborators.like(params[:search]).includes(:user_extension)
+ @users = kaminari_paginate(users)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/projects/project_applies_controller.rb b/app/controllers/projects/project_applies_controller.rb
index 37d9d615e..63922a461 100644
--- a/app/controllers/projects/project_applies_controller.rb
+++ b/app/controllers/projects/project_applies_controller.rb
@@ -1,4 +1,5 @@
class Projects::ProjectAppliesController < Projects::BaseController
+ before_action :require_profile_completed, only: [:create]
def create
project = Projects::ApplyJoinService.call(current_user, create_params)
render_ok(project_id: project.id)
diff --git a/app/controllers/projects/project_units_controller.rb b/app/controllers/projects/project_units_controller.rb
index e21fa388f..52cd857d1 100644
--- a/app/controllers/projects/project_units_controller.rb
+++ b/app/controllers/projects/project_units_controller.rb
@@ -6,7 +6,8 @@ class Projects::ProjectUnitsController < Projects::BaseController
def create
if current_user.admin? || @project.manager?(current_user)
ActiveRecord::Base.transaction do
- ProjectUnit.update_by_unit_types!(@project, unit_types)
+ before_units, after_units = ProjectUnit.update_by_unit_types!(@project, unit_types)
+ SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, {navbar: true}) unless before_units.eql?(after_units) if Site.has_notice_menu?
render_ok
end
else
diff --git a/app/controllers/projects/teams_controller.rb b/app/controllers/projects/teams_controller.rb
index b6ea32185..3ffc78001 100644
--- a/app/controllers/projects/teams_controller.rb
+++ b/app/controllers/projects/teams_controller.rb
@@ -14,7 +14,7 @@ class Projects::TeamsController < Projects::BaseController
def create
ActiveRecord::Base.transaction do
@team_project = TeamProject.build(@owner.id, @operate_team.id, @project.id)
- Gitea::Organization::TeamProject::CreateService.call(@owner.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
+ Gitea::Organization::TeamProject::CreateService.call(current_user.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
render_ok
end
rescue Exception => e
@@ -25,7 +25,7 @@ class Projects::TeamsController < Projects::BaseController
def destroy
ActiveRecord::Base.transaction do
@team_project.destroy!
- Gitea::Organization::TeamProject::DeleteService.call(@owner.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
+ Gitea::Organization::TeamProject::DeleteService.call(current_user.gitea_token, @operate_team.gtid, @owner.login, @project.identifier)
render_ok
end
rescue Exception => e
diff --git a/app/controllers/projects/webhooks_controller.rb b/app/controllers/projects/webhooks_controller.rb
new file mode 100644
index 000000000..9f36da206
--- /dev/null
+++ b/app/controllers/projects/webhooks_controller.rb
@@ -0,0 +1,116 @@
+class Projects::WebhooksController < Projects::BaseController
+ before_action :require_manager!
+ before_action :find_webhook, only:[:edit, :update, :destroy, :tasks, :test]
+
+ def index
+ @webhooks = @project.webhooks
+ @webhooks = kaminari_paginate(@webhooks)
+ end
+
+ def create
+ ActiveRecord::Base.transaction do
+ return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19
+ return render_error("参数错误.") unless webhook_params.present?
+ form = Projects::Webhooks::CreateForm.new(webhook_params)
+ return render json: {status: -1, message: form.errors} unless form.validate!
+ response = Gitea::Repository::Webhooks::CreateService.new(operating_token, @project&.owner&.login, @project&.identifier, gitea_webhooks_params).call
+ if response[0] == 201
+ @webhook = response[2]
+ else
+ render_error("创建失败.")
+ end
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def edit
+
+ end
+
+ def update
+ return render_error("参数错误.") unless webhook_params.present?
+ form = Projects::Webhooks::CreateForm.new(webhook_params)
+ return render json: {status: -1, message: form.errors} unless form.validate!
+ response = Gitea::Repository::Webhooks::UpdateService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id, gitea_webhooks_params)
+ if response[0] == 200
+ @webhook = response[2]
+ render_ok
+ else
+ render_error("更新失败.")
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def destroy
+ response = Gitea::Repository::Webhooks::DeleteService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id)
+ if response[0] == 204
+ @webhook = response[2]
+ render_ok
+ else
+ render_error("删除失败.")
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def tasks
+ @tasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
+ @tasks = kaminari_paginate(@tasks)
+ end
+
+ def test
+ ActiveRecord::Base.transaction do
+ response = Gitea::Repository::Webhooks::TestService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id)
+ if response[0] == 204
+ render_ok
+ else
+ render_error("测试推送失败.")
+ end
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ private
+ def find_webhook
+ @webhook = @project.webhooks.find_by_id(params[:id])
+ return render_not_found if @webhook.nil?
+ end
+
+ def webhook_params
+ params.require(:webhook).permit(:url, :type, :http_method, :content_type, :secret, :active, :branch_filter, events: [])
+ end
+
+ def webhook_type
+ webhook_params.fetch(:type, "gitea")
+ end
+
+ def webhook_branch_filter
+ webhook_params.fetch(:branch_filter, "*")
+ end
+
+ def gitea_webhooks_params
+ {
+ active: webhook_params[:active],
+ branch_filter: webhook_branch_filter,
+ config: {
+ content_type: webhook_params[:content_type],
+ url: webhook_params[:url],
+ http_method: webhook_params[:http_method],
+ secret: webhook_params[:secret]
+ },
+ events: webhook_params[:events],
+ type: webhook_type,
+ }
+ end
+
+ def operating_token
+ @project.member?(current_user) ? current_user.gitea_token : @project&.owner&.gitea_token
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 3e40619c5..1864c6964 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -4,8 +4,9 @@ class ProjectsController < ApplicationController
include ProjectsHelper
include Acceleratorable
- before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list]
- before_action :load_project, except: %i[index group_type_list migrate create recommend]
+ before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list]
+ before_action :require_profile_completed, only: [:create, :migrate]
+ before_action :load_repository, except: %i[index group_type_list migrate create recommend banner_recommend]
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
@@ -16,20 +17,21 @@ class ProjectsController < ApplicationController
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls")
+ menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki")
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops")
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources")
menu.append(menu_hash_by_name("activity"))
- menu.append(menu_hash_by_name("setting")) if current_user.admin? || @project.manager?(current_user)
+ menu.append(menu_hash_by_name("settings")) if current_user.admin? || @project.manager?(current_user)
render json: menu
end
def index
- scope = Projects::ListQuery.call(params)
+ scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params)
- # @projects = kaminari_paginate(scope)
- @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
+ @projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units))
+ # @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
category_id = params[:category_id]
@total_count =
@@ -84,6 +86,13 @@ class ProjectsController < ApplicationController
@branches = result.is_a?(Hash) && result.key?(:status) ? [] : result
end
+ def branches_slice
+ return @branches = [] unless @project.forge?
+
+ slice_result = Gitea::Repository::Branches::ListSliceService.call(@owner, @project.identifier)
+ @branches_slice = slice_result.is_a?(Hash) && slice_result.key?(:status) ? [] : slice_result
+ end
+
def group_type_list
project_statics = ProjectStatistic.first
@@ -108,28 +117,35 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
# TODO:
# 临时特殊处理修改website、lesson_url操作方法
- if project_params.has_key?("website")
+ if project_params.has_key?("website")
@project.update(project_params)
+ elsif project_params.has_key?("default_branch")
+ @project.update(project_params)
+ gitea_params = {
+ default_branch: @project.default_branch
+ }
+ Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
else
validate_params = project_params.slice(:name, :description,
- :project_category_id, :project_language_id, :private)
+ :project_category_id, :project_language_id, :private, :identifier)
- Projects::UpdateForm.new(validate_params).validate!
+ Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier)).validate!
- private = params[:private] || false
+ private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false
new_project_params = project_params.except(:private).merge(is_public: !private)
@project.update_attributes!(new_project_params)
+ @project.forked_projects.update_all(is_public: @project.is_public)
gitea_params = {
private: private,
default_branch: @project.default_branch,
- website: @project.website
+ website: @project.website,
+ name: @project.identifier
}
- if [true, false].include? private
- Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
- @project.repository.update_column(:hidden, private)
- end
+ gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
+ @project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
end
+ SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
end
rescue Exception => e
uid_logger_error(e.message)
@@ -144,6 +160,7 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
@project.destroy!
+ @project.forked_projects.update_all(forked_from_project_id: nil)
render_ok
end
else
@@ -173,6 +190,8 @@ class ProjectsController < ApplicationController
end
def simple
+ # 为了缓存活跃项目的基本信息,后续删除
+ Cache::V2::ProjectCommonService.new(@project.id).read
json_response(@project, current_user)
end
@@ -180,6 +199,10 @@ class ProjectsController < ApplicationController
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc)
end
+ def banner_recommend
+ @projects = Project.recommend.where.not(recommend_index: 0).includes(:project_category, :owner, :project_language).order(recommend_index: :desc)
+ end
+
def about
@project_detail = @project.project_detail
@attachments = Array(@project_detail&.attachments) if request.get?
@@ -211,7 +234,7 @@ class ProjectsController < ApplicationController
private
def project_params
- params.permit(:user_id, :name, :description, :repository_name, :website, :lesson_url,
+ params.permit(:user_id, :name, :description, :repository_name, :website, :lesson_url, :default_branch, :identifier,
:project_category_id, :project_language_id, :license_id, :ignore_id, :private)
end
diff --git a/app/controllers/public_keys_controller.rb b/app/controllers/public_keys_controller.rb
new file mode 100644
index 000000000..327e719cc
--- /dev/null
+++ b/app/controllers/public_keys_controller.rb
@@ -0,0 +1,64 @@
+class PublicKeysController < ApplicationController
+ before_action :require_login
+ before_action :find_public_key, only: [:destroy]
+
+ def index
+ @public_keys = current_user.public_keys
+ @public_keys = kaminari_paginate(@public_keys)
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def create
+ return render_error("参数错误") if public_key_params.blank?
+ return render_ok({status: 10002, message: "请输入密钥"}) if public_key_params[:key].blank?
+ return render_ok({status: 10001, message: "请输入标题"}) if public_key_params[:title].blank?
+ @gitea_response = Gitea::User::Keys::CreateService.call(current_user.gitea_token, public_key_params)
+ if @gitea_response[0] == 201
+ @public_key = @gitea_response[2]
+ else
+ return render_error("创建ssh key失败") if @gitea_response[2].blank?
+ return render_ok({status: 10002, message: "密钥格式不正确"}) if @gitea_response[2]["message"].starts_with?("Invalid key content")
+ exist_public_key = Gitea::PublicKey.find_by(content: public_key_params[:key])
+ return render_ok({status: 10002, message: "密钥已被占用"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key") && exist_public_key.present? && exist_public_key&.owner_id != current_user.gitea_uid
+ return render_ok({status: 10002, message: "密钥已存在,请勿重复添加"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key")
+ @public_key = nil
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def destroy
+ return render_not_found unless @public_key.present?
+ result = Gitea::User::Keys::DeleteService.call(current_user.gitea_token, @public_key.id)
+ if result[0] == 204
+ render_ok
+ else
+ render_error
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ private
+
+ def page
+ params[:page].to_i.zero? ? 1 : params[:page].to_i
+ end
+
+ def limit
+ limit = params[:limit] || params[:per_page]
+ limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
+ end
+
+ def public_key_params
+ params.require(:public_key).permit(:key, :title)
+ end
+
+ def find_public_key
+ @public_key = current_user.public_keys.find_by_id(params[:id])
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb
index 8521cd4b3..675c6523b 100644
--- a/app/controllers/pull_requests_controller.rb
+++ b/app/controllers/pull_requests_controller.rb
@@ -1,14 +1,16 @@
class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show, :files, :commits]
+ before_action :require_profile_completed, only: [:create]
before_action :load_repository
+ before_action :check_menu_authorize
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
before_action :load_pull_request, only: [:files, :commits]
+ before_action :find_atme_receivers, only: [:create, :update]
include TagChosenHelper
include ApplicationHelper
def index
- return render_not_found unless @project.has_menu_permission("pulls")
# @issues = Gitea::PullRequest::ListService.new(@user,@repository.try(:identifier)).call #通过gitea获取
issues = @project.issues.issue_pull_request.issue_index_includes.includes(pull_request: :user)
issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user))
@@ -19,6 +21,7 @@ class PullRequestsController < ApplicationController
@close_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::CLOSED})
@merged_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::MERGED})
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
+ @user_admin_or_developer = current_user.present? && (current_user.admin || @project.all_developers.include?(current_user))
scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "PullRequest")
@issues_size = scopes.size
@@ -56,8 +59,11 @@ class PullRequestsController < ApplicationController
ActiveRecord::Base.transaction do
@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"])
- render_ok
+ @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
+ SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id) if Site.has_notice_menu?
+ Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
+ AtmeService.call(current_user, @atme_receivers, @pull_request) if @atme_receivers.size > 0
else
render_error("create pull request error: #{@gitea_pull_request[:status]}")
raise ActiveRecord::Rollback
@@ -66,21 +72,22 @@ class PullRequestsController < ApplicationController
end
def edit
- @fork_project_user_name = @project&.fork_project&.owner.try(:show_real_name)
- @fork_project_user = @project&.fork_project&.owner.try(:login)
- @fork_project_identifier = @project&.fork_project&.repository.try(:identifier)
+ @fork_project_user_name = @pull_request&.fork_project&.owner.try(:show_real_name)
+ @fork_project_user = @pull_request&.fork_project&.owner.try(:login)
+ @fork_project_identifier = @pull_request&.fork_project&.repository.try(:identifier)
end
def update
if params[:title].nil?
normal_status(-1, "名称不能为空")
elsif params[:issue_tag_ids].nil?
- normal_status(-1, "标签不能为空")
+ normal_status(-1, "标记不能为空")
else
ActiveRecord::Base.transaction do
begin
merge_params
+ @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@@ -91,7 +98,7 @@ class PullRequestsController < ApplicationController
if @issue.update_attributes(@issue_params)
if @pull_request.update_attributes(@local_params.compact)
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
- @pull_request.gpid, @requests_params, current_user.gitea_token)
+ @pull_request.gitea_number, @requests_params, current_user.gitea_token)
if gitea_pull[:status] === :success
if params[:issue_tag_ids].present?
@@ -102,6 +109,8 @@ class PullRequestsController < ApplicationController
if params[:status_id].to_i == 5
@issue.issue_times.update_all(end_time: Time.now)
end
+ Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
+ AtmeService.call(current_user, @atme_receivers, @pull_request) if @atme_receivers.size > 0
normal_status(0, "PullRequest更新成功")
else
normal_status(-1, "PullRequest更新失败")
@@ -114,6 +123,8 @@ class PullRequestsController < ApplicationController
normal_status(-1, e.message)
raise ActiveRecord::Rollback
end
+ SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
end
end
@@ -123,7 +134,13 @@ class PullRequestsController < ApplicationController
ActiveRecord::Base.transaction do
begin
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
- colsed === true ? normal_status(1, "已拒绝") : normal_status(-1, '合并失败')
+ if colsed === true
+ @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
+ SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
+ normal_status(1, "已拒绝")
+ else
+ normal_status(-1, '合并失败')
+ end
rescue => e
normal_status(-1, e.message)
raise ActiveRecord::Rollback
@@ -139,7 +156,7 @@ class PullRequestsController < ApplicationController
@issue_user = @issue.user
@issue_assign_to = @issue.get_assign_user
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
- @repository.identifier, @pull_request.gpid, current_user&.gitea_token)
+ @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
end
def pr_merge
@@ -150,11 +167,20 @@ class PullRequestsController < ApplicationController
else
ActiveRecord::Base.transaction do
begin
- result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
+ @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
- if result.status == 200 && @pull_request.merge!
- @pull_request.project_trend_status!
+ if @gitea_pull["merged_by"].present?
+ success_condition = true
+ else
+ result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
+ success_condition = result.status == 200
+ end
+
+ if success_condition && @pull_request.merge!
+ # @pull_request.project_trend_status!
+ @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
+ SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
normal_status(1, "合并成功")
else
normal_status(-1, result.message)
@@ -181,7 +207,7 @@ class PullRequestsController < ApplicationController
if can_merge.present?
render json: {
status: -2,
- message: "在这些分支之间的合并请求已存在:#{can_merge.first.try(:title)} ",
+ message: "在这些分支之间的合并请求已存在:#{can_merge.first.try(:title)} ",
}
else
normal_status(0, "可以合并")
@@ -191,12 +217,12 @@ class PullRequestsController < ApplicationController
def files
- @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token)
+ @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token)
# render json: @files_result
end
def commits
- @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token)
+ @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token)
# render json: @commits_result
end
@@ -252,4 +278,8 @@ class PullRequestsController < ApplicationController
status_id: 1,
}
end
+
+ def check_menu_authorize
+ return render_not_found unless @project.has_menu_permission("pulls")
+ end
end
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 93ba02a92..9b94f0d5d 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -1,13 +1,15 @@
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]
+ 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]
+ 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]
@@ -46,23 +48,13 @@ class RepositoriesController < ApplicationController
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}/"
-
- # TODO
- # 临时处理readme文件问题
- result = Gitea::Repository::Readme::GetService.call(@owner.login, @project.identifier, @ref, @owner&.gitea_token)
- @readme =
- if result[:status] == :success
- result[:body]
- else
- {}
- end
end
end
@@ -72,6 +64,7 @@ class RepositoriesController < ApplicationController
def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
+ @path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
if @project.educoder?
if params[:type] === 'file'
@@ -102,10 +95,21 @@ class RepositoriesController < ApplicationController
end
def commits
- @hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
- sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
+ if params[:filepath].present?
+ file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
+ @hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri,
+ sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
+ else
+ @hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
+ sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
+ end
end
+ def commits_slice
+ @hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier,
+ sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token)
+ end
+
def commit
@sha = params[:sha]
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
@@ -119,7 +123,11 @@ class RepositoriesController < ApplicationController
end
def contributors
- @contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
+ if params[:filepath].present?
+ @contributors = []
+ else
+ @contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
+ end
end
def edit
@@ -182,16 +190,46 @@ class RepositoriesController < ApplicationController
end
def readme
- result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
-
+ if params[:filepath].present?
+ result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
+ else
+ result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
+ end
@readme = result[:status] === :success ? result[:body] : nil
- render json: @readme
+ @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref])
+ render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha")
+ rescue
+ render json: nil
end
def languages
render json: languages_precentagable
end
+ def archive
+ domain = Gitea.gitea_config[:domain]
+ api_url = Gitea.gitea_config[:base_url]
+ archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}"
+
+ file_path = [domain, api_url, archive_url].join
+ file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
+
+ return render_not_found if !request.format.zip? && !request.format.gzip?
+
+ redirect_to file_path
+ end
+
+ def raw
+ domain = Gitea.gitea_config[:domain]
+ api_url = Gitea.gitea_config[:base_url]
+
+ url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{params[:filepath]}?ref=#{params[:ref]}"
+ file_path = [domain, api_url, url].join
+ file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") if @repository.hidden?
+
+ redirect_to URI.escape(file_path)
+ end
+
private
def find_project
@@ -212,8 +250,14 @@ class RepositoriesController < ApplicationController
# TODO 获取最新commit信息
def project_commits
- Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
- sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
+ 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
@@ -266,7 +310,7 @@ class RepositoriesController < ApplicationController
# uploadPushInfo
end
-
+
def create_new_pr(params)
if params[:new_branch].present? && params[:new_branch] != params[:branch]
local_params = {
diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb
index b6662f661..b2dc2e900 100644
--- a/app/controllers/settings_controller.rb
+++ b/app/controllers/settings_controller.rb
@@ -4,7 +4,7 @@ class SettingsController < ApplicationController
get_add_menu
get_common_menu
get_personal_menu
-
+ get_top_system_notification
end
private
@@ -40,6 +40,10 @@ class SettingsController < ApplicationController
end
end
+ def get_top_system_notification
+ @top_system_notification = SystemNotification.is_top.first
+ end
+
def get_site_url(key, value)
key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value)
end
diff --git a/app/controllers/template_message_settings_controller.rb b/app/controllers/template_message_settings_controller.rb
new file mode 100644
index 000000000..967481f2a
--- /dev/null
+++ b/app/controllers/template_message_settings_controller.rb
@@ -0,0 +1,8 @@
+class TemplateMessageSettingsController < ApplicationController
+ before_action :require_login
+
+ def index
+ @group_settings = TemplateMessageSetting.group(:type).count
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/user_rank_controller.rb b/app/controllers/user_rank_controller.rb
new file mode 100644
index 000000000..dddca485c
--- /dev/null
+++ b/app/controllers/user_rank_controller.rb
@@ -0,0 +1,24 @@
+class UserRankController < ApplicationController
+ # 根据时间获取热门开发者
+ def index
+ $redis_cache.zunionstore("recent-days-user-rank", get_timeable_key_names)
+ @user_rank = $redis_cache.zrevrange("recent-days-user-rank", 0, 3, withscores: true)
+ rescue Exception => e
+ @user_rank = []
+ end
+
+ private
+ # 默认显示7天的
+ def time
+ params.fetch(:time, 7).to_i
+ end
+
+ def get_timeable_key_names
+ names_array = []
+ (0...time).to_a.each do |i|
+ date_time_string = (Date.today - i.days).to_s
+ names_array << "v2-user-rank-#{date_time_string}"
+ end
+ names_array
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb
index 128dc539b..214427798 100644
--- a/app/controllers/users/base_controller.rb
+++ b/app/controllers/users/base_controller.rb
@@ -5,7 +5,7 @@ class Users::BaseController < ApplicationController
helper_method :observed_logged_user?, :observed_user
def observed_user
- @_observed_user ||= (User.find_by_id(params[:user_id]) || User.find_by_login(params[:user_id]))
+ @_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
end
def observed_logged_user?
diff --git a/app/controllers/users/headmaps_controller.rb b/app/controllers/users/headmaps_controller.rb
index 81bd5771c..7c88b5681 100644
--- a/app/controllers/users/headmaps_controller.rb
+++ b/app/controllers/users/headmaps_controller.rb
@@ -1,7 +1,7 @@
class Users::HeadmapsController < Users::BaseController
def index
result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp)
- @headmaps = result[2]
+ @headmaps = result[2].blank? ? [] : result[2]
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
diff --git a/app/controllers/users/messages_controller.rb b/app/controllers/users/messages_controller.rb
new file mode 100644
index 000000000..5116f580f
--- /dev/null
+++ b/app/controllers/users/messages_controller.rb
@@ -0,0 +1,96 @@
+class Users::MessagesController < Users::BaseController
+ before_action :private_user_resources!
+ before_action :find_receivers, only: [:create]
+
+ def index
+ limit = params[:limit] || params[:per_page]
+ limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
+ page = params[:page].to_i.zero? ? 1 : params[:page].to_i
+ result = Notice::Read::ListService.call(observed_user.id, message_type, message_status, page, limit)
+ return render_error if result.nil?
+ @data = result[2]
+ end
+
+ def create
+ return render_forbidden unless %w(atme).include?(params[:type])
+ case params[:type]
+ when 'atme'
+ Notice::Write::CreateAtmeForm.new(atme_params).validate!
+ case atme_params[:atmeable_type]
+ when 'Issue'
+ SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
+ when 'PullRequest'
+ SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
+ when 'Journal'
+ journal = Journal.find_by_id(atme_params[:atmeable_id])
+ if journal.present?
+ if journal&.issue&.pull_request.present?
+ SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
+ else
+ SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) if Site.has_notice_menu?
+ end
+ end
+ end
+ end
+ render_ok
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def delete
+ return render_forbidden unless %w(atme).include?(params[:type])
+ result = Notice::Write::DeleteService.call(params[:ids], observed_user.id, message_type)
+ return render_error if result.nil?
+
+ render_ok
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def read
+ return render_forbidden unless %w(notification atme).include?(params[:type])
+ result = Notice::Write::ChangeStatusService.call(params[:ids], observed_user.id, message_type)
+ if result.nil?
+ render_error
+ else
+ render_ok
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ private
+ def message_type
+ @message_type = begin
+ case params[:type]
+ when "notification" then 1
+ when "atme" then 2
+ else
+ -1
+ end
+ end
+ end
+
+ def message_status
+ @message_status = begin
+ case params[:status]
+ when "1" then 1
+ when "2" then 2
+ else
+ -1
+ end
+ end
+ end
+
+ def atme_params
+ params.permit(:atmeable_type, :atmeable_id, receivers_login: [])
+ end
+
+ def find_receivers
+ @receivers = User.where(login: params[:receivers_login])
+ return render_not_found if @receivers.size == 0
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb
index c6cc0d889..dffd3f607 100644
--- a/app/controllers/users/statistics_controller.rb
+++ b/app/controllers/users/statistics_controller.rb
@@ -14,7 +14,7 @@ class Users::StatisticsController < Users::BaseController
@date_data << date.strftime("%Y.%m.%d")
@issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size
@pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size
- date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
+ date_commit_data = commit_data.blank? ? nil : commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
@commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i)
end
render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data}
@@ -188,30 +188,32 @@ class Users::StatisticsController < Users::BaseController
@project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count
@platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count
else
+ @platform_result = Cache::V2::PlatformStatisticService.new.read
+ @user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
# 用户被follow数量
- @follow_count = Cache::UserFollowCountService.call(observed_user)
- @platform_follow_count = Cache::PlatformFollowCountService.call
+ @follow_count = @user_result["follow-count"].to_i
+ @platform_follow_count = @platform_result["follow-count"].to_i
# 用户pr数量
- @pullrequest_count = Cache::UserPullrequestCountService.call(observed_user)
- @platform_pullrequest_count = Cache::PlatformPullrequestCountService.call
+ @pullrequest_count = @user_result["pullrequest-count"].to_i
+ @platform_pullrequest_count = @platform_result["pullrequest-count"].to_i
# 用户issue数量
- @issues_count = Cache::UserIssueCountService.call(observed_user)
- @platform_issues_count = Cache::PlatformIssueCountService.call
+ @issues_count = @user_result["issue-count"].to_i
+ @platform_issues_count = @platform_result["issue-count"].to_i
# 用户总项目数
- @project_count = Cache::UserProjectCountService.call(observed_user)
- @platform_project_count = Cache::PlatformProjectCountService.call
+ @project_count = @user_result["project-count"].to_i
+ @platform_project_count = @platform_result["project-count"].to_i
# 用户项目被fork数量
- @fork_count = Cache::UserProjectForkCountService.call(observed_user)
- @platform_fork_count = Cache::PlatformProjectForkCountService.call
+ @fork_count = @user_result["fork-count"].to_i
+ @platform_fork_count = @platform_result["fork-count"].to_i
# 用户项目关注数
- @project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user)
- @platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call
+ @project_watchers_count = @user_result["project-watcher-count"].to_i
+ @platform_project_watchers_count = @platform_result["project-watcher-count"].to_i
# 用户项目点赞数
- @project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user)
- @platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call
+ @project_praises_count = @user_result["project-praise-count"].to_i
+ @platform_project_praises_count = @platform_result["project-praise-count"].to_i
# 用户不同语言项目数量
- @project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user)
- @platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call
+ @project_languages_count = JSON.parse(@user_result["project-language"])
+ @platform_project_languages_count = JSON.parse(@platform_result["project-language"])
end
end
end
\ No newline at end of file
diff --git a/app/controllers/users/system_notification_histories_controller.rb b/app/controllers/users/system_notification_histories_controller.rb
new file mode 100644
index 000000000..70e91fbb9
--- /dev/null
+++ b/app/controllers/users/system_notification_histories_controller.rb
@@ -0,0 +1,15 @@
+class Users::SystemNotificationHistoriesController < Users::BaseController
+ before_action :private_user_resources!, only: [:create]
+ def create
+ @history = observed_user.system_notification_histories.new(system_notification_id: params[:system_notification_id])
+ if @history.save
+ render_ok
+ else
+ Rails.logger.info @history.errors.as_json
+ render_error(@history.errors.full_messages.join(","))
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/users/template_message_settings_controller.rb b/app/controllers/users/template_message_settings_controller.rb
new file mode 100644
index 000000000..2234e7301
--- /dev/null
+++ b/app/controllers/users/template_message_settings_controller.rb
@@ -0,0 +1,36 @@
+class Users::TemplateMessageSettingsController < Users::BaseController
+ before_action :check_auth
+ before_action :get_current_setting
+
+ def current_setting
+
+ end
+
+ def update_setting
+ Rails.logger.info setting_params[:notification_body]
+ Rails.logger.info setting_params[:email_body]
+
+ @current_setting.notification_body = setting_params[:notification_body].to_hash
+ @current_setting.email_body = setting_params[:email_body].to_hash
+ return render_error("保存失败") unless @current_setting.save!
+ end
+
+ private
+ def check_auth
+ return render_forbidden unless current_user.admin? || observed_logged_user?
+ end
+
+ def get_current_setting
+ @current_setting = @_observed_user.user_template_message_setting
+ @current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil?
+ end
+
+ def setting_params
+ params.require(:setting).permit(notification_body: {}, email_body: {})
+ end
+
+ def valid_setting_params
+ setting_params[:notification_body].keys.equal?(UserTemplateMessageSetting.init_notification_body.keys) && setting_params[:email_body].keys.equal?(UserTemplateMessageSetting.init_email_body)
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index a0184a348..744468ed8 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -51,6 +51,8 @@ class UsersController < ApplicationController
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size
+ # 为了缓存活跃用户的基本信息,后续删除
+ Cache::V2::OwnerCommonService.new(@user.id).read
end
def watch_users
@@ -74,7 +76,7 @@ class UsersController < ApplicationController
end
def update
- return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id])
+ 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)
@@ -91,6 +93,12 @@ class UsersController < ApplicationController
def get_user_info
begin
@user = current_user
+ begin
+ result = Notice::Read::CountService.call(current_user.id)
+ @message_unread_total = result.nil? ? 0 : result[2]["unread_notification"]
+ rescue
+ @message_unread_total = 0
+ end
# TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
rescue Exception => e
@@ -185,7 +193,7 @@ class UsersController < ApplicationController
def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = []
- domain_url = EduSetting.get('host_name') + '/projects'
+ domain_url = EduSetting.get('host_name')
if projects.present?
projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}"
diff --git a/app/controllers/version_releases_controller.rb b/app/controllers/version_releases_controller.rb
index ac17c7d4b..2d7546a1c 100644
--- a/app/controllers/version_releases_controller.rb
+++ b/app/controllers/version_releases_controller.rb
@@ -1,14 +1,14 @@
class VersionReleasesController < ApplicationController
before_action :load_repository
before_action :set_user
- before_action :require_login, except: [:index]
- before_action :find_version , only: [:edit, :update, :destroy]
+ before_action :require_login, except: [:index, :show]
+ before_action :check_release_authorize, except: [:index, :show]
+ before_action :find_version , only: [:show, :edit, :update, :destroy]
def index
- version_releases = Gitea::Versions::ListService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier)).call
- @version_releases = version_releases
- @user_permission = current_user.present? && (current_user == @user || current_user.admin?)
- @forge_releases = @repository.version_releases.select(:id,:version_gid, :created_at).includes(:attachments)
+ @version_releases = kaminari_paginate(@repository.version_releases.order(created_at: :desc))
+ @user_permission = current_user.present? && (@repository.project.all_developers.include?(current_user) || current_user.admin?)
+ @user_admin_permission = current_user.present? && (@repository.project.all_managers.include?(current_user) || current_user.admin?)
end
def new
@@ -22,6 +22,10 @@ class VersionReleasesController < ApplicationController
end
end
+ def show
+ # @release = Gitea::Versions::GetService.call(current_user.gitea_token, @user&.login, @repository&.identifier, @version&.version_gid)
+ end
+
def create
if params[:name].nil?
normal_status(-1, "名称不能为空")
@@ -37,13 +41,14 @@ class VersionReleasesController < ApplicationController
version_params = releases_params
version_release = VersionRelease.new(version_params.merge(user_id: current_user.id, repository_id: @repository.id))
if version_release.save!
- git_version_release = Gitea::Versions::CreateService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params).call
+ git_version_release = Gitea::Versions::CreateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params).call
if git_version_release
update_params = {
tarball_url: git_version_release["tarball_url"],
zipball_url: git_version_release["zipball_url"],
url: git_version_release["url"],
version_gid: git_version_release["id"],
+ sha: git_version_release["sha"]
}
version_release.update_attributes!(update_params)
version_release.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
@@ -81,7 +86,7 @@ class VersionReleasesController < ApplicationController
if @version.update_attributes!(version_params)
create_attachments(params[:attachment_ids], @version) if params[:attachment_ids].present?
- git_version_release = Gitea::Versions::UpdateService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call
+ git_version_release = Gitea::Versions::UpdateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call
unless git_version_release
raise Error, "更新失败"
end
@@ -102,7 +107,7 @@ class VersionReleasesController < ApplicationController
ActiveRecord::Base.transaction do
begin
if @version.destroy
- git_version_release = Gitea::Versions::DeleteService.new(@user.gitea_token, @user.try(:login), @repository.try(:identifier), @version.try(:version_gid)).call
+ git_version_release = Gitea::Versions::DeleteService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), @version.try(:version_gid)).call
if git_version_release.status == 204
normal_status(0, "删除成功")
@@ -157,4 +162,8 @@ class VersionReleasesController < ApplicationController
end
end
+ def check_release_authorize
+ return render_forbidden("您没有权限进行此操作.") unless current_user.admin? || @project.manager?(current_user)
+ end
+
end
diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb
index f5d09ed3b..4e515db71 100644
--- a/app/controllers/versions_controller.rb
+++ b/app/controllers/versions_controller.rb
@@ -1,11 +1,12 @@
class VersionsController < ApplicationController
before_action :require_login, except: [:index, :show]
+ before_action :require_profile_completed, only: [:create]
before_action :load_repository
+ before_action :check_menu_authorize
before_action :check_issue_permission, except: [:show, :index]
before_action :set_version, only: [:edit, :update, :destroy, :show,:update_status]
def index
- return render_not_found unless @project.has_menu_permission("versions")
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
status = params[:status]
versions = @project.versions.version_includes
@@ -25,17 +26,13 @@ class VersionsController < ApplicationController
end
def show
- version_issues = @version.issues.issue_includes
+ version_issues = @version.issues.issue_issue.issue_includes
status_type = params[:status_type] || "1"
# @close_issues_size = version_issues.where(status_id: 5).size
# @open_issues_size = version_issues.size - @close_issues_size
- if status_type.to_s == "1" #表示开启中的
- version_issues = version_issues.where.not(status_id: 5)
- else
- version_issues = version_issues.where(status_id: 5)
- end
+
version_issues = version_issues.where(author_id: params[:author_id]) if params[:author_id].present? && params[:author_id].to_s != "all"
version_issues = version_issues.where(assigned_to_id: params[:assigned_to_id]) if params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all"
version_issues = version_issues.where(tracker_id: params[:tracker_id]) if params[:tracker_id].present? && params[:tracker_id].to_s != "all"
@@ -47,10 +44,26 @@ class VersionsController < ApplicationController
version_issues = version_issues.joins(:issue_tags).where(issue_tags: {id: params[:issue_tag_id].to_i}) if params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all"
version_issues = version_issues.reorder("#{order_name} #{order_type}")
+ has_filter_params = (params[:author_id].present? && params[:author_id].to_s != "all") ||
+ (params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all") ||
+ (params[:tracker_id].present? && params[:tracker_id].to_s != "all") ||
+ (params[:status_id].present? && params[:status_id].to_s != "all") ||
+ (params[:priority_id].present? && params[:priority_id].to_s != "all") ||
+ (params[:fixed_version_id].present? && params[:fixed_version_id].to_s != "all") ||
+ (params[:done_ratio].present? && params[:done_ratio].to_s != "all") ||
+ (params[:issue_type].present? && params[:issue_type].to_s != "all") ||
+ (params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all")
+ @version_close_issues_size = has_filter_params ? version_issues.closed.size : @version.issues.issue_issue.issue_includes.closed.size
+ @version_issues_size = has_filter_params ? version_issues.size : @version.issues.issue_issue.issue_includes.size
+ if status_type.to_s == "1" #表示开启中的
+ version_issues = version_issues.where.not(status_id: 5)
+ else
+ version_issues = version_issues.where(status_id: 5)
+ end
@page = params[:page] || 1
@limit = params[:limit] || 15
- @version_issues_size = version_issues.size
+ # @version_issues_size = version_issues.size
@version_issues = version_issues.page(@page).per(@limit)
end
@@ -170,4 +183,8 @@ class VersionsController < ApplicationController
%w(desc asc).include?(params[:order_type]) ? params[:order_type] : 'desc'
end
+ def check_menu_authorize
+ return render_not_found unless @project.has_menu_permission("versions")
+ end
+
end
diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb
index 38f60ebae..aa3642616 100644
--- a/app/controllers/watchers_controller.rb
+++ b/app/controllers/watchers_controller.rb
@@ -1,5 +1,6 @@
class WatchersController < ApplicationController
before_action :require_login, except: %i[index]
+ before_action :require_profile_completed, only: [:follow]
# before_action :find_project_with_id
before_action :get_target
diff --git a/app/decorators/course_decorator.rb b/app/decorators/course_decorator.rb
deleted file mode 100644
index 9c3340bbf..000000000
--- a/app/decorators/course_decorator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module CourseDecorator
- def can_visited?
- is_public == 1 || User.current.admin_or_business? || User.current.member_of_course?(self)
- end
-end
\ No newline at end of file
diff --git a/app/decorators/ec_course_target_decorator.rb b/app/decorators/ec_course_target_decorator.rb
deleted file mode 100644
index 2965a8381..000000000
--- a/app/decorators/ec_course_target_decorator.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module EcCourseTargetDecorator
-end
\ No newline at end of file
diff --git a/app/decorators/experience_decorator.rb b/app/decorators/experience_decorator.rb
deleted file mode 100644
index f50f479d7..000000000
--- a/app/decorators/experience_decorator.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module ExperienceDecorator
- def container_type_text
- I18n.t("experience.container_type.#{container_type.to_s.underscore}")
- end
-
- def content
- case container_type.to_s.underscore
- when 'game' then
- game = Game.find_by(id: container_id)
- game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
- when 'shixun_publish' then
- shixun = Shixun.find_by(id: container_id)
- shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
- end
- end
-end
\ No newline at end of file
diff --git a/app/decorators/grade_decorator.rb b/app/decorators/grade_decorator.rb
deleted file mode 100644
index 5e2b9deed..000000000
--- a/app/decorators/grade_decorator.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module GradeDecorator
- def container_type_text
- I18n.t("grade.container_type.#{container_type.to_s.underscore}")
- end
-
- def content
- case container_type.to_s.underscore
- when 'avatar' then '用户首次上传头像获得的奖励'
- when 'phone' then '用户首次绑定手机号码获得的奖励'
- when 'mail' then '用户首次绑定邮箱获得的奖励'
- when 'attendance' then '用户每天签到获得的奖励'
- when 'account' then '新用户首次填写基本资料获得的奖励'
- when 'memo' then '发布的评论或者帖子获得平台奖励'
- when 'discusses' then '发布的评论获得平台奖励'
- when 'star' then '用户给实训评分获得的随机奖励'
- when 'feedback' then '反馈的问题获得平台奖励'
- when 'authentication' then '用户首次完成实名认证获得的奖励'
- when 'professional' then '用户首次完成职业认证获得的奖励'
- when 'answer' then
- game = Game.find_by(id: container_id)
- game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的参考答案消耗的金币" : ''
- when 'game' then
- game = Game.find_by(id: container_id)
- game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
- when 'test_set' then
- game = Game.find_by(id: container_id)
- game.present? ? "查看实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关的隐藏测试集消耗的金币" : ''
- when 'shixun_publish' then
- shixun = Shixun.find_by(id: container_id)
- shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
- when 'check_ta_answer' then
- game = Game.find_by(id: container_id)
- game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : ''
- when 'hack' then
- hack = Hack.find_by(id: container_id)
- hack.present? ? "完成了题目解答“#{hack.name}”,获得金币奖励:#{hack.score}" : ''
- end
- end
-end
\ No newline at end of file
diff --git a/app/decorators/library_decorator.rb b/app/decorators/library_decorator.rb
deleted file mode 100644
index 2768ad036..000000000
--- a/app/decorators/library_decorator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module LibraryDecorator
- extend ApplicationDecorator
-
- display_time_method :published_at, :created_at, :updated_at
-end
\ No newline at end of file
diff --git a/app/decorators/shixun_decorator.rb b/app/decorators/shixun_decorator.rb
deleted file mode 100644
index 4b7a0714a..000000000
--- a/app/decorators/shixun_decorator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module ShixunDecorator
- def human_status
- I18n.t("shixun.status.#{status}")
- end
-end
diff --git a/app/decorators/subject_decorator.rb b/app/decorators/subject_decorator.rb
deleted file mode 100644
index 7ba3277f7..000000000
--- a/app/decorators/subject_decorator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module SubjectDecorator
- def can_visited?
- published? || User.current.admin? || member?(User.current)
- end
-end
\ No newline at end of file
diff --git a/app/decorators/video_decorator.rb b/app/decorators/video_decorator.rb
deleted file mode 100644
index 904e78dbb..000000000
--- a/app/decorators/video_decorator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module VideoDecorator
- extend ApplicationDecorator
-
- display_time_method :published_at, :created_at, :updated_at
-end
\ No newline at end of file
diff --git a/app/docs/slate/source/api.html.md b/app/docs/slate/source/api.html.md
index a08823a4e..a846317c4 100644
--- a/app/docs/slate/source/api.html.md
+++ b/app/docs/slate/source/api.html.md
@@ -12,6 +12,7 @@ toc_footers:
includes:
- licenses
- gitignores
+ - public_keys
- users
- projects
- repositories
diff --git a/app/docs/slate/source/images/logo.png b/app/docs/slate/source/images/logo.png
index 30affed0b..2f34775dc 100644
Binary files a/app/docs/slate/source/images/logo.png and b/app/docs/slate/source/images/logo.png differ
diff --git a/public/docs/images/logo-b38b63e6.png b/app/docs/slate/source/images/trustie_logo.png
similarity index 100%
rename from public/docs/images/logo-b38b63e6.png
rename to app/docs/slate/source/images/trustie_logo.png
diff --git a/app/docs/slate/source/includes/_public_keys.md b/app/docs/slate/source/includes/_public_keys.md
new file mode 100644
index 000000000..60d73c01a
--- /dev/null
+++ b/app/docs/slate/source/includes/_public_keys.md
@@ -0,0 +1,158 @@
+
+# PublicKeys
+
+## public_keys列表
+获取public_keys列表,支持分页
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/public_keys.json
+```
+
+```javascript
+await octokit.request('GET /api/public_keys.json')
+```
+
+### HTTP 请求
+`GET api/public_keys.json`
+
+### 请求参数
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+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
+{
+ "total_count": 1,
+ "public_keys": [
+ {
+ "id": 16,
+ "name": "xxx",
+ "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
+ "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
+ "created_unix": 1626246596,
+ "created_time": "2021/07/14 15:09"
+ }
+ ]
+}
+```
+
+Success — a happy kitten is an authenticated kitten!
+
+
+## 创建public_key
+创建public_key
+
+> 示例:
+
+```shell
+curl -X POST \
+http://localhost:3000/api/public_keys.json
+```
+
+```javascript
+await octokit.request('POST /api/public_keys.json')
+```
+
+### HTTP 请求
+`POST api/public_keys.json`
+
+### 请求参数
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+key |是 | 否 | string | 密钥 |
+title |是 | 否 | string | 密钥标题 |
+
+> 请求的JSON示例:
+```json
+{
+ "public_key": {
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
+ "title": "xxx"
+ }
+}
+```
+
+### 返回字段说明
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+total_count |int |总数 |
+id |int |ID|
+name |string|密钥标题|
+content |string|密钥内容|
+fingerprint |string|密钥标识|
+created_time |string|密钥创建时间|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "id": 17,
+ "name": "xxx",
+ "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
+ "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
+ "created_time": "2021/07/14 15:26"
+}
+```
+
+Success — a happy kitten is an authenticated kitten!
+
+
+
+## 删除public_key
+删除public_key
+
+> 示例:
+
+```shell
+curl -X DELETE \
+http://localhost:3000/api/public_keys/:id.json
+```
+
+```javascript
+await octokit.request('DELETE /api/public_keys/:id.json')
+```
+
+### HTTP 请求
+`DELETE api/public_keys/:id.json`
+
+### 请求参数
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+id |是 | 否 | int | 密钥ID |
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+Success — a happy kitten is an authenticated kitten!
+
+
diff --git a/app/docs/slate/source/includes/_pulls.md b/app/docs/slate/source/includes/_pulls.md
index 1df50f6bf..b9ad3b0ba 100644
--- a/app/docs/slate/source/includes/_pulls.md
+++ b/app/docs/slate/source/includes/_pulls.md
@@ -1 +1,502 @@
# Pulls
+
+
+## Get a pull request
+获取合并请求详情接口
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/Jasder/gitlink/pulls/88.json
+```
+
+```javascript
+await octokit.request('GET /api/Jasder/gitlink/pulls/88.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/pulls/:id.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|id |是| | integer | pull id值 |
+
+
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "响应成功",
+ "project_name": "Gitlink",
+ "identifier": "forgeplus",
+ "project_identifier": "forgeplus",
+ "pr_time": "52分钟前",
+ "commits_count": 229,
+ "files_count": 328,
+ "comments_count": 0,
+ "comments_total_count": 0,
+ "pull_request": {
+ "id": 1189,
+ "base": "master",
+ "head": "develop",
+ "status": 0,
+ "fork_project_id": null,
+ "is_original": false,
+ "pull_request_staus": "open",
+ "fork_project_user": null,
+ "create_user": "jasder",
+ "mergeable": true,
+ "state": "open"
+ },
+ "issue": {
+ "id": 51888,
+ "subject": "FIx release v3.2.0",
+ "description": null,
+ "is_private": false,
+ "branch_name": null,
+ "project_author_name": "Gitlink",
+ "closed_on": "",
+ "created_at": "2021-10-12 15:51",
+ "assign_user_name": "victor",
+ "assign_user_login": "moshenglv",
+ "author_name": "段甲生",
+ "author_login": "jasder",
+ "author_picture": "images/avatars/User/36480?t=1615520120",
+ "issue_status": "新增",
+ "priority": "正常",
+ "version": null,
+ "issue_tags": null
+ },
+ "conflict_files": []
+}
+```
+
+## 获取pull request文件列表
+获取pull request文件列表
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/Jason/gitlink/pulls/1/files.json
+```
+
+```javascript
+await octokit.request('GET /api/jasder/gitlink/pulls/1/files.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/pulls/:id/files.json`
+
+### 请求参数:
+|参数名|必选|类型|说明|
+|-|-|-|-|
+|owner |是|string |用户登录名 |
+|repo |是|string |project's identifier |
+|id |是|int |pull request's id |
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|-|-|-|
+|files_count |int|文件更改的总数量|
+|total_addition |int|添加代码总行数|
+|total_deletion |int|删除代码总行数|
+|files |array||
+|-- sha |string|commit's sha value|
+|-- name |string|当前文件名|
+|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改|
+|-- addition |int|文件添加的行数|
+|-- deletion |int|文件删除的行数|
+|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容|
+|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否|
+|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否|
+|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否|
+|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否|
+|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否|
+|-- sections |array||
+|---- fileName |string|文件名称|
+|---- lines |array||
+|------ leftIdx |string|文件变动之前所在行数|
+|------ rightIdx |string|文件更改后所在行数|
+|------ type |string|文件变更类型,1: 新增,2: 修改, 3: 删除, 4: diff统计信息|
+|------ content |string|文件变更的内容|
+|------ sectionInfo |object||
+|-------- path |string|文件相对仓库的路径|
+|-------- lastLeftIdx |int||
+|-------- lastRightIdx |int||
+|-------- leftHunkSize |int|文件变更之前的行数|
+|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)|
+|-------- leftIdx |int|文件变更之前所在行数|
+|-------- rightIdx |int|文件变更之后所在行数(即:页面编辑器开始显示的行数)|
+
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "files_count": 6,
+ "total_addition": 447,
+ "total_deletion": 0,
+ "files": [
+ {
+ "sha": "xefenisnii",
+ "name": "文件.txt",
+ "old_name": "文件.txt",
+ "index": 6,
+ "addition": 2,
+ "deletion": 0,
+ "type": 1,
+ "isCreated": true,
+ "isDeleted": false,
+ "isBin": false,
+ "isLFSFile": false,
+ "isRenamed": false,
+ "isSubmodule": false,
+ "sections": [
+ {
+ "fileName": "文件.txt",
+ "name": "",
+ "lines": [
+ {
+ "leftIdx": 0,
+ "rightIdx": 0,
+ "type": 4,
+ "content": "@@ -0,0 +1,2 @@",
+ "sectionInfo": {
+ "path": null,
+ "lastLeftIdx": null,
+ "lastRightIdx": null,
+ "leftIdx": 0,
+ "rightIdx": 0,
+ "leftHunkSize": null,
+ "rightHunkSize": null
+ }
+ },
+ {
+ "leftIdx": 0,
+ "rightIdx": 1,
+ "type": 2,
+ "content": "+用例图一致性更新",
+ "sectionInfo": null
+ },
+ {
+ "leftIdx": 0,
+ "rightIdx": 2,
+ "type": 2,
+ "content": "+工程文件直接上传会有文件缺失,现在压缩后上传",
+ "sectionInfo": null
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+```
+
+
+## 获取pull request的commits列表
+获取pull request的commits列表
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/jasder/jasder_test/pulls/1/commits.json
+```
+
+```javascript
+await octokit.request('GET /api/jasder/jasder_test/pulls/1/commits.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/pulls/:id/commits.json`
+
+### 请求参数:
+|参数名|必选|类型|说明|
+|-|-|-|-|
+|owner |是|string |用户登录名 |
+|repo |是|string |project's identifier |
+|id |是|int |pull request's id |
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|commits_count |int|commits总数量|
+|commits |array||
+|-- author |object|项目作者|
+|---- login |string|用户login|
+|---- name |string|用户姓名|
+|---- image_url |string|用户头像|
+|-- committer |object|commit提交用户|
+|---- login |string|用户login|
+|---- name |string|用户姓名|
+|---- image_url |string|用户头像|
+|-- timestamp |int|commit的unix时间戳|
+|-- time_from_now|string|commit’s 提交时间距当前时间的时间值|
+|-- message |string|commit说明信息|
+|-- sha |string|commit’s sha值|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "commits_count": 1,
+ "commits": [
+ {
+ "author": {
+ "id": 36480,
+ "login": "jasder",
+ "name": "段甲生",
+ "image_url": "avatars/User/b"
+ },
+ "committer": {
+ "id": 36480,
+ "login": "jasder",
+ "name": "段甲生",
+ "image_url": "avatars/User/b"
+ },
+ "timestamp": 1604382982,
+ "time_from_now": "3小时前",
+ "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n",
+ "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968"
+ }
+ ]
+}
+```
+
+## Compare two commits
+Compare two commits
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/Jason/test-txt/compare/master...develop
+
+curl -X GET \
+http://localhost:3000/api/Jason/test-txt/compare/master...Jason/test-txt:develop
+```
+
+```javascript
+await octokit.request('GET /api/Jason/test-txt/compare/master...Jason/test-txt:develop')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/compare/{base}...{head}.json`
+
+### 请求参数:
+|参数名|必选|类型|说明|
+|-|-|-|-|
+|owner |是|string |用户登录名 |
+|repo |是|string |project's identifier |
+|base |是|string |pull request's id |
+|head |是|string |pull request's id |
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|-|-|-|
+|commits_count |int|commits总数量|
+|commits |array||
+|-- author |object|项目作者|
+|---- login |string|用户login|
+|---- name |string|用户姓名|
+|---- image_url |string|用户头像|
+|-- committer |object|commit提交用户|
+|---- login |string|用户login|
+|---- name |string|用户姓名|
+|---- image_url |string|用户头像|
+|-- timestamp |int|commit的unix时间戳|
+|-- time_from_now|string|commit’s 提交时间距当前时间的时间值|
+|-- message |string|commit说明信息|
+|-- sha |string|commit’s sha值|
+|diff |object||
+|-- files_count |int|文件更改的总数量|
+|-- total_addition |int|添加代码总行数|
+|-- total_deletion |int|删除代码总行数|
+|-- files |Array||
+|-- sha |string|commit's sha |
+|-- name |string|当前文件名|
+|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改|
+|-- addition |int|文件添加的行数|
+|-- deletion |int|文件删除的行数|
+|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容|
+|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否|
+|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否|
+|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否|
+|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否|
+|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否|
+|-- sections |array||
+|---- fileName |string|文件名称|
+|---- lines |array||
+|------ leftIdx |string|文件变动之前所在行数|
+|------ rightIdx |string|文件更改后所在行数|
+|------ type |string|文件变更类型,1: 内容未改动,2: 添加, 3: 删除, 4: diff统计信息|
+|------ content |string|文件变更的内容|
+|------ sectionInfo |object||
+|-------- path |string|文件相对仓库的路径|
+|-------- lastLeftIdx |int||
+|-------- lastRightIdx |int||
+|-------- leftHunkSize |int|文件变更之前的行数|
+|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)|
+|-------- leftIdx |int|文件变更之前所在行数|
+|-------- rightIdx |int|文件变更之后所在行数|
+
+> 返回的JSON示例:
+
+```json
+{
+ "commits_count": 1,
+ "commits": [
+ {
+ "author": {
+ "id": 36480,
+ "login": "jasder",
+ "name": "段甲生",
+ "image_url": "avatars/User/b"
+ },
+ "committer": {
+ "id": 36480,
+ "login": "jasder",
+ "name": "段甲生",
+ "image_url": "avatars/User/b"
+ },
+ "timestamp": 1604382982,
+ "time_from_now": "4小时前",
+ "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n",
+ "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968"
+ }
+ ],
+ "diff": {
+ "files_count": 6,
+ "total_addition": 447,
+ "total_deletion": 0,
+ "files": [
+ {
+ "name": "build.go",
+ "old_name": "build.go",
+ "index": 1,
+ "addition": 33,
+ "deletion": 0,
+ "type": 1,
+ "isCreated": true,
+ "isDeleted": false,
+ "isBin": false,
+ "isLFSFile": false,
+ "isRenamed": false,
+ "isSubmodule": false,
+ "sections": [
+ {
+ "fileName": "build.go",
+ "name": "",
+ "lines": [
+ {
+ "leftIdx": 0,
+ "rightIdx": 0,
+ "type": 4,
+ "content": "@@ -0,0 +1,33 @@",
+ "sectionInfo": {
+ "path": "build.go",
+ "lastLeftIdx": 0,
+ "lastRightIdx": 0,
+ "leftIdx": 0,
+ "rightIdx": 1,
+ "leftHunkSize": 0,
+ "rightHunkSize": 33
+ }
+ },
+ {
+ "leftIdx": 0,
+ "rightIdx": 1,
+ "type": 2,
+ "content": "+// Copyright 2020 The Gitea Authors. All rights reserved.",
+ "sectionInfo": null
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+```
+
+
+## List pull requests
+获取合并请求列表
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/Jasder/gitlink/pulls.json
+```
+
+```javascript
+await octokit.request('GET /api/Jasder/gitlink/pulls.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/pulls.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+
+
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "响应成功",
+ "open_count": 4,
+ "close_count": 51,
+ "merged_issues_size": 123,
+ "search_count": 4,
+ "limit": null,
+ "user_admin_or_member": true,
+ "user_admin_or_developer": true,
+ "project_name": "Gitlink",
+ "project_author_name": "Gitlink",
+ "issues": [
+ {
+ "pull_request_id": 1189,
+ "pull_request_status": 0,
+ "pull_request_head": "develop",
+ "pull_request_base": "master",
+ "pull_request_staus": "open",
+ "is_original": false,
+ "fork_project_id": null,
+ "fork_project_identifier": null,
+ "fork_project_user": null,
+ "id": 51888,
+ "name": "FIx release v3.2.0",
+ "pr_time": "59分钟前",
+ "assign_user_name": "victor",
+ "assign_user_login": "moshenglv",
+ "author_name": "段甲生",
+ "author_login": "jasder",
+ "avatar_url": "images/avatars/User/36480?t=1615520120",
+ "priority": "正常",
+ "version": null,
+ "journals_count": 0,
+ "issue_tags": null
+ }
+ ]
+}
+```
\ No newline at end of file
diff --git a/app/docs/slate/source/includes/_repositories.md b/app/docs/slate/source/includes/_repositories.md
index 40d3ba2ff..3604689c8 100644
--- a/app/docs/slate/source/includes/_repositories.md
+++ b/app/docs/slate/source/includes/_repositories.md
@@ -274,6 +274,124 @@ await octokit.request('GET /api/yystopf/ceshi/detail.json')
}
```
+## 仓库标签列表
+仓库标签列表
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/yystopf/csfjkkj/tags.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/csfjkkj/tags.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/tags.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|page |否| 1 | integer | 页码 |
+|limit |否| 20| integer | 每页个数 |
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|id |int |标签id |
+|name |string|标签名称|
+|zipball_url |string|标签zip包下载地址|
+|tarball_url |string|标签tar包下载地址|
+|tagger |object|打标签的人|
+|time_ago |string|打标签的时间|
+|created_at_unix|string|打标签的时间戳|
+|message |string|标签信息|
+|commit |object|标签最后一个commit|
+|commit.sha |string|commit的id|
+|commit.message |string|commit的提交信息|
+|commit.time_ago|string|commit的提交时间|
+|commit.created_at_unix|string|commit的提交时间戳|
+|commit.committer|object|commit的提交者|
+|commit.author|object|commit的作者|
+
+
+> 返回的JSON示例:
+
+```json
+[
+ {
+ "name": "v2.0.0",
+ "id": "c7d0873ee41796d1a0e193063095ccf539a9bf31",
+ "zipball_url": "http://localhost:3000/api/yystopf/csfjkkj/archive/v2.0.0.zip",
+ "tarball_url": "http://localhost:3000/api/yystopf/csfjkkj/archive/v2.0.0.tar.gz",
+ "tagger": {
+ "id": 4,
+ "login": "testforge1",
+ "name": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ },
+ "time_ago": "1天前",
+ "created_at_unix": 1632376903,
+ "message": "jdfkls",
+ "commit": {
+ "sha": "08fe383f1e5ebe2e2a384a8ea3ee890a758c7cd7",
+ "message": "add\n",
+ "time_ago": "1天前",
+ "created_at_unix": 1632376186,
+ "committer": {
+ "id": 4,
+ "login": "testforge1",
+ "name": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ },
+ "author": {
+ "id": 4,
+ "login": "testforge1",
+ "name": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ }
+ }
+ },
+ {
+ "name": "v1.0.0",
+ "id": "12168ad39c3ef201a445a2db181a3e43d50e40dd",
+ "zipball_url": "http://localhost:3000/api/yystopf/csfjkkj/archive/v1.0.0.zip",
+ "tarball_url": "http://localhost:3000/api/yystopf/csfjkkj/archive/v1.0.0.tar.gz",
+ "tagger": {
+ "id": null,
+ "login": "viletyy",
+ "name": "viletyy",
+ "image_url": "system/lets/letter_avatars/2/V/39_141_222/120.png"
+ },
+ "time_ago": "10天前",
+ "created_at_unix": 1631588042,
+ "message": "dfks",
+ "commit": {
+ "sha": "5291b5e45a377c1f7710cc6647259887ed7aaccf",
+ "message": "ADD file via upload\n",
+ "time_ago": "21天前",
+ "created_at_unix": 1630648417,
+ "committer": {
+ "id": null,
+ "login": "yystopf",
+ "name": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
+ },
+ "author": {
+ "id": null,
+ "login": "yystopf",
+ "name": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
+ }
+ }
+ }
+]
+```
+
## 编辑仓库信息
编辑仓库信息
@@ -867,3 +985,796 @@ await octokit.request('GET /api/jasder/jasder_test/sub_entries.json')
+
+## 获取仓库README文件
+获取仓库README文件
+
+> 示例:
+
+```shell
+curl -X GET \
+-d "ref=master" \
+-d "filepath=lib" \
+http://localhost:3000/api/yystopf/csfjkkj/readme.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/csfjkkj/readme.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/readme.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|ref |否| | string |分支名称、tag名称或是提交记录id,默认为默认分支 |
+|filepath |否| | string |子目录名称,默认为空 |
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type |string|文件类型, file:文件,dir:文件目录
+|encoding |string |编码 |
+|size |int|文件夹或文件大小 单位B
+|name |string|文件夹或文件名称|
+|path |string|文件夹或文件相对路径|
+|content |string|文件内容
+|sha |string|文件commitid
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "type": "file",
+ "encoding": "base64",
+ "size": 24,
+ "name": "README.md",
+ "path": "lib/README.md",
+ "content": "ZGZhc2RhZGpmIGRrZnNsCgpzZGZkZnMK",
+ "sha": "860962cd21c60b1a9e07d723080c87c32c18d44a"
+}
+```
+
+
+## 获取仓库贡献者
+获取仓库贡献者
+
+> 示例:
+
+```shell
+curl -X GET \
+-d "ref=master" \
+-d "filepath=lib" \
+http://localhost:3000/api/yystopf/csfjkkj/contributors.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/csfjkkj/contributors.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/contributors.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|ref |否| | string |分支名称、tag名称或是提交记录id,默认为整个仓库 |
+|filepath |否| | string |子目录名称,默认为空 |
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|total_count |integer|贡献者数量|
+|contributions |integer|贡献数量|
+|login |string |用户登录名 |
+|type |string|用户类型 |
+|name |string|用户昵称|
+|image_url |string|用户头像|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "contributors": [
+ {
+ "contributions": 5,
+ "login": "testforge2",
+ "type": "User",
+ "name": "testforge2",
+ "image_url": "system/lets/letter_avatars/2/T/236_177_85/120.png"
+ },
+ {
+ "contributions": 79,
+ "login": "yystopf",
+ "type": "User",
+ "name": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
+ }
+ ],
+ "total_count": 2
+}
+```
+
+
+
+## 获取仓库webhooks列表
+获取仓库webhooks列表
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/yystopf/ceshi/webhooks.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/webhooks.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|id |int |id |
+|url |string|地址|
+|http_method |string|请求方式|
+|is_active |bool |是否激活|
+|type |string|类型|
+|last_status |string|最后一次推送的状态|
+|create_time |string|创建时间|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "total_count": 4,
+ "webhooks": [
+ {
+ "id": 2,
+ "url": "https://oapi.dingtalk.com/robot/send?access_token=7e1e19d0eddb6a5e33c5c2c4e66f4c88f9437184b9ed2c2653194c6374c7d513",
+ "http_method": "",
+ "is_active": true,
+ "type": "dingtalk",
+ "last_status": "succeed",
+ "create_time": "2021-07-12 10:50:07"
+ },
+ {
+ "id": 3,
+ "url": "http://localhost:3000",
+ "http_method": "GET",
+ "is_active": true,
+ "type": "gitea",
+ "last_status": "succeed",
+ "create_time": "2021-07-26 10:03:45"
+ },
+ {
+ "id": 4,
+ "url": "http://localhost:10081",
+ "http_method": "POST",
+ "is_active": true,
+ "type": "gitea",
+ "last_status": "waiting",
+ "create_time": "2021-07-26 16:56:53"
+ },
+ {
+ "id": 5,
+ "url": "http://localhost:3001",
+ "http_method": "POST",
+ "is_active": true,
+ "type": "gitea",
+ "last_status": "fail",
+ "create_time": "2021-07-26 16:58:23"
+ }
+ ]
+}
+```
+
+
+## 获取仓库单个webhook
+获取仓库单个webhook
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/webhooks/:id/edit.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|id |是||integer|webhook ID|
+
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|id |int |id |
+|url |string|地址|
+|content_type |string|POST Content Type|
+|http_method |string|请求方式|
+|secret| |string|密钥|
+|is_active |bool |是否激活|
+|type |string|类型|
+|last_status |string|最后一次推送的状态, waiting 等待,fail 失败,succeed 成功|
+|branch_filter |string|分支过滤|
+|events |string|触发条件|
+|create_time |string|创建时间|
+
+
+参数| 含义|
+--------- | ------- | ------- |
+|create|创建分支或标签|
+|delete|分支或标签删除|
+|fork|仓库被fork|
+|push|git仓库推送|
+|issue|易修已打开、已关闭、已重新打开或编辑|
+|issue_assign|易修被指派|
+|issue_label|易修标签被更新或删除|
+|issue_milestone|易修被收入里程碑|
+|issue_comment|易修评论|
+|pull_request|合并请求|
+|pull_request_assign|合并请求被指派|
+|pull_request_label|合并请求被贴上标签|
+|pull_request_milestone|合并请求被记录于里程碑中|
+|pull_request_comment|合并请求被评论|
+|pull_request_review_approved|合并请求被批准|
+|pull_request_review_rejected|合并请求被拒绝|
+|pull_request_review_comment|合并请求被提出审查意见|
+|pull_request_sync|合并请求被同步|
+|repository|创建或删除仓库|
+|release|版本发布|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "id": 3,
+ "http_method": "GET",
+ "content_type": "form",
+ "url": "http://localhost:3000",
+ "secret": "123456",
+ "last_status": "succeed",
+ "is_active": true,
+ "type": "gitea",
+ "create_time": "2021-07-26 10:03:45",
+ "branch_filter": "*",
+ "events": [
+ "create",
+ "delete",
+ "fork",
+ "issues",
+ "issue_assign",
+ "issue_label",
+ "issue_milestone",
+ "issue_comment",
+ "push",
+ "pull_request",
+ "pull_request_assign",
+ "pull_request_label",
+ "pull_request_milestone",
+ "pull_request_comment",
+ "pull_request_review",
+ "pull_request_sync",
+ "repository",
+ "release"
+ ]
+}
+```
+
+
+## 添加仓库webhook
+添加仓库webhook
+
+> 示例:
+
+```shell
+curl -X POST \
+http://localhost:3000/api/yystopf/ceshi/webhooks.json
+```
+
+```javascript
+await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
+```
+
+### HTTP 请求
+`POST /api/:owner/:repo/webhooks.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| | string |用户登录名 |
+|repo |是| | string |项目标识identifier |
+|webhook.url |是| | string |目标url |
+|webhook.type |否| | string |类型|
+|webhook.http_method |是| | string | http方法, POST和GET |
+|webhook.content_type |是| | string | POST Content Type |
+|webhook.secret |否| | string |密钥文本|
+|webhook.active |是| | bool | 是否激活|
+|webhook.branch_filter|否| |string|分支过滤|
+|webhook.events |否| |array|触发事件|
+
+触发事件字段说明
+
+参数| 含义|
+--------- | ------- | ------- |
+|create|创建分支或标签|
+|delete|分支或标签删除|
+|fork|仓库被fork|
+|push|git仓库推送|
+|issue|易修已打开、已关闭、已重新打开或编辑|
+|issue_assign|易修被指派|
+|issue_label|易修标签被更新或删除|
+|issue_milestone|易修被收入里程碑|
+|issue_comment|易修评论|
+|pull_request|合并请求|
+|pull_request_assign|合并请求被指派|
+|pull_request_label|合并请求被贴上标签|
+|pull_request_milestone|合并请求被记录于里程碑中|
+|pull_request_comment|合并请求被评论|
+|pull_request_review_approved|合并请求被批准|
+|pull_request_review_rejected|合并请求被拒绝|
+|pull_request_review_comment|合并请求被提出审查意见|
+|pull_request_sync|合并请求被同步|
+|repository|创建或删除仓库|
+|release|版本发布|
+
+
+> 请求的JSON示例:
+
+```json
+{
+ "active": true,
+ "content_type": "json",
+ "http_method": "GET",
+ "secret": "123456",
+ "url": "http://localhost:10000",
+ "branch_filter": "*",
+ "events": ["push"]
+}
+```
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|id |int |id |
+|url |string|地址|
+|content_type |string|POST Content Type|
+|is_active |bool |是否激活|
+|type |string|类型|
+|events | array|触发事件 |
+|create_time |string|创建时间|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "id": 18,
+ "type": "gitea",
+ "content_type": "json",
+ "url": "http://localhost:10000",
+ "events": [
+ "push"
+ ],
+ "active": true,
+ "create_time": "2021-07-26 18:53:43"
+}
+```
+
+
+## 更新仓库webhook
+更新仓库webhook
+
+> 示例:
+
+```shell
+curl -X PATCH \
+http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
+```
+
+```javascript
+await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
+```
+
+### HTTP 请求
+`PATCH /api/:owner/:repo/webhooks/:id.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| | string |用户登录名 |
+|repo |是| | string |项目标识identifier |
+|id |是| | string |webhook id |
+|webhook.url |是| | string |目标url |
+|webhook.type |否| | string |类型|
+|webhook.http_method |是| | string | http方法, POST和GET |
+|webhook.content_type |是| | string | POST Content Type |
+|webhook.secret |否| | string |密钥文本|
+|webhook.active |是| | bool | 是否激活|
+|webhook.branch_filter|否| |string|分支过滤|
+|webhook.events |否| |array|触发事件|
+
+触发事件字段说明
+
+参数| 含义|
+--------- | ------- | ------- |
+|create|创建分支或标签|
+|delete|分支或标签删除|
+|fork|仓库被fork|
+|push|git仓库推送|
+|issue|易修已打开、已关闭、已重新打开或编辑|
+|issue_assign|易修被指派|
+|issue_label|易修标签被更新或删除|
+|issue_milestone|易修被收入里程碑|
+|issue_comment|易修评论|
+|pull_request|合并请求|
+|pull_request_assign|合并请求被指派|
+|pull_request_label|合并请求被贴上标签|
+|pull_request_milestone|合并请求被记录于里程碑中|
+|pull_request_comment|合并请求被评论|
+|pull_request_review_approved|合并请求被批准|
+|pull_request_review_rejected|合并请求被拒绝|
+|pull_request_review_comment|合并请求被提出审查意见|
+|pull_request_sync|合并请求被同步|
+|repository|创建或删除仓库|
+|release|版本发布|
+
+
+> 请求的JSON示例:
+
+```json
+{
+ "active": true,
+ "content_type": "json",
+ "http_method": "GET",
+ "secret": "123456",
+ "url": "http://localhost:10000",
+ "branch_filter": "*",
+ "events": ["push"]
+}
+```
+
+### 返回字段说明:
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+
+## 删除仓库webhook
+删除仓库webhook
+
+> 示例:
+
+```shell
+curl -X DELETE \
+http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
+```
+
+```javascript
+await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json')
+```
+
+### HTTP 请求
+`DELETE /api/:owner/:repo/webhooks/:id.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| | string |用户登录名 |
+|repo |是| | string |项目标识identifier |
+|id |是| | string |webhook id |
+
+### 返回字段说明:
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+## 获取仓库webhook的历史推送列表
+获取仓库webhook的历史推送列表
+
+> 示例:
+
+```shell
+curl -X GET \
+http://localhost:3000/api/yystopf/ceshi/webhooks/3/tasks.json
+```
+
+```javascript
+await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
+```
+
+### HTTP 请求
+`GET /api/:owner/:repo/webhooks/:id/tasks.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| |string |用户登录名 |
+|repo |是| |string |项目标识identifier |
+|id |是| |integer |webhook ID|
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|id |int |id |
+|uuid |string|推送uuid|
+|type |string|类型|
+|is_succeed |bool|是否推送成功|
+|is_delivered |bool|是否完成推送|
+|payload_content |json|请求主体内容|
+|request_content |json|请求内容,头部等等|
+|reponse_content |json|响应内容,状态,头部,主体等等|
+|delivered_time |string|推送时间|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "total_count": 6,
+ "tasks": [
+ {
+ "id": 20,
+ "type": "gitea",
+ "uuid": "99aa2c23-6884-4c44-9020-5469320aa408",
+ "is_succeed": true,
+ "is_delivered": true,
+ "payload_content": {
+ "secret": "123456",
+ "ref": "refs/heads/master",
+ "before": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
+ "after": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
+ "compare_url": "",
+ "commits": [
+ {
+ "id": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
+ "message": "fix\n",
+ "url": "http://localhost:10081/yystopf/ceshi/commit/feb48e31362787a7620b53d4df3c4effddbb6f0b",
+ "author": {
+ "name": "viletyy",
+ "email": "yystopf@163.com",
+ "username": "root"
+ },
+ "committer": {
+ "name": "viletyy",
+ "email": "yystopf@163.com",
+ "username": "root"
+ },
+ "verification": {
+ "verified": false,
+ "reason": "gpg.error.not_signed_commit",
+ "signature": "",
+ "signer": null,
+ "payload": ""
+ },
+ "timestamp": "2021-07-26T13:52:13+08:00",
+ "added": null,
+ "removed": null,
+ "modified": null
+ }
+ ],
+ "head_commit": null,
+ "repository": {
+ "id": 2,
+ "owner": {
+ "id": 3,
+ "login": "yystopf",
+ "full_name": "",
+ "email": "yystopf@forge.com",
+ "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
+ "language": "zh-CN",
+ "is_admin": true,
+ "last_login": "2021-07-21T18:38:21+08:00",
+ "created": "2021-06-03T14:50:25+08:00",
+ "username": "yystopf"
+ },
+ "name": "ceshi",
+ "full_name": "yystopf/ceshi",
+ "description": "",
+ "empty": false,
+ "private": false,
+ "fork": false,
+ "template": false,
+ "parent": null,
+ "mirror": false,
+ "size": 3846,
+ "html_url": "http://localhost:10081/yystopf/ceshi",
+ "ssh_url": "virus@localhost:10081:yystopf/ceshi.git",
+ "clone_url": "http://localhost:10081/yystopf/ceshi.git",
+ "original_url": "",
+ "website": "",
+ "stars_count": 0,
+ "forks_count": 1,
+ "watchers_count": 1,
+ "open_issues_count": 0,
+ "open_pr_counter": 0,
+ "release_counter": 0,
+ "default_branch": "master",
+ "archived": false,
+ "created_at": "2021-06-03T15:15:30+08:00",
+ "updated_at": "2021-07-26T13:52:16+08:00",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": false
+ },
+ "has_issues": true,
+ "internal_tracker": {
+ "enable_time_tracker": true,
+ "allow_only_contributors_to_track_time": true,
+ "enable_issue_dependencies": true
+ },
+ "has_wiki": true,
+ "has_pull_requests": true,
+ "ignore_whitespace_conflicts": false,
+ "allow_merge_commits": true,
+ "allow_rebase": true,
+ "allow_rebase_explicit": true,
+ "allow_squash_merge": true,
+ "avatar_url": "",
+ "internal": false
+ },
+ "pusher": {
+ "id": 0,
+ "login": "yystopf",
+ "full_name": "",
+ "email": "yystopf@forge.com",
+ "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
+ "language": "",
+ "is_admin": false,
+ "last_login": "0001-01-01T00:00:00Z",
+ "created": "2021-06-03T14:50:25+08:00",
+ "username": "yystopf"
+ },
+ "sender": {
+ "id": 0,
+ "login": "yystopf",
+ "full_name": "",
+ "email": "yystopf@forge.com",
+ "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
+ "language": "",
+ "is_admin": false,
+ "last_login": "0001-01-01T00:00:00Z",
+ "created": "2021-06-03T14:50:25+08:00",
+ "username": "yystopf"
+ }
+ },
+ "request_content": {
+ "headers": {
+ "X-GitHub-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
+ "X-GitHub-Event": "push",
+ "X-Gitea-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
+ "X-Gitea-Event": "push",
+ "X-Gitea-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66",
+ "X-Gogs-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
+ "X-Gogs-Event": "push",
+ "X-Gogs-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66"
+ }
+ },
+ "response_content": {
+ "status": 200,
+ "headers": {
+ "Cache-Control": "no-store, must-revalidate, private, max-age=0",
+ "Content-Length": "2556",
+ "Content-Type": "text/html; charset=utf-8",
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+ "Set-Cookie": "__profilin=p%3Dt; path=/; HttpOnly",
+ "Vary": "Origin",
+ "X-Content-Type-Options": "nosniff",
+ "X-Download-Options": "noopen",
+ "X-Frame-Options": "SAMEORIGIN",
+ "X-Miniprofiler-Ids": "9ynvpncz5xm0rpgorb5y,hgggd9mv6lr4a9drcrlr,j7zqlx2vy5aji2vtgoba,f1ktsmh3jxvq0z2hf612,mih3dvgvlqhi3zy8lf2x,5k1qbkvbnru8mye9cest,tj6ern8w6awqf2zsimbr,9isaehvubivd52wo5p9v,1rzfhtq1nhuwbgy9p76g,z0xzidzyywna0y7a69m0,hzoklky92ycjqt42gi0s,y0ai7y0t28mcn8x0py2x,322il7nadinp51mw2r5m,m6dukftfsh6tjcxzp1gq,667wlqbytfwbrirnmma1,jcehj3dl8lkw8gk510cr",
+ "X-Miniprofiler-Original-Cache-Control": "max-age=0, private, must-revalidate",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Request-Id": "08bff080-bbb5-4183-b845-81de3d47120a",
+ "X-Runtime": "0.394766",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "body": "
\n"
+ },
+ "delivered_time": "2021-07-28 11:47:29"
+ }
+ ]
+}
+```
+
+
+## 仓库webhook测试推送
+仓库webhook测试推送
+
+> 示例:
+
+```shell
+curl -X POST \
+http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json
+```
+
+```javascript
+await octokit.request('POST /api/yystopf/ceshi/webhooks/3/test.json')
+```
+
+### HTTP 请求
+`POST /api/:owner/:repo/webhooks/:id/test.json`
+
+### 请求参数:
+参数 | 必选 | 默认 | 类型 | 字段说明
+--------- | ------- | ------- | -------- | ----------
+|owner |是| | string |用户登录名 |
+|repo |是| | string |项目标识identifier |
+|id |是| | integer|webhook ID|
+
+
+
+
+### 返回字段说明:
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
\ No newline at end of file
diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md
index bb4fd2b66..218a1a4b7 100644
--- a/app/docs/slate/source/includes/_users.md
+++ b/app/docs/slate/source/includes/_users.md
@@ -1,7 +1,7 @@
# Users
@@ -47,6 +47,305 @@ await octokit.request('GET /api/users/me.json')
Success Data.
+## 用户消息列表
+获取用户消息列表
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('GET /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`GET api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,不传为所有消息,notification为系统消息,atme为@我消息|
+|status | integer | 是否已读,不传为所有消息,1为未读,2为已读 |
+|limit | integer | 每页个数 |
+|page | integer | 页码 |
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|total_count | integer | 消息总数 |
+|type | string | 消息类型 |
+|unread_notification | integer | 未读系统通知数量 |
+|unread_atme | integer | 未读@我数量 |
+|messages.id | integer | 消息id |
+|messages.status | integer | 消息是否已读,1为未读,2为已读 |
+|messages.content | string | 消息内容 |
+|messages.notification_url | string | 消息跳转地址 |
+|messages.source | string | 消息来源 |
+|messages.timeago | string | 消息时间 |
+|messages.type | string | 消息类型,notification为系统消息,atme为@我消息|
+|sender | object | 消息发送者 |
+
+#### 消息来源source字段说明
+类型|说明
+--------- | -----------
+|IssueAssigned | 有新指派给我的易修 |
+|IssueAssignerExpire | 我负责的易修截止日期到达最后一天 |
+|IssueAtme | 在易修中@我 |
+|IssueChanged | 我创建或负责的易修状态变更 |
+|IssueCreatorExpire | 我创建的易修截止日期到达最后一天 |
+|IssueDeleted | 我创建或负责的易修删除 |
+|IssueJournal | 我创建或负责的易修有新的评论 |
+|LoginIpTip | 登录异常提示 |
+|OrganizationJoined | 账号被拉入组织 |
+|OrganizationLeft | 账号被移出组织 |
+|OrganizationRole | 账号组织权限变更 |
+|ProjectDeleted | 我关注的仓库被删除 |
+|ProjectFollowed | 我管理的仓库被关注 |
+|ProjectForked | 我管理的仓库被复刻 |
+|ProjectIssue | 我管理/关注的仓库有新的易修 |
+|ProjectJoined | 账号被拉入项目 |
+|ProjectLeft | 账号被移出项目 |
+|ProjectMemberJoined | 我管理的仓库有成员加入 |
+|ProjectMemberLeft | 我管理的仓库有成员移出 |
+|ProjectMilestone | 我管理的仓库有新的里程碑 |
+|ProjectPraised | 我管理的仓库被点赞 |
+|ProjectPullRequest | 我管理/关注的仓库有新的合并请求 |
+|ProjectRole | 账号仓库权限变更 |
+|ProjectSettingChanged | 我管理的仓库项目设置被更改 |
+|ProjectTransfer | 我关注的仓库被转移 |
+|ProjectVersion | 我关注的仓库有新的发行版 |
+|PullRequestAssigned | 有新指派给我的合并请求 |
+|PullReuqestAtme | 在合并请求中@我 |
+|PullRequestChanged | 我创建或负责的合并请求状态变更 |
+|PullRequestClosed | 我创建或负责的合并请求被关闭 |
+|PullRequestJournal | 我创建或负责的合并请求有新的评论 |
+|PullRequestMerged | 我创建或负责的合并请求被合并 |
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "total_count": 5,
+ "type": "",
+ "unread_notification": 3,
+ "unread_atme": 2,
+ "messages": [
+ {
+ "id": 1,
+ "status": 1,
+ "content": "Atme Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "PullRequestAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 5,
+ "type": "User",
+ "name": "testforge2",
+ "login": "testforge2",
+ "image_url": "system/lets/letter_avatars/2/T/236_177_85/120.png"
+ }
+ },
+ {
+ "id": 2,
+ "status": 0,
+ "content": "Atme Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 4,
+ "type": "User",
+ "name": "testforge1",
+ "login": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ }
+ },
+ {
+ "id": 3,
+ "status": 1,
+ "content": "Notification Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueDelete",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 4,
+ "status": 0,
+ "content": "Notification Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueChanged",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 5,
+ "status": 0,
+ "content": "Notification Message Content 3",
+ "notification_url": "http://www.baidu.com",
+ "source": "ProjectJoined",
+ "time_ago": "1天前",
+ "type": "notification"
+ }
+ ]
+}
+```
+
+
+## 用户阅读系统通知
+用户阅读系统通知
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/yystopf/system_notification_histories.json
+```
+
+```javascript
+await octokit.request('GET /api/users/:login/system_notification_histories.json')
+```
+
+### HTTP 请求
+`POST /api/users/:login/system_notification_histories.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|system_notification_id |integer |阅读的系统通知id |
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+## 发送消息
+发送消息, 目前只支持atme
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('POST /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`POST api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型 |
+|receivers_login | array | 需要发送消息的用户名数组|
+|atmeable_type | string | atme消息对象,是从哪里@我的,比如评论:Journal、易修:Issue、合并请求:PullRequest |
+|atmeable_id | integer | atme消息对象id |
+
+> 请求的JSON示例:
+
+```json
+{
+ "type": "atme",
+ "receivers_login": ["yystopf", "testforge1"],
+ "atmeable_type": "Journal",
+ "atmeable_id": 67
+}
+```
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+## 阅读消息
+阅读消息
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/:login/messages/read.json
+```
+
+```javascript
+await octokit.request('POST /api/users/:login/messages/read.json')
+```
+
+### HTTP 请求
+`POST api/users/yystopf/messages/read.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,不传为所有消息,notification为系统消息,atme为@我消息|
+|ids | array | 消息id数组,包含-1则把所有未读消息标记为已读|
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+## 删除消息
+删除消息
+
+> 示例:
+
+```shell
+curl -X DELETE http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('DELETE /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`DELETE api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,atme为@我消息|
+|ids | array | 消息id数组,包含-1则把所有消息删除|
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+
## 更改用户信息
更改用户信息
@@ -103,6 +402,290 @@ await octokit.request('PATCH/PUT /api/users/:login.json')
"message": "success"
}
```
+
+## 获取平台消息设置配置信息
+获取平台消息设置配置信息
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/template_message_settings.json
+```
+
+```javascript
+await octokit.request('GET /api/template_message_settings.json')
+```
+
+### HTTP 请求
+`GET /api/template_message_settings.json`
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type |string |消息配置类型 |
+|type_name |string |消息配置类型含义|
+|total_settings_count |int |配置条数|
+|settings.name |string |配置名称|
+|settings.key |string |配置标识|
+|settings.notification_disabled |boolean |站内信设置是否禁用|
+|settings.email_disabled |boolean |邮件设置是否禁用|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "响应成功",
+ "setting_types": [
+ {
+ "type": "TemplateMessageSetting::Normal",
+ "type_name": "",
+ "total_settings_count": 3,
+ "settings": [
+ {
+ "name": "被拉入或移出组织",
+ "key": "Organization",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "被拉入或移出项目",
+ "key": "Project",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "有权限变更",
+ "key": "Permission",
+ "notification_disabled": true,
+ "email_disabled": false
+ }
+ ]
+ },
+ {
+ "type": "TemplateMessageSetting::CreateOrAssign",
+ "type_name": "我创建的或负责的",
+ "total_settings_count": 4,
+ "settings": [
+ {
+ "name": "易修被指派",
+ "key": "IssueAssigned",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "合并请求被指派",
+ "key": "PullRequestAssigned",
+ "notification_disabled": true,
+ "email_disabled": false
+ }
+ ]
+ },
+ {
+ "type": "TemplateMessageSetting::ManageProject",
+ "type_name": "我管理的仓库",
+ "total_settings_count": 4,
+ "settings": [
+ {
+ "name": "有新的易修",
+ "key": "Issue",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "有新的合并请求",
+ "key": "PullRequest",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "有成员变动",
+ "key": "Member",
+ "notification_disabled": true,
+ "email_disabled": false
+ },
+ {
+ "name": "设置更改",
+ "key": "SettingChanged",
+ "notification_disabled": true,
+ "email_disabled": false
+ }
+ ]
+ }
+ ]
+}
+```
+
+
+## 获取用户消息设置配置信息
+获取用户消息设置配置信息
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/users/yystopf/template_message_settings.json
+```
+
+```javascript
+await octokit.request('GET /api/uses/yystopf/template_message_settings.json')
+```
+
+### HTTP 请求
+`GET /api/users/:user_id/template_message_settings.json`
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|notification_body |string |站内信配置 |
+|email_body |string |邮件配置|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "响应成功",
+ "user": {
+ "id": 2,
+ "type": "User",
+ "name": "heh",
+ "login": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
+ },
+ "notification_body": {
+ "CreateOrAssign::IssueAssigned": true,
+ "CreateOrAssign::PullRequestAssigned": true,
+ "ManageProject::Issue": true,
+ "ManageProject::PullRequest": true,
+ "ManageProject::Member": true,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": true,
+ "Normal::Project": true,
+ "Normal::Permission": true
+ },
+ "email_body": {
+ "CreateOrAssign::IssueAssigned": false,
+ "CreateOrAssign::PullRequestAssigned": false,
+ "ManageProject::Issue": false,
+ "ManageProject::PullRequest": false,
+ "ManageProject::Member": false,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": false,
+ "Normal::Project": true,
+ "Normal::Permission": false
+ }
+}
+```
+
+
+## 重新设置用户消息设置配置信息
+重新设置用户消息设置配置信息
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/yystopf/template_message_settings/update_setting.json
+```
+
+```javascript
+await octokit.request('POST /api/uses/yystopf/template_message_settings/update_setting.json')
+```
+
+### HTTP 请求
+`POST /api/users/:user_id/template_message_settings/update_setting.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|notification_body |string |站内信配置 |
+|email_body |string |邮件配置|
+
+
+> 请求的JSON示例:
+
+```json
+{
+ "setting": {
+ "notification_body": {
+ "CreateOrAssign::IssueAssigned": true,
+ "CreateOrAssign::PullRequestAssigned": true,
+ "ManageProject::Issue": true,
+ "ManageProject::PullRequest": true,
+ "ManageProject::Member": true,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": true,
+ "Normal::Project": true,
+ "Normal::Permission": true
+ },
+ "email_body": {
+ "CreateOrAssign::IssueAssigned": false,
+ "CreateOrAssign::PullRequestAssigned": false,
+ "ManageProject::Issue": false,
+ "ManageProject::PullRequest": false,
+ "ManageProject::Member": false,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": false,
+ "Normal::Project": "t",
+ "Normal::Permission": false
+ }
+ }
+}
+```
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|notification_body |string |站内信配置 |
+|email_body |string |邮件配置|
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "响应成功",
+ "user": {
+ "id": 2,
+ "type": "User",
+ "name": "heh",
+ "login": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
+ },
+ "notification_body": {
+ "CreateOrAssign::IssueAssigned": true,
+ "CreateOrAssign::PullRequestAssigned": true,
+ "ManageProject::Issue": true,
+ "ManageProject::PullRequest": true,
+ "ManageProject::Member": true,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": true,
+ "Normal::Project": true,
+ "Normal::Permission": true
+ },
+ "email_body": {
+ "CreateOrAssign::IssueAssigned": false,
+ "CreateOrAssign::PullRequestAssigned": false,
+ "ManageProject::Issue": false,
+ "ManageProject::PullRequest": false,
+ "ManageProject::Member": false,
+ "ManageProject::SettingChanged": true,
+ "Normal::Organization": false,
+ "Normal::Project": true,
+ "Normal::Permission": false
+ }
+}
+```
+
+
## 获取用户星标项目
获取用户星标项目
diff --git a/app/forms/add_school_apply_form.rb b/app/forms/add_school_apply_form.rb
deleted file mode 100644
index f98e8b05b..000000000
--- a/app/forms/add_school_apply_form.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class AddSchoolApplyForm
- include ActiveModel::Model
-
- attr_accessor :name, :province, :city, :address, :remarks
-
- validates :name, presence: true
- # validates :province, presence: true
- # validates :city, presence: true
- # validates :address, presence: true
-end
\ No newline at end of file
diff --git a/app/forms/apply_shixun_mirror_form.rb b/app/forms/apply_shixun_mirror_form.rb
deleted file mode 100644
index 4f6b738e2..000000000
--- a/app/forms/apply_shixun_mirror_form.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class ApplyShixunMirrorForm
- include ActiveModel::Model
-
- attr_accessor :language, :runtime, :run_method, :attachment_id
-
- validates :language, presence: true
- validates :runtime, presence: true
- validates :run_method, presence: true
- validates :attachment_id, presence: true, numericality: { only_integer: true }
-
- validate :ensure_attachment_presence
- def ensure_attachment_presence
- return unless attachment_id
-
- if attachment.blank?
- errors.add(:attachment_id, :attachment_not_exist)
- end
- end
-
- def attachment
- @attachment ||= Attachment.find_by_id(attachment_id)
- end
-
- def to_json
- { language: language, runtime: runtime, run_method: run_method, attachment_id: attachment_id }.to_json
- end
-end
\ No newline at end of file
diff --git a/app/forms/base_form.rb b/app/forms/base_form.rb
index 015332d82..437217f00 100644
--- a/app/forms/base_form.rb
+++ b/app/forms/base_form.rb
@@ -2,18 +2,32 @@ class BaseForm
include ActiveModel::Model
def check_project_category(project_category_id)
- raise "project_category_id参数值无效." if (ProjectCategory.find_by_id project_category_id).blank?
+ unless project_category_id == ''
+ raise "project_category_id参数值无效." if project_category_id && !ProjectCategory.exists?(project_category_id)
+ end
end
def check_project_language(project_language_id)
- raise "project_language_id参数值无效." if (ProjectLanguage.find_by_id project_language_id).blank?
+ unless project_language_id == ''
+ raise "project_language_id参数值无效." if project_language_id && !ProjectLanguage.exists?(project_language_id)
+ end
end
def check_repository_name(user_id, repository_name)
- raise "仓库名称已被使用." if Repository.where(user_id: user_id, identifier: repository_name.strip).exists?
+ check_reversed_keyword(repository_name)
+ raise "项目标识已被使用." if Repository.where(user_id: user_id, identifier: repository_name.strip).exists?
end
def check_project_name(user_id, project_name)
raise "项目名称已被使用." if Project.where(user_id: user_id, name: project_name.strip).exists?
end
+
+ def check_reversed_keyword(repository_name)
+ raise "项目标识已被占用." if ReversedKeyword.check_exists?(repository_name)
+ end
+
+ private
+ def strip(str)
+ str.to_s.strip.presence
+ end
end
diff --git a/app/forms/examination_banks/save_exam_form.rb b/app/forms/examination_banks/save_exam_form.rb
deleted file mode 100644
index d066300be..000000000
--- a/app/forms/examination_banks/save_exam_form.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class ExaminationBanks::SaveExamForm
- include ActiveModel::Model
-
- attr_accessor :discipline_id, :sub_discipline_id, :difficulty, :name, :duration, :tag_discipline_id
-
- validates :discipline_id, presence: true
- validates :sub_discipline_id, presence: true
- validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
- validates :name, presence: true, length: { maximum: 60, too_long: "不能超过60个字符" }
- validate :validate_duration
-
- def validate_duration
- raise '时长应为大于0的整数' if duration.present? && duration.to_i < 1
- end
-end
\ No newline at end of file
diff --git a/app/forms/examination_intelligent_settings/save_exam_form.rb b/app/forms/examination_intelligent_settings/save_exam_form.rb
deleted file mode 100644
index ec4f17ad7..000000000
--- a/app/forms/examination_intelligent_settings/save_exam_form.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class ExaminationIntelligentSettings::SaveExamForm
- include ActiveModel::Model
-
- attr_accessor :name, :duration
-
- validates :name, presence: true, length: { maximum: 60 }
- validate :validate_duration
-
- def validate_duration
- raise '时长应为大于0的整数' if duration.present? && duration.to_i < 1
- end
-end
\ No newline at end of file
diff --git a/app/forms/examination_intelligent_settings/save_exam_setting_form.rb b/app/forms/examination_intelligent_settings/save_exam_setting_form.rb
deleted file mode 100644
index bbfb9eee8..000000000
--- a/app/forms/examination_intelligent_settings/save_exam_setting_form.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class ExaminationIntelligentSettings::SaveExamSettingForm
- include ActiveModel::Model
-
- attr_accessor :discipline_id, :sub_discipline_id, :source, :difficulty, :tag_discipline_id, :question_settings
-
- validates :discipline_id, presence: true
- validates :sub_discipline_id, presence: true
- validates :source, presence: true
- validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
- validates :question_settings, presence: true
-end
\ No newline at end of file
diff --git a/app/forms/issues/create_form.rb b/app/forms/issues/create_form.rb
index 7dde8ecda..602775ff4 100644
--- a/app/forms/issues/create_form.rb
+++ b/app/forms/issues/create_form.rb
@@ -5,7 +5,7 @@ class Issues::CreateForm
validates :subject, presence: { message: "不能为空" }
- validates :subject, length: { maximum: 80, too_long: "不能超过80个字符" }
+ validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
end
diff --git a/app/forms/issues/update_form.rb b/app/forms/issues/update_form.rb
index 7447c8cc0..64acdfb5c 100644
--- a/app/forms/issues/update_form.rb
+++ b/app/forms/issues/update_form.rb
@@ -5,6 +5,6 @@ class Issues::UpdateForm
validates :subject, presence: { message: "不能为空" }
- validates :subject, length: { maximum: 80, too_long: "不能超过80个字符" }
+ validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
end
\ No newline at end of file
diff --git a/app/forms/notice/write/create_atme_form.rb b/app/forms/notice/write/create_atme_form.rb
new file mode 100644
index 000000000..5ac3acc25
--- /dev/null
+++ b/app/forms/notice/write/create_atme_form.rb
@@ -0,0 +1,23 @@
+class Notice::Write::CreateAtmeForm
+ include ActiveModel::Model
+
+ attr_accessor :receivers_login, :atmeable_type, :atmeable_id
+
+ validate :check_receivers
+
+ def check_receivers
+ receivers_login.each do |login|
+ receiver = User.find_by(login: login) || User.find_by_id(login)
+ raise 'receivers_login值无效.' unless receiver.present?
+ end
+ end
+
+ def check_atmeable
+ begin
+ raise 'atmeable对象无效.' unless atmeable_type.constantize.find_by_id(atmeable_id).present?
+ rescue => exception
+ raise 'atmeable对象无效.'
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/forms/projects/create_form.rb b/app/forms/projects/create_form.rb
index 0b57f215b..c51c2c60f 100644
--- a/app/forms/projects/create_form.rb
+++ b/app/forms/projects/create_form.rb
@@ -1,11 +1,9 @@
class Projects::CreateForm < BaseForm
- REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
attr_accessor :user_id, :name, :description, :repository_name, :project_category_id,
:project_language_id, :ignore_id, :license_id, :private, :owner
- validates :user_id, :name, :description,:repository_name,
- :project_category_id, :project_language_id, presence: true
- validates :repository_name, format: { with: REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
+ validates :user_id, :name, :repository_name, presence: true
+ validates :repository_name, format: { with: CustomRegexp::REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
validates :name, length: { maximum: 50 }
validates :repository_name, length: { maximum: 100 }
@@ -15,6 +13,8 @@ class Projects::CreateForm < BaseForm
validate do
check_project_category(project_category_id)
check_project_language(project_language_id)
+ check_project_name(user_id, name) unless name.blank?
+ check_repository_name(user_id, repository_name) unless repository_name.blank?
end
def check_license
@@ -26,13 +26,14 @@ class Projects::CreateForm < BaseForm
end
def check_owner
- @owner = Owner.find_by(id: user_id)
- raise "user_id值无效." if user_id && owner.blank?
+ @project_owner = Owner.find_by(id: user_id)
+ raise "user_id值无效." if user_id && @project_owner.blank?
end
def check_max_repo_creation
- return unless owner.is_a?(Organization)
- return if owner.max_repo_creation <= -1
- raise "已超过组织设置最大仓库数" if owner.max_repo_creation == owner.num_projects
+ return unless @project_owner.is_a?(Organization)
+ return if @project_owner.max_repo_creation <= -1
+
+ raise "已超过组织设置最大仓库数" if @project_owner.max_repo_creation == @project_owner.num_projects
end
end
diff --git a/app/forms/projects/migrate_form.rb b/app/forms/projects/migrate_form.rb
index 51116b2b5..ccd854478 100644
--- a/app/forms/projects/migrate_form.rb
+++ b/app/forms/projects/migrate_form.rb
@@ -1,12 +1,13 @@
class Projects::MigrateForm < BaseForm
- REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
- 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
+ attr_accessor :user_id, :name, :repository_name, :project_category_id, :description,
+ :project_language_id, :clone_addr, :private, :is_mirror, :auth_username, :auth_password, :owner
- attr_accessor :user_id, :name, :description, :repository_name, :project_category_id, :project_language_id, :clone_addr, :private, :is_mirror, :auth_username, :auth_password, :owner
-
- validates :user_id, :name, :description,:repository_name, :project_category_id, :project_language_id, presence: true
- validates :repository_name, format: { with: REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
- validates :clone_addr, format: { with: URL_REGEX, multiline: true, message: "地址格式不正确" }
+ validates :user_id, :name, :repository_name, :clone_addr, presence: true
+ validates :repository_name, format: { with: CustomRegexp::REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
+ validates :clone_addr, format: { with: CustomRegexp::URL_REGEX, multiline: true, message: "地址格式不正确" }
+ validates :name, length: { maximum: 50 }
+ validates :repository_name, length: { maximum: 100 }
+ validates :description, length: { maximum: 200 }
validate do
check_project_name(user_id, name) unless name.blank?
check_repository_name(user_id, repository_name) unless repository_name.blank?
diff --git a/app/forms/projects/update_form.rb b/app/forms/projects/update_form.rb
index 65810a820..3048bc079 100644
--- a/app/forms/projects/update_form.rb
+++ b/app/forms/projects/update_form.rb
@@ -1,11 +1,15 @@
class Projects::UpdateForm < BaseForm
- attr_accessor :name, :description, :project_category_id, :project_language_id, :private
- validates :name, :description, :project_category_id, :project_language_id, presence: true
+ attr_accessor :name, :description, :project_category_id, :project_language_id, :private, :identifier, :user_id, :project_identifier
+ validates :name, presence: true
validates :name, length: { maximum: 50 }
validates :description, length: { maximum: 200 }
+ validates :identifier, format: { with: CustomRegexp::REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
+
validate do
check_project_category(project_category_id)
check_project_language(project_language_id)
+
+ check_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier
end
end
diff --git a/app/forms/projects/webhooks/create_form.rb b/app/forms/projects/webhooks/create_form.rb
new file mode 100644
index 000000000..75b07b1bd
--- /dev/null
+++ b/app/forms/projects/webhooks/create_form.rb
@@ -0,0 +1,8 @@
+class Projects::Webhooks::CreateForm < BaseForm
+ attr_accessor :type, :url, :http_method, :content_type, :secret, :events, :active, :branch_filter
+
+ validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
+ validates :active, inclusion: {in: [true, false]}
+ validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
+ validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}
+end
\ No newline at end of file
diff --git a/app/forms/register/base_form.rb b/app/forms/register/base_form.rb
new file mode 100644
index 000000000..df5abd871
--- /dev/null
+++ b/app/forms/register/base_form.rb
@@ -0,0 +1,51 @@
+module Register
+ class BaseForm < ::BaseForm
+ include ActiveModel::Model
+
+ Error = Class.new(StandardError)
+ EmailError = Class.new(Error)
+ LoginError = Class.new(Error)
+ PhoneError = Class.new(Error)
+ PasswordFormatError = Class.new(Error)
+ VerifiCodeError = Class.new(Error)
+
+ private
+ def check_login(login)
+ login = strip(login)
+ raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN
+
+ login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login)
+ raise LoginError, '登录名已被使用' if login_exist
+ end
+
+ def check_mail(mail)
+ mail = strip(mail)
+ raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL
+
+ mail_exist = Owner.exists?(mail: mail)
+ raise EmailError, '邮箱已被使用' if mail_exist
+ end
+
+ def check_phone(phone)
+ phone = strip(phone)
+ raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE
+
+ phone_exist = Owner.exists?(phone: phone)
+ raise PhoneError, '手机号已被使用' if phone_exist
+ end
+
+ def check_password(password)
+ password = strip(password)
+ raise PasswordFormatError, "8~16位密码,支持字母数字和符号" unless password =~ CustomRegexp::PASSWORD
+ end
+
+ def check_verifi_code(verifi_code, code)
+ code = strip(code)
+ # return if code == "123123" # TODO 万能验证码,用于测试
+
+ raise VerifiCodeError, "验证码不正确" if verifi_code&.code != code
+ raise VerifiCodeError, "验证码已失效" if !verifi_code&.effective?
+ end
+
+ end
+end
diff --git a/app/forms/register/check_columns_form.rb b/app/forms/register/check_columns_form.rb
new file mode 100644
index 000000000..20c5b1e89
--- /dev/null
+++ b/app/forms/register/check_columns_form.rb
@@ -0,0 +1,19 @@
+module Register
+ class CheckColumnsForm < Register::BaseForm
+ attr_accessor :type, :value
+
+ validates :type, presence: true, numericality: true
+ validates :value, presence: true
+ validate :check!
+
+ def check!
+ # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号)
+ case strip(type).to_i
+ when 1 then check_login(strip(value))
+ when 2 then check_mail(strip(value))
+ when 3 then check_phone(strip(value))
+ else raise("type值无效")
+ end
+ end
+ end
+end
diff --git a/app/forms/register/form.rb b/app/forms/register/form.rb
new file mode 100644
index 000000000..bad7a23e6
--- /dev/null
+++ b/app/forms/register/form.rb
@@ -0,0 +1,27 @@
+module Register
+ class Form < Register::BaseForm
+ # login 登陆方式,支持邮箱、登陆、手机号等
+ # namespace 用户空间地址
+ # type: 1:手机号注册;2:邮箱注册
+ attr_accessor :login, :namespace, :password, :code, :type
+
+ validates :login, :code, :password, :namespace, presence: true
+ validate :check!
+
+ def check!
+ Rails.logger.info "Register::Form params: code: #{code}; login: #{login}; namespace: #{namespace}; password: #{password}; type: #{type}"
+ db_verifi_code =
+ if type == 1
+ check_phone(login)
+ VerificationCode.where(phone: login, code: code, code_type: 1).last
+ elsif type == 0
+ check_mail(login)
+ VerificationCode.where(email: login, code: code, code_type: 8).last
+ end
+
+ check_login(namespace)
+ check_verifi_code(db_verifi_code, code)
+ check_password(password)
+ end
+ end
+end
diff --git a/app/forms/weapps/create_course_form.rb b/app/forms/weapps/create_course_form.rb
deleted file mode 100644
index 64d0a506f..000000000
--- a/app/forms/weapps/create_course_form.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Weapps::CreateCourseForm
- include ActiveModel::Model
-
- attr_accessor :course
- attr_accessor :name, :course_list_name, :credit, :course_module_types, :end_date
-
- validates :name, presence: true
- validates :course_list_name, presence: true
-
- validate :course_name_prefix
- validate :check_course_modules
-
- def course_name_prefix
- raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0
- end
-
- def check_course_modules
- raise '请至少添加一个课堂模块' if course_module_types.blank?
- end
-end
\ No newline at end of file
diff --git a/app/forms/weapps/update_course_form.rb b/app/forms/weapps/update_course_form.rb
deleted file mode 100644
index 60509dd1d..000000000
--- a/app/forms/weapps/update_course_form.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class Weapps::UpdateCourseForm
- include ActiveModel::Model
-
- attr_accessor :course
- attr_accessor :name, :course_list_name, :credit, :end_date
-
- validates :name, presence: true
- validates :course_list_name, presence: true
-
- validate :course_name_prefix
-
- def course_name_prefix
- raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0
- end
-end
\ No newline at end of file
diff --git a/app/helpers/admins/projects_helper.rb b/app/helpers/admins/projects_helper.rb
index c6d94c4ca..36d9d6f5a 100644
--- a/app/helpers/admins/projects_helper.rb
+++ b/app/helpers/admins/projects_helper.rb
@@ -4,7 +4,7 @@ module Admins::ProjectsHelper
owner = project.owner
if owner.is_a?(User)
- link_to(project.owner&.real_name, "/users/#{project&.owner&.login}", target: '_blank')
+ link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank')
elsif owner.is_a?(Organization)
link_to(project.owner&.real_name, "/organize/#{project&.owner&.login}", target: '_blank')
else
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a1aea4aeb..f2a9f93b6 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,6 +1,6 @@
# 所有的方法请按首字母的顺序依次列出
module ApplicationHelper
- include Educoder::I18n
+ include Gitlink::I18n
include GitHelper
ONE_MINUTE = 60 * 1000
@@ -434,6 +434,22 @@ module ApplicationHelper
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
@@ -447,5 +463,11 @@ module ApplicationHelper
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
end
diff --git a/app/helpers/avatar_helper.rb b/app/helpers/avatar_helper.rb
new file mode 100644
index 000000000..b703e1b4e
--- /dev/null
+++ b/app/helpers/avatar_helper.rb
@@ -0,0 +1,26 @@
+module AvatarHelper
+ def relative_path
+ "avatars"
+ end
+
+ def storage_path
+ File.join(Rails.root, "public", "images", relative_path)
+ end
+
+ def disk_filename(source_type,source_id,image_file=nil)
+ File.join(storage_path, "#{source_type}", "#{source_id}")
+ end
+
+ 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
+end
\ No newline at end of file
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
deleted file mode 100644
index e66bdaf6b..000000000
--- a/app/helpers/boards_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module BoardsHelper
-end
diff --git a/app/helpers/challenges_helper.rb b/app/helpers/challenges_helper.rb
deleted file mode 100644
index fc0101dff..000000000
--- a/app/helpers/challenges_helper.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-module ChallengesHelper
-
- def match_begin_symbol str
- str.gsub(/\A\r/, "\r\r")
- end
-
-
-
-
-end
diff --git a/app/helpers/course_groups_helper.rb b/app/helpers/course_groups_helper.rb
deleted file mode 100644
index 061c39dd5..000000000
--- a/app/helpers/course_groups_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module CourseGroupsHelper
-end
diff --git a/app/helpers/course_modules_helper.rb b/app/helpers/course_modules_helper.rb
deleted file mode 100644
index 4de7a3826..000000000
--- a/app/helpers/course_modules_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module CourseModulesHelper
-end
diff --git a/app/helpers/course_second_categories_helper.rb b/app/helpers/course_second_categories_helper.rb
deleted file mode 100644
index 7ed9aa1e9..000000000
--- a/app/helpers/course_second_categories_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module CourseSecondCategoriesHelper
-end
diff --git a/app/helpers/course_stages_helper.rb b/app/helpers/course_stages_helper.rb
deleted file mode 100644
index 7ebb68d9a..000000000
--- a/app/helpers/course_stages_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module CourseStagesHelper
-end
diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb
deleted file mode 100644
index f0d58adbb..000000000
--- a/app/helpers/courses_helper.rb
+++ /dev/null
@@ -1,298 +0,0 @@
-module CoursesHelper
-
- def member_manager group, teachers
- str = ""
- members = teachers.select{|teacher| teacher.teacher_course_groups.pluck(:course_group_id).include?(group.id) || teacher.teacher_course_groups.size == 0}
- str = members.uniq.size == teachers.size ? "全部教师" : members.map{|member| member.user.real_name}.join("、")
- str
- # teachers.each do |member|
- # if member.teacher_course_groups.exists?(course_group_id: group.id) || member.teacher_course_groups.size == 0
- # str << member.user.real_name
- # end
- # end
- end
-
- def edit_auth group, teachers
- User.current.admin_or_business? ||
- teachers.select{|teacher| teacher.user_id == User.current.id &&
- (teacher.teacher_course_groups.pluck(:course_group_id).include?(group.id) || teacher.teacher_course_groups.size == 0)}.size > 0
- end
-
- # 是否有切换为学生的入口
- def switch_student_role is_teacher, course, user
- is_teacher && course.course_members.where(user_id: user.id, role: %i(STUDENT)).exists?
- end
-
- # 是否有切换为教师的入口
- def switch_teacher_role is_student, course, user
- is_student && course.course_members.where(user_id: user.id, role: %i(CREATOR PROFESSOR)).exists?
- end
-
- # 是否有切换为助教的入口
- def switch_assistant_role is_student, course, user
- is_student && course.course_members.where(user_id: user.id, role: %i(ASSISTANT_PROFESSOR)).exists?
- end
-
- # 课堂结束天数
- def course_end_date end_date
- if end_date.present?
- curr = Time.new
- date = ((Date.parse(end_date.to_s) - Date.parse(curr.to_s)).to_i)
- date > 0 ? "#{date}天后" : ""
- end
- end
-
- # 课堂模块的url
- def module_url mod, course
- return nil if mod.blank? or course.blank?
- case mod.module_type
- when "announcement"
- "/courses/#{course.id}/informs"
- when "online_learning"
- "/courses/#{course.id}/online_learning"
- when "shixun_homework"
- "/courses/#{course.id}/shixun_homeworks/#{mod.id}"
- when "common_homework"
- "/courses/#{course.id}/common_homeworks/#{mod.id}"
- when "group_homework"
- "/courses/#{course.id}/group_homeworks/#{mod.id}"
- when "graduation"
- "/courses/#{course.id}/graduation_topics/#{mod.id}"
- when "exercise"
- "/courses/#{course.id}/exercises/#{mod.id}"
- when "poll"
- "/courses/#{course.id}/polls/#{mod.id}"
- when "attachment"
- "/courses/#{course.id}/files/#{mod.id}"
- when "board"
- course_board = course.course_board
- "/courses/#{course.id}/boards/#{course_board.id}"
- when "course_group"
- "/courses/#{course.id}/course_groups"
- when "statistics"
- "/courses/#{course.id}/statistics"
- when "video"
- "/courses/#{course.id}/course_videos"
- end
- end
-
- # 子目录对应的url
- def category_url category, course
- case category.category_type
- when "shixun_homework"
- "/courses/#{course.id}/shixun_homework/#{category.id}"
- when "graduation"
- if category.name == "毕设选题"
- "/courses/#{course.id}/graduation_topics/#{category.course_module_id}"
- else
- "/courses/#{course.id}/graduation_tasks/#{category.course_module_id}"
- end
- when "attachment"
- "/courses/#{course.id}/file/#{category.id}"
- end
- end
-
- # 子目录下的任务数
- def category_task_count course, category, user
- case category.category_type
- when "shixun_homework"
- get_homework_commons_count(course, 4, category.id)
- when "graduation"
- if category.name == "毕设选题"
- course.graduation_topics_count
- else
- course.graduation_tasks_count
- end
- when "attachment"
- get_attachment_count(course, category.id)
- end
- end
-
- # 课堂模块的任务数
- def course_task_count(course, module_type)
- case module_type
- when "shixun_homework"
- get_homework_commons_count(course, 4, 0)
- when "common_homework"
- get_homework_commons_count(course, 1, 0)
- when "group_homework"
- get_homework_commons_count(course, 3, 0)
- when "graduation"
- 0
- when "exercise"
- course.exercises_count
- when "poll"
- course.polls_count
- when "attachment"
- get_attachment_count(course, 0)
- when "board"
- course_board = course.course_board
- course_board.present? ? course_board.messages.size : 0
- when "course_group"
- course.course_groups_count
- when "announcement"
- course.informs.count
- when "online_learning"
- course.shixuns.count
- when "video"
- course.course_videos.count + course.live_links.count
- end
- end
-
- # 当前用户可见的课堂作业,type指定作业类型, category_id指定二级目录
- def visible_homework course, user, type, category_id=0
- if user.teacher_of_course?(course)
- homeworks = course.homework_commons.where("homework_type = #{type} and course_second_category_id = #{category_id}")
- elsif user.member_of_course?(course)
- member = course.course_members.find_by(user_id: user.id, role: 4)
- if member.try(:course_group_id).to_i == 0
- homeworks = course.homework_commons.where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}'
- and unified_setting = 1 and course_second_category_id = #{category_id}")
- else
- not_homework_ids = course.homework_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
- (publish_time > '#{Time.now}' or publish_time is null)").pluck(:homework_common_id)
- # not_homework_ids = not_homework_ids.blank? ? "(-1)" : "(" + not_homework_ids.map(&:homework_common_id).join(",") + ")"
- homeworks = course.homework_commons.where.not(id: not_homework_ids).where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}'
- and course_second_category_id = #{category_id}")
- end
- else
- homeworks = course.homework_commons.where("homework_type = #{type} and publish_time <= '#{Time.now}' and unified_setting = 1
- and course_second_category_id = #{category_id}")
- end
- homeworks
- end
-
- # 当前用户可见的课堂试卷
- def visible_exercise course, user
- if user.teacher_of_course?(course)
- exercises = course.exercises
- elsif user.member_of_course?(course)
- member = course.course_members.find_by(user_id: user.id, role: 4)
- if member.try(:course_group_id).to_i == 0
- exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1")
- else
- not_exercise_ids = course.exercise_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
- (publish_time > '#{Time.now}' or publish_time is null)").pluck(:exercise_id)
- exercises = course.exercises.where.not(id: not_exercise_ids).where("publish_time <= '#{Time.now}'")
- end
- else
- exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1")
- end
- exercises
- end
-
- # 当前用户可见的课堂问卷
- def visible_poll course, user
- if user.teacher_of_course?(course)
- polls = course.polls
- elsif user.member_of_course?(course)
- member = course.course_members.find_by(user_id: user.id, role: 4)
- if member.try(:course_group_id).to_i == 0
- polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1")
- else
- not_poll_ids = course.poll_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
- (publish_time > '#{Time.now}' or publish_time is null)").pluck(:poll_id)
- polls = course.polls.where.not(id: not_poll_ids).where("publish_time <= '#{Time.now}'")
- end
- else
- polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1")
- end
- polls
- end
-
- # 当前用户可见的课堂资源,category_id指定资源的目录
- def visible_attachment course, user, category_id=0
- result = []
- course.attachments.where(course_second_category_id: category_id).each do |attachment|
- if attachment.unified_setting
- if attachment.is_public == 1 && attachment.is_publish == 1 || user == attachment.author || user.teacher_of_course?(course) || (user.member_of_course?(course) && attachment.is_publish == 1)
- result << attachment
- end
- else
- if attachment.is_public == 1 && attachment.is_publish == 1 && !user.member_of_course?(course) || user == attachment.author || user.teacher_of_course?(course)
- result << attachment
- elsif user.member_of_course?(course) && attachment.is_publish == 1
- member = course.course_members.find_by(user_id: user.id, role: 4)
- if member.try(:course_group_id).to_i == 0 && attachment.unified_setting
- result << attachment
- elsif attachment.attachment_group_settings.where("course_group_id = #{member.try(:course_group_id)} and publish_time > '#{Time.now}'").count == 0
- result << attachment
- end
- end
- end
- end
- result
- end
-
- # 获取课堂的资源数
- def get_attachment_count(course, category_id)
- category_id.to_i == 0 ? course.attachments.size : course.attachments.where(course_second_category_id: category_id).size
- end
-
- # 获取课堂的作业数
- def get_homework_commons_count(course, type, category_id)
- category_id == 0 ? HomeworkCommon.where(course_id: course.id, homework_type: type).size :
- HomeworkCommon.where(course_id: course.id, homework_type: type, course_second_category_id: category_id).size
- end
-
-
- # 获取课堂的任务数(作业数+试卷数+问卷数)
- def get_tasks_count(course)
- course.homework_commons_count + course.exercises_count + course.polls_count
- end
-
- # 当前用户可见的毕设任务
- def visible_graduation_task course, user
- if user.teacher_of_course?(course)
- tasks = course.graduation_tasks
- else
- tasks = course.graduation_tasks.where("publish_time <= '#{Time.now}'")
- end
- tasks
- end
-
- # 分班情况
- def course_group_info course, user_id
- course_group_ids = course.group_course_power(user_id)
- course_groups =
- if course_group_ids.present?
- course.course_groups.where(id: course_group_ids).includes(:course_members)
- else
- course.course_groups.includes(:course_members)
- end
- group_info = []
- if !course_groups.blank?
- course_groups.each do |group|
- group_info << {course_group_id: group.id, group_group_name: group.name, count: group.course_members_count}
- end
-
- none_group_count = course.students.where(course_group_id: 0).size
- group_info << {course_group_id: 0, group_group_name: "未分班", count: none_group_count} if none_group_count > 0 && !course_group_ids.present?
- end
-
- return group_info
- end
-
- def left_group_info course
- group_info = []
- if course.course_groups_count > 0
- none_group_count = course.students.where(course_group_id: 0).size
- group_info << {category_id: 0, category_name: "未分班", position: course.course_groups.pluck(:position).max.to_i + 1,
- category_count: none_group_count, category_type: false,
- second_category_url: "/courses/#{@course.id}/course_groups/0"}
- course.course_groups.each do |course_group|
- group_info << {category_id: course_group.id, category_name: course_group.name, position: course_group.position,
- category_count: course_group.course_members_count, category_type: false,
- second_category_url: "/courses/#{@course.id}/course_groups/#{course_group.id}"}
- end
- end
- group_info
- end
-
- def last_subject_shixun course, myshixuns
- myshixun = myshixuns.sort{|x,y| y[:updated_at] <=> x[:updated_at] }.first
- return "" unless myshixun
- stage_shixun = course.course_stage_shixuns.where(shixun_id: myshixun.shixun_id).take
- progress = stage_shixun&.course_stage&.position.to_s + "-" + stage_shixun&.position.to_s + " " + myshixun.shixun&.name
- end
-end
diff --git a/app/helpers/discusses_helper.rb b/app/helpers/discusses_helper.rb
deleted file mode 100644
index c686fcada..000000000
--- a/app/helpers/discusses_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module DiscussesHelper
-end
diff --git a/app/helpers/edu_datas_helper.rb b/app/helpers/edu_datas_helper.rb
deleted file mode 100644
index 1a8584d15..000000000
--- a/app/helpers/edu_datas_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module EduDatasHelper
-end
diff --git a/app/helpers/graduation_tasks_helper.rb b/app/helpers/graduation_tasks_helper.rb
deleted file mode 100644
index 2bc059a55..000000000
--- a/app/helpers/graduation_tasks_helper.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-module GraduationTasksHelper
- include CoursesHelper
- # 教师评阅
- def teacher_comment task, user_id
- [{ id: 0 ,name: "未评", count: task.uncomment_count(user_id)}, {id: 1, name: "已评", count: task.comment_count(user_id)}]
- end
-
- # 作品状态
- def task_status task, user_id
- [{id: 0, name: "未提交", count: task.unfinished_count(user_id)},
- {id: 1, name: "按时提交", count: task.finished_count(user_id)},
- {id: 2, name: "延时提交", count: task.delay_finished_count(user_id)}]
- end
-
- # 交叉评阅
- def cross_comment task, user_id
- if task.cross_comment && task.status >= 3
- [{id: 1, name: "只看我的交叉评阅", count: task.graduation_work_comment_assignations.myself(user_id).count}]
- else
- []
- end
- end
-
- def task_curr_status task, course
- result = {}
- status = []
- time = ""
-
- if course.try(:is_end)
- status << "已结束"
- time = course.end_date.present? ? course.end_date.strftime("%Y-%m-%d") : ""
- else
- if task.status > 1 && task.allow_late && (task.late_time.nil? || task.late_time > Time.now)
- status << "补交中"
- end
-
- case task.status
- when 0
- status << "未发布"
- time = task.publish_time.present? ? "将于 #{format_time(task.publish_time)} 发布" : "创建于#{time_from_now(task.created_at)}"
- when 1
- if task.end_time && task.end_time >= Time.now
- status << "提交中"
- time = how_much_time(task.end_time)
- end
- when 2
- status << "评阅中"
- time = task.comment_time.present? ? how_much_time(task.comment_time) : course.end_date.present? ? how_much_time(course.end_date.end_of_day) : ""
- when 3
- status << "交叉评阅中"
- time = course.end_date.present? ? how_much_time(course.end_date.end_of_day) : ""
- end
-
- status << "未开启补交" if (!task.allow_late && task.status != 0) #6.11 -hs 新增status不等于0
-
- # 如果还在补交阶段则显示补交结束时间
- if task.status > 1 && task.allow_late && task.late_time && task.late_time > Time.now
- time = how_much_time(task.late_time)
- end
- end
-
- result[:status] = status
- result[:time] = time
- result
- end
-
- # 作品数统计:type: 1 已提交 0 未提交
- def grduationwork_count task, type
- works = task.graduation_works
- type == 1 ? works.select{|work| work.work_status != 0}.size : works.select{|work| work.work_status == 0}.size
- end
-
- # 普通/分组 作业作品状态数组
- def graduation_work_status task, user_id, course
- status = []
- work = task.graduation_works.find_by(user_id: user_id)
-
- work = work || GraduationWork.create(graduation_task_id: task.id, user_id: user_id)
- late_time = task.late_time || course.end_date
-
- if course.is_end && work && work.work_status > 0
- status << "查看作品"
- elsif !course.is_end
- if task.publish_time && task.publish_time < Time.now
- # 作业未截止时
- if task.end_time > Time.now
- if task.task_type == 2 && task.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 task.allow_late && (late_time.nil? || late_time > Time.now)
- if task.task_type == 2 && task.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
- status << "查看作品"
- end
- end
- end
- end
-
- # 阶段剩余时间
- def task_left_time task
- if task.publish_time && task.publish_time < Time.now
- if task.end_time > Time.now
- status = "剩余提交时间"
- time = "#{how_much_time(task.end_time)}"
- else
- if task.allow_late && task.late_time && task.late_time >= Time.now
- status = "剩余补交时间"
- time = "#{how_much_time(task.late_time)}"
- end
- end
- end
- {status: status, time: time}
- end
-end
diff --git a/app/helpers/graduation_topics_helper.rb b/app/helpers/graduation_topics_helper.rb
deleted file mode 100644
index ae15d201e..000000000
--- a/app/helpers/graduation_topics_helper.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-module GraduationTopicsHelper
-
- # 课题类型
- def topic_type
- [{id: 1, name: "设计"}, {id: 2, name: "论文"}, {id: 3, name: "创作"}]
- end
-
- # 课程来源
- def topic_source
- [{id: 1, name: "生产/社会实际"}, {id: 2, name:"结合科研"}, {id: 3, name: "其它"}]
- end
-
- # 课题性质1
- def topic_property_first
- [{id: 1, name: "真题"}, {id: 2, name:"模拟题"}]
- end
-
- # 课题性质2
- def topic_property_second
- [{id: 1, name: "纵向课题"}, {id: 2, name:"横向课题"}, {id: 3, name: "自选"}]
- end
-
- # 课题重复
- def topic_repeat
- [{id: 1, name: "新题"}, {id: 2, name:"往届题,有新要求"}, {id: 3, name: "往届题,无新要求"}]
- end
-
-
-
-end
diff --git a/app/helpers/graduation_works_helper.rb b/app/helpers/graduation_works_helper.rb
deleted file mode 100644
index 577efa797..000000000
--- a/app/helpers/graduation_works_helper.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module GraduationWorksHelper
- include GraduationTasksHelper
-
- # 作品最终成绩
- # 参数: work作品, current_user用户,course_identity用户在课堂的身份
- def work_final_score work, current_user, course_identity
- work_score =
- if work.work_score.nil?
- "--"
- else
- if work.check_score_power? current_user, course_identity
- format("%.1f", work.work_score < 0 ? 0 : work.work_score.round(1))
- else
- "**"
- end
- end
- # work_score 最终成绩; late_penalty 迟交扣分; final_score 最终评分
- {username: work.user.full_name, login: work.user.login, work_score: work_score, final_score: work.final_score}
- end
-end
diff --git a/app/helpers/hack_user_lastest_codes_helper.rb b/app/helpers/hack_user_lastest_codes_helper.rb
deleted file mode 100644
index 13350a8f6..000000000
--- a/app/helpers/hack_user_lastest_codes_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module HackUserLastestCodesHelper
-end
diff --git a/app/helpers/hacks_helper.rb b/app/helpers/hacks_helper.rb
deleted file mode 100644
index 13f5ac76d..000000000
--- a/app/helpers/hacks_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module HacksHelper
-end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 226096c24..cc4a3fe02 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -13,12 +13,16 @@ module ProjectsHelper
end
end
- def render_zip_url(project, archive_name)
- [gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.zip"].join('/')
+ def render_zip_url(owner, repository, archive)
+ [base_url, archive_repositories_path(owner&.login, repository, "#{archive}.zip")].join
end
- def render_tar_url(project, archive_name)
- [gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.tar.gz"].join('/')
+ def render_tar_url(owner, repository, archive)
+ [base_url, archive_repositories_path(owner&.login, repository, "#{archive}.tar.gz")].join
+ end
+
+ def render_download_file_url(owner, repository, filepath, ref)
+ [base_url, "/api/#{owner&.login}/#{repository.identifier}/raw?filepath=#{filepath}&ref=#{ref}"].join
end
def render_http_url(project)
@@ -34,11 +38,12 @@ module ProjectsHelper
end
def json_response(project, user)
- repo = Repository.includes(:mirror).select(:id, :mirror_url, :source_clone_url).find_by(project: project)
+ repo = Repository.includes(:mirror).select(:id, :is_mirror, :mirror_url, :source_clone_url).find_by(project: project)
tmp_json = {}
unless project.common?
tmp_json = tmp_json.merge({
+ is_mirror: repo.is_mirror ? true : false,
mirror_status: repo.mirror_status,
mirror_num: repo.mirror_num,
mirror_url: repo.remote_mirror_url,
@@ -54,7 +59,11 @@ module ProjectsHelper
repo_id: repo.id,
open_devops: (user.blank? || user.is_a?(AnonymousUser)) ? false : project.open_devops?,
type: project.numerical_for_project_type,
- author: render_owner(project)
+ author: render_owner(project),
+ project_category_id: project.project_category_id,
+ project_language_id: project.project_language_id,
+ license_id: project.license_id,
+ ignore_id: project.ignore_id
}).compact
render json: tmp_json
diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb
index e704acb83..cc50c8d66 100644
--- a/app/helpers/repositories_helper.rb
+++ b/app/helpers/repositories_helper.rb
@@ -6,16 +6,16 @@ module RepositoriesHelper
def render_decode64_content(str)
return nil if str.blank?
- Base64.decode64(str).force_encoding("UTF-8")
+ Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end
def download_type(str)
- default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx dot)
+ 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)
default_type.include?(str&.downcase)
end
def image_type?(str)
- default_type = %w(png jpg gif tif psd svg)
+ default_type = %w(png jpg gif tif psd svg bmp webp jpeg)
default_type.include?(str&.downcase)
end
@@ -26,8 +26,23 @@ module RepositoriesHelper
end
def render_commit_author(author_json)
- return nil if author_json.blank?
- find_user_by_login author_json['name']
+ return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
+ if author_json["id"].present?
+ return find_user_by_gitea_uid author_json['id']
+ end
+ if author_json["id"].nil? && (author_json["name"].present? && author_json["email"].present?)
+ return find_user_by_login_and_mail(author_json['name'], author_json["email"])
+ end
+ 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
+ if author_json["Name"].present? && author_json["Email"].present?
+ return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
+ end
end
def readme_render_decode64_content(str, path)
@@ -78,12 +93,53 @@ module RepositoriesHelper
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
- content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, entry['path'], ref: ref)['content']
+ content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
readme_render_decode64_content(content, path)
else
- file_type = entry['name'].to_s.split(".").last
- return entry['content'] if download_type(file_type)
+ file_type = File.extname(entry['name'].to_s)[1..-1]
+ if image_type?(file_type)
+ return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] : entry['content']
+ end
+ if download_type(file_type)
+ return entry['content']
+ end
render_decode64_content(entry['content'])
end
end
+
+ def base64_to_image(path, content)
+ # generate to https://git.trusite.net/pawm36ozq/-/raw/branch/master/entrn.png"
+ content = Base64.decode64(content)
+ File.open(path, 'wb') { |f| f.write(content) }
+ end
+
+ def render_download_image_url(dir_path, file_path, content)
+ full_path = file_path.starts_with?("/") ? [dir_path, file_path].join("") : [dir_path, file_path].join("/")
+ file_name = full_path.split("/")[-1]
+ # 用户名/项目标识/文件路径
+ dir_path = generate_dir_path(full_path.split("/"+file_name)[0])
+
+ file_path = [dir_path, file_name].join('/')
+
+ puts "##### render_download_image_url file_path: #{file_path}"
+ base64_to_image(file_path, content)
+ file_path = file_path[6..-1]
+ File.join(base_url, file_path)
+ end
+
+ def generate_dir_path(dir_path)
+ # tmp_dir_path
+ # eg: jasder/forgeplus/raw/branch/ref
+ dir_path = ["public", tmp_dir, dir_path].join('/')
+ puts "#### dir_path: #{dir_path}"
+ unless Dir.exists?(dir_path)
+ FileUtils.mkdir_p(dir_path) ##不成功这里会抛异常
+ end
+ dir_path
+ end
+
+ def tmp_dir
+ "repo"
+ end
+
end
diff --git a/app/helpers/tag_chosen_helper.rb b/app/helpers/tag_chosen_helper.rb
index 5193c9ab4..593e412d9 100644
--- a/app/helpers/tag_chosen_helper.rb
+++ b/app/helpers/tag_chosen_helper.rb
@@ -20,10 +20,16 @@ module TagChosenHelper
"done_ratio": render_complete_percentage,
"issue_tag": render_issue_tags(project),
"issue_type": render_issue_species,
- "all_issues": all_issues
+ "all_issues": all_issues,
+ "branches": render_branches(project)
}
end
+ def render_branches(project)
+ branches = Gitea::Repository::Branches::ListService.call(project&.owner, project.identifier)
+ branches.collect{|i| i["name"] if i.is_a?(Hash)}
+ end
+
def render_cache_trackers
cache_key = "all_trackers/#{Tracker.maximum('id')}"
@@ -176,7 +182,7 @@ module TagChosenHelper
real_name = user.try(:show_real_name)
user_id = user.id
is_chosen = ((user.id.to_s == issue_info[0].to_s) ? "1" : "0")
- member_info = {id: user_id, name: real_name,avatar_url: url_to_avatar(user),is_chosen: is_chosen}
+ member_info = {id: user_id, name: real_name,avatar_url: url_to_avatar(user), permission: project.get_premission(user), is_chosen: is_chosen}
project_members_info.push(member_info)
end
end
diff --git a/app/helpers/trustie_hacks_helper.rb b/app/helpers/trustie_hacks_helper.rb
deleted file mode 100644
index 3ebe3a9cc..000000000
--- a/app/helpers/trustie_hacks_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module TrustieHacksHelper
-end
diff --git a/app/helpers/weapps/courses_helper.rb b/app/helpers/weapps/courses_helper.rb
deleted file mode 100644
index 580536ec6..000000000
--- a/app/helpers/weapps/courses_helper.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-module Weapps::CoursesHelper
- require 'chinese_pinyin'
-
- def teacher_list teachers, user_course_identity
- data = []
- teachers.each do |teacher|
- if teacher.user.present?
- teacher_user = teacher.user
- name = teacher_user.real_name
- role = teacher.role == "CREATOR" ? "管理员" : teacher.role == "PROFESSOR" ? "教师" : "助教"
- member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? teacher_user.course_role(teacher.course) : []
- item = {name: name, course_member_id: teacher.id, login: teacher_user.login, user_id: teacher.user_id, role: role,
- school: teacher_user.school_name, image_url: url_to_avatar(teacher_user), member_roles: member_roles}
- pinyin = Pinyin.t(name.strip, splitter: '')
- first_char = pinyin[0]
- letter = first_letter first_char
- if data.pluck(:letter).include?(letter)
- data.select{|a|a[:letter]==letter}.first[:items] << item
- else
- data << {letter: letter, items: [item]}
- end
- end
- end
- # data = data.sort do |a, b|
- # [a[:letter]] <=> [b[:letter]]
- # end
- # data.push(data.shift) if data.select{|a|a[:letter]=='#'}.first.present? # '#'排在最后
- return data
- end
-
-
- def student_list students, excellent, user_course_identity
- data = []
- students.each do |student|
- if student.user.present?
- student_user = student.user
- name = student_user.real_name
- phone = excellent ? "" : student_user.hidden_phone
- member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? student_user.course_role(student.course) : []
- item = {name: name, course_member_id: student.id, login: student_user.login, user_id: student.user_id,
- student_id: student_user.student_id, image_url: url_to_avatar(student_user), phone: phone, member_roles: member_roles}
- pinyin = Pinyin.t(name.strip, splitter: '')
- first_char = pinyin[0]
- letter = first_letter first_char
- if data.pluck(:letter).include?(letter)
- data.select{|a|a[:letter]==letter}.first[:items] << item
- else
- data << {letter: letter, items: [item]}
- end
- end
- end
- # data = data.sort do |a, b|
- # [a[:letter]] <=> [b[:letter]]
- # end
- # data.push(data.shift) if data.select{|a|a[:letter]=='#'}.first.present? # '#'排在最后
- return data
- end
-
- def first_letter char
- if char.ord >= 97 && char.ord <= 122
- letter = (char.ord - 32).chr.to_s
- elsif char.ord >= 65 && char.ord <= 90
- letter = char
- else
- letter = '#'
- end
- letter
- end
-end
\ No newline at end of file
diff --git a/app/imports/admins/import_course_member_excel.rb b/app/imports/admins/import_course_member_excel.rb
deleted file mode 100644
index ddd3b01a1..000000000
--- a/app/imports/admins/import_course_member_excel.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Admins::ImportCourseMemberExcel < BaseImportXlsx
- Data = Struct.new(:student_id, :name, :course_id, :role, :course_group_name, :school_id)
-
- def read_each(&block)
- sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
- data = row.map(&method(:cell_value))[0..5]
- block.call Data.new(*data)
- end
- end
-
- private
-
- def check_sheet_valid!
- raise_import_error('请按照模板格式导入') if sheet.row(1).size != 6
- end
-
- def cell_value(obj)
- obj&.cell_value&.to_s&.strip
- end
-end
diff --git a/app/interactors/gitea/create_file_interactor.rb b/app/interactors/gitea/create_file_interactor.rb
index acceeaa97..389813520 100644
--- a/app/interactors/gitea/create_file_interactor.rb
+++ b/app/interactors/gitea/create_file_interactor.rb
@@ -24,8 +24,14 @@ module Gitea
def run
Contents::CreateForm.new(valid_params).validate!
- response = Gitea::Repository::Entries::CreateService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call
- render_result(response)
+ result = Gitea::Repository::Entries::CreateService.call(token,
+ owner, @params[:identifier], @params[:filepath], file_params)
+
+ if result[:status] == :success
+ @result = result[:body]
+ else
+ fail!(result[:message])
+ end
rescue Exception => exception
Rails.logger.info "Exception ===========> #{exception.message}"
fail!(exception.message)
@@ -56,7 +62,7 @@ module Gitea
file_params = {}
file_params = file_params.merge(branch: @params[:branch]) unless @params[:branch].blank?
file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank?
- file_params = file_params.merge(content: Base64.encode64(@params[:content]))
+ file_params = file_params.merge(content: Base64.encode64(@params[:content] || ""))
file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank?
file_params = file_params.merge(committer: @params[:committer])
file_params
diff --git a/app/jobs/batch_publish_video_notify_job.rb b/app/jobs/batch_publish_video_notify_job.rb
deleted file mode 100644
index 01390dc2d..000000000
--- a/app/jobs/batch_publish_video_notify_job.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# 批量发布视频 消息任务
-class BatchPublishVideoNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(user_id, video_ids)
- user = User.find_by(id: user_id)
- return if user.blank?
-
- attrs = %i[user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
-
- same_attrs = {
- user_id: 1,
- trigger_user_id: user.id,
- container_type: 'Video',
- tiding_type: 'Apply', status: 0
- }
- Tiding.bulk_insert(*attrs) do |worker|
- user.videos.where(id: video_ids).each do |video|
- worker.add same_attrs.merge(container_id: video.id)
- end
- end
- end
-end
diff --git a/app/jobs/broadcast_mirror_repo_msg_job.rb b/app/jobs/broadcast_mirror_repo_msg_job.rb
index 6372ae2e3..4dee6894a 100644
--- a/app/jobs/broadcast_mirror_repo_msg_job.rb
+++ b/app/jobs/broadcast_mirror_repo_msg_job.rb
@@ -18,12 +18,30 @@ class BroadcastMirrorRepoMsgJob < ApplicationJob
id: project.id,
type: project.numerical_for_project_type
}
+ # 新增失败重试机制, 重试三次
+ result = broadcast(project, json_data)
+
+ if result == 0
+ count = 3
+ while count > 0
+ sleep 3.seconds
+ result = broadcast(project, json_data)
+ if result > 0
+ break
+ end
+ count -= 1
+ end
+ end
+ end
+
+ def broadcast(project, json_data)
puts "############ broadcast start.......... "
puts "############ broadcast channel_name: channel_room_#{project.id}"
puts "############ broadcast project data: #{json_data} "
cable_result = ActionCable.server.broadcast "channel_room_#{project.id}", project: json_data
- puts "############ broadcast result: #{cable_result == 1 ? 'successed' : 'failed'} "
+ puts "############ broadcast result: #{cable_result > 0 ? 'successed' : 'failed'} "
+ return cable_result
end
end
diff --git a/app/jobs/cache_async_clear_job.rb b/app/jobs/cache_async_clear_job.rb
new file mode 100644
index 000000000..651dfaf41
--- /dev/null
+++ b/app/jobs/cache_async_clear_job.rb
@@ -0,0 +1,12 @@
+class CacheAsyncClearJob < ApplicationJob
+ queue_as :cache
+
+ def perform(type, id=nil)
+ case type
+ when "project_common_service"
+ Cache::V2::ProjectCommonService.new(id).clear
+ when "owner_common_service"
+ Cache::V2::OwnnerCommonService.new(id).clear
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/jobs/cache_async_reset_job.rb b/app/jobs/cache_async_reset_job.rb
new file mode 100644
index 000000000..0df0f0fd4
--- /dev/null
+++ b/app/jobs/cache_async_reset_job.rb
@@ -0,0 +1,16 @@
+class CacheAsyncResetJob < ApplicationJob
+ queue_as :cache
+
+ def perform(type, id=nil)
+ case type
+ when "platform_statistic_service"
+ Cache::V2::PlatformStatisticService.new.reset
+ when "project_common_service"
+ Cache::V2::ProjectCommonService.new(id).reset
+ when "owner_common_service"
+ Cache::V2::OwnnerCommonService.new(id).reset
+ when "user_statistic_service"
+ Cache::V2::UserStatisticService.new(id).reset
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/jobs/cache_async_set_job.rb b/app/jobs/cache_async_set_job.rb
new file mode 100644
index 000000000..9c7015d42
--- /dev/null
+++ b/app/jobs/cache_async_set_job.rb
@@ -0,0 +1,16 @@
+class CacheAsyncSetJob < ApplicationJob
+ queue_as :cache
+
+ def perform(type, params={}, id=nil)
+ case type
+ when "platform_statistic_service"
+ Cache::V2::PlatformStatisticService.new(params).call
+ when "project_common_service"
+ Cache::V2::ProjectCommonService.new(id, params).call
+ when "owner_common_service"
+ Cache::V2::OwnnerCommonService.new(id, params).call
+ when "user_statistic_service"
+ Cache::V2::UserStatisticService.new(id, params).call
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/jobs/course_add_student_create_works_job.rb b/app/jobs/course_add_student_create_works_job.rb
deleted file mode 100644
index fec28f395..000000000
--- a/app/jobs/course_add_student_create_works_job.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# 学生加入课堂时创建相关任务作品
-class CourseAddStudentCreateWorksJob < ApplicationJob
- queue_as :default
-
- def perform(course_id, student_ids)
- course = Course.find_by(id: course_id)
- return if course.blank?
-
- # 如果之前存在相关作品,则更新is_delete字段
- student_works = StudentWork.joins(:homework_common).where(user_id: student_ids, homework_commons: {course_id: course.id})
- student_works.update_all(is_delete: 0)
-
- exercise_users = ExerciseUser.joins(:exercise).where(user_id: student_ids, exercises: {course_id: course.id})
- exercise_users.update_all(is_delete: 0)
-
- poll_users = PollUser.joins(:poll).where(user_id: student_ids, polls: {course_id: course.id})
- poll_users.update_all(is_delete: 0)
-
- graduation_works = course.graduation_works.where(user_id: student_ids)
- graduation_works.update_all(is_delete: 0)
-
- attrs = %i[homework_common_id user_id created_at updated_at]
-
- StudentWork.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- same_attrs = {user_id: user_id}
- course.homework_commons.where(homework_type: %i[normal group practice]).each do |homework|
- next if StudentWork.where(user_id: user_id, homework_common_id: homework.id).any?
- worker.add same_attrs.merge(homework_common_id: homework.id)
- end
- end
- end
-
- attrs = %i[exercise_id user_id created_at updated_at]
- ExerciseUser.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- same_attrs = {user_id: user_id}
- course.exercises.each do |exercise|
- next if ExerciseUser.where(user_id: user_id, exercise_id: exercise.id).any?
- worker.add same_attrs.merge(exercise_id: exercise.id)
- end
- end
- end
-
- attrs = %i[poll_id user_id created_at updated_at]
- PollUser.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- same_attrs = {user_id: user_id}
- course.polls.each do |poll|
- next if PollUser.where(user_id: user_id, poll_id: poll.id).any?
- worker.add same_attrs.merge(poll_id: poll.id)
- end
- end
- end
-
- attrs = %i[graduation_task_id user_id course_id created_at updated_at]
- GraduationWork.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- same_attrs = {user_id: user_id, course_id: course.id}
- course.graduation_tasks.each do |task|
- next if GraduationWork.where(user_id: user_id, graduation_task_id: task.id).any?
- worker.add same_attrs.merge(graduation_task_id: task.id)
- end
- end
- end
- end
-end
diff --git a/app/jobs/course_delete_student_delete_works_job.rb b/app/jobs/course_delete_student_delete_works_job.rb
deleted file mode 100644
index a84608b2c..000000000
--- a/app/jobs/course_delete_student_delete_works_job.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CourseDeleteStudentDeleteWorksJob < ApplicationJob
- queue_as :default
-
- def perform(course_id, student_ids)
- course = Course.find_by(id: course_id)
- return if course.blank?
-
- student_works = StudentWork.joins(:homework_common).where(user_id: student_ids, homework_commons: {course_id: course.id})
- student_works.update_all(is_delete: 1)
-
- exercise_users = ExerciseUser.joins(:exercise).where(user_id: student_ids, exercises: {course_id: course.id})
- exercise_users.update_all(is_delete: 1)
-
- poll_users = PollUser.joins(:poll).where(user_id: student_ids, polls: {course_id: course.id})
- poll_users.update_all(is_delete: 1)
-
- course.graduation_works.where(user_id: student_ids).update_all(is_delete: 1)
- end
-end
diff --git a/app/jobs/course_delete_student_notify_job.rb b/app/jobs/course_delete_student_notify_job.rb
deleted file mode 100644
index 898fc97c9..000000000
--- a/app/jobs/course_delete_student_notify_job.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# 删除课堂用户
-class CourseDeleteStudentNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(course_id, student_ids, trigger_user_id)
- course = Course.find_by(id: course_id)
- return if course.blank?
-
- attrs = %i[user_id trigger_user_id container_id container_type belong_container_id
- belong_container_type tiding_type created_at updated_at]
-
- same_attrs = {
- trigger_user_id: trigger_user_id, container_id: course.id, container_type: 'DeleteCourseMember',
- belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'System'
- }
- Tiding.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- worker.add same_attrs.merge(user_id: user_id)
- end
- end
- end
-end
diff --git a/app/jobs/create_diff_record_job.rb b/app/jobs/create_diff_record_job.rb
deleted file mode 100644
index fbe8cbff2..000000000
--- a/app/jobs/create_diff_record_job.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateDiffRecordJob < ApplicationJob
- queue_as :default
-
- def perform(user_id, obj_id, obj_klass, column_name, before, after)
- user = User.find_by(id: user_id)
- obj = obj_klass.constantize.find_by(id: obj_id)
-
- return if user.blank? || obj.blank?
-
- CreateDiffRecordService.call(user, obj, column_name, before, after)
- end
-end
\ No newline at end of file
diff --git a/app/jobs/delay_expired_issue_job.rb b/app/jobs/delay_expired_issue_job.rb
new file mode 100644
index 000000000..bf0e1d2e4
--- /dev/null
+++ b/app/jobs/delay_expired_issue_job.rb
@@ -0,0 +1,11 @@
+class DelayExpiredIssueJob < ApplicationJob
+ queue_as :message
+
+ 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?
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/jobs/delete_department_notify_job.rb b/app/jobs/delete_department_notify_job.rb
deleted file mode 100644
index 1da5e2e85..000000000
--- a/app/jobs/delete_department_notify_job.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# 删除部门 消息通知
-class DeleteDepartmentNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(department_id, operator_id, user_ids)
- department = Department.unscoped.find_by(id: department_id)
- return if department.blank? || user_ids.blank?
-
- attrs = %i[ user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
-
- same_attrs = {
- trigger_user_id: operator_id, container_id: department.id, container_type: 'Department',
- status: 4, tiding_type: 'System'
- }
- Tiding.bulk_insert(*attrs) do |worker|
- user_ids.each do |user_id|
- worker.add same_attrs.merge(user_id: user_id)
- end
- end
- end
-end
diff --git a/app/jobs/exercise_publish_notify_job.rb b/app/jobs/exercise_publish_notify_job.rb
deleted file mode 100644
index 9c43b1978..000000000
--- a/app/jobs/exercise_publish_notify_job.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# 试卷发布 消息通知
-class ExercisePublishNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(exercise_id, group_ids)
- exercise = Exercise.find_by(id: exercise_id)
- return if exercise.blank?
- user = exercise.user
- course = exercise.course
-
- if group_ids.present?
- students = course.students.where(course_group_id: group_ids)
- subquery = course.teacher_course_groups.where(course_group_id: group_ids).select(:course_member_id)
- teachers = course.teachers.where(id: subquery)
- else
- students = course.students
- teachers = course.teachers
- end
-
- attrs = %i[
- user_id trigger_user_id container_id container_type parent_container_id parent_container_type
- belong_container_id belong_container_type viewed tiding_type created_at updated_at
- ]
-
- same_attrs = {
- trigger_user_id: user.id, container_id: exercise.id, container_type: 'Exercise',
- parent_container_id: exercise.id, parent_container_type: 'ExercisePublish',
- belong_container_id: exercise.course_id, belong_container_type: 'Course',
- viewed: 0, tiding_type: 'Exercise'
- }
- Tiding.bulk_insert(*attrs) do |worker|
- teacher_ids = teachers.pluck(:user_id)
- unless exercise.tidings.exists?(parent_container_type: 'ExercisePublish', user_id: teacher_ids)
- teacher_ids.each do |user_id|
- worker.add same_attrs.merge(user_id: user_id)
- end
- end
-
- students.pluck(:user_id).each do |user_id|
- worker.add same_attrs.merge(user_id: user_id)
- end
- end
- end
-end
diff --git a/app/jobs/get_aliyun_video_info_job.rb b/app/jobs/get_aliyun_video_info_job.rb
deleted file mode 100644
index d93186458..000000000
--- a/app/jobs/get_aliyun_video_info_job.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# 获取阿里云视频信息
-class GetAliyunVideoInfoJob < ApplicationJob
- queue_as :default
-
- def perform(vod_video_id)
- video = Video.find_by(uuid: vod_video_id)
- return if video.blank? || video.vod_uploading?
-
- result = AliyunVod::Service.get_play_info(video.uuid)
- cover_url = result.dig('VideoBase', 'CoverURL')
- file_url = (result.dig('PlayInfoList', 'PlayInfo') || []).first&.[]('PlayURL')
-
- video.cover_url = cover_url if cover_url.present? && video.cover_url.blank?
- video.file_url = file_url if file_url.present?
- video.save!
- end
-end
\ No newline at end of file
diff --git a/app/jobs/graduation_task_cross_comment_job.rb b/app/jobs/graduation_task_cross_comment_job.rb
deleted file mode 100644
index a2d181b50..000000000
--- a/app/jobs/graduation_task_cross_comment_job.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# 毕设任务的交叉评阅分配
-class GraduationTaskCrossCommentJob < ApplicationJob
- queue_as :default
-
- def perform(graduation_task_id)
- task = GraduationTask.find_by(id: graduation_task_id)
- return if task.blank?
-
- task.graduation_task_group_assignations.includes(:graduation_group, :graduation_work).each do |assignation|
- graduation_group = assignation.graduation_group
- work = assignation.graduation_work
- if graduation_group.present? && work.present?
- member_ids = graduation_group.course_members.pluck(:user_id).uniq
- member_ids.each do |user_id|
- unless work.graduation_work_comment_assignations.exists?(user_id: user_id)
- work.graduation_work_comment_assignations << GraduationWorkCommentAssignation.new(user_id: user_id, graduation_task_id: task.id)
- end
- end
- end
- end
- end
-end
diff --git a/app/jobs/graduation_task_publish_notify_job.rb b/app/jobs/graduation_task_publish_notify_job.rb
deleted file mode 100644
index 84049fe90..000000000
--- a/app/jobs/graduation_task_publish_notify_job.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# 任务发布 消息通知
-class GraduationTaskPublishNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(graduation_task_id)
- task = GraduationTask.find_by(id: graduation_task_id)
- return if task.blank?
- course = task.course
- return if course.blank?
-
- attrs = %i[
- user_id trigger_user_id container_id container_type parent_container_id parent_container_type
- belong_container_id belong_container_type viewed tiding_type created_at updated_at
- ]
-
- same_attrs = {
- trigger_user_id: task.user_id, container_id: task.id, container_type: 'GraduationTask',
- parent_container_id: task.id, parent_container_type: 'TaskPublish',
- belong_container_id: task.course_id, belong_container_type: 'Course',
- viewed: 0, tiding_type: 'GraduationTask'
- }
- Tiding.bulk_insert(*attrs) do |worker|
- course.course_members.pluck(:user_id).uniq.each do |user_id|
- worker.add same_attrs.merge(user_id: user_id)
- end
- end
- end
-end
diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb
index 03727908d..e54eaf2bc 100644
--- a/app/jobs/migrate_remote_repository_job.rb
+++ b/app/jobs/migrate_remote_repository_job.rb
@@ -8,10 +8,14 @@ class MigrateRemoteRepositoryJob < ApplicationJob
puts "############ MigrateRemoteRepositoryJob starting ... ############"
gitea_repository = Gitea::Repository::MigrateService.new(token, params).call
- if gitea_repository
- repo&.project&.update_columns(gpid: gitea_repository["id"])
+ puts "#gitea_repository#{gitea_repository}"
+ if gitea_repository[0]==201
+ repo&.project&.update_columns(gpid: gitea_repository[2]["id"])
repo&.mirror&.succeeded!
puts "############ mirror status: #{repo.mirror.status} ############"
+ else
+ repo&.mirror&.failed!
end
+ BroadcastMirrorRepoMsgJob.perform_later(repo.id) unless repo&.mirror.waiting?
end
end
diff --git a/app/jobs/reset_user_cache_job.rb b/app/jobs/reset_user_cache_job.rb
index 3562475ce..7b2c5c63b 100644
--- a/app/jobs/reset_user_cache_job.rb
+++ b/app/jobs/reset_user_cache_job.rb
@@ -2,6 +2,7 @@ class ResetUserCacheJob < ApplicationJob
queue_as :cache
def perform(user)
+ return if user.nil?
Cache::UserFollowCountService.new(user).reset
Cache::UserIssueCountService.new(user).reset
Cache::UserProjectCountService.new(user).reset
diff --git a/app/jobs/resubmit_student_work_notify_job.rb b/app/jobs/resubmit_student_work_notify_job.rb
deleted file mode 100644
index 1a67aa3ad..000000000
--- a/app/jobs/resubmit_student_work_notify_job.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class ResubmitStudentWorkNotifyJob < ApplicationJob
- queue_as :notify
-
- def perform(homework_id, student_ids)
- homework = HomeworkCommon.find_by(id: homework_id)
- return if homework.blank? || student_ids.blank?
- course = homework.course
-
- attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type
- belong_container_id belong_container_type tiding_type viewed created_at updated_at]
-
- same_attrs = {
- container_type: 'ResubmitStudentWork', parent_container_id: homework.id, parent_container_type: 'HomeworkCommon',
- belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'HomeworkCommon', viewed: 0
- }
- Tiding.bulk_insert(*attrs) do |worker|
- student_ids.each do |user_id|
- next unless User.exists?(id: user_id)
-
- work = homework.student_works.find_by(user_id: user_id)
- next if work.blank?
- score_user_ids = work.student_works_scores.where.not(score: nil).where(reviewer_role: [1, 2]).pluck(user_id).uniq
- next if score_user_ids.blank?
-
- attrs = same_attrs.merge(trigger_user_id: user_id, container_id: work.id)
-
- score_user_ids.each do |user_id|
- worker.add attrs.merge(user_id: user_id)
- end
- end
- end
- end
-end
diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb
new file mode 100644
index 000000000..125ed3e0b
--- /dev/null
+++ b/app/jobs/send_template_message_job.rb
@@ -0,0 +1,279 @@
+class SendTemplateMessageJob < ApplicationJob
+ queue_as :message
+
+ def perform(source, *args)
+ Rails.logger.info "SendTemplateMessageJob [args] #{args}"
+ case source
+ when 'FollowTip'
+ watcher_id = args[0]
+ watcher = Watcher.find_by_id(watcher_id)
+ return unless watcher.present?
+ receivers = User.where(id: watcher.watchable_id)
+ followeder = User.find_by_id(watcher.user_id)
+ receivers_string, content, notification_url = MessageTemplate::FollowedTip.get_message_content(receivers, followeder)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {watcher_id: watcher.id})
+ when 'IssueAssigned'
+ operator_id, issue_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ issue = Issue.find_by_id(issue_id)
+ return unless operator.present? && issue.present?
+ receivers = User.where(id: issue&.assigned_to_id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::IssueAssigned.get_message_content(receivers, operator, issue)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id})
+ receivers.find_each do |receiver|
+ 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)
+ issue = Issue.find_by_id(issue_id)
+ return unless operator.present? && issue.present?
+ # receivers = receivers.where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::IssueAtme.get_message_content(receivers, operator, issue)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}, 2, operator_id)
+ when 'IssueChanged'
+ operator_id, issue_id, change_params = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ issue = Issue.find_by_id(issue_id)
+ return unless operator.present? && issue.present?
+ receivers = User.where(id: [issue&.assigned_to_id, issue&.author_id]).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::IssueChanged.get_message_content(receivers, operator, issue, change_params.symbolize_keys)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id, change_params: change_params.symbolize_keys})
+ receivers.find_each do |receiver|
+ 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'
+ 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)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
+ 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)
+ return unless operator.present?
+ receivers = User.where(id: [issue_assigned_to_id, issue_author_id]).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::IssueDeleted.get_message_content(receivers, operator, issue_title)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_title: issue_title})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::IssueDeleted.get_email_message_content(receiver, operator, issue_title)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'OrganizationJoined'
+ user_id, organization_id = args[0], args[1]
+ user = User.find_by_id(user_id)
+ organization = Organization.find_by_id(organization_id)
+ return unless user.present? && organization.present?
+ receivers = User.where(id: user.id)
+ receivers_string, content, notification_url = MessageTemplate::OrganizationJoined.get_message_content(receivers, organization)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::OrganizationJoined.get_email_message_content(receiver, organization)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'OrganizationLeft'
+ user_id, organization_id = args[0], args[1]
+ user = User.find_by_id(user_id)
+ organization = Organization.find_by_id(organization_id)
+ return unless user.present? && organization.present?
+ receivers = User.where(id: user.id)
+ receivers_string, content, notification_url = MessageTemplate::OrganizationLeft.get_message_content(receivers, organization)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id})
+ receivers.find_each do |receiver|
+ 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 'OrganizationRole'
+ user_id, organization_id, role = args[0], args[1], args[2]
+ user = User.find_by_id(user_id)
+ organization = Organization.find_by_id(organization_id)
+ return unless user.present? && organization.present?
+ receivers = User.where(id: user.id)
+ receivers_string, content, notification_url = MessageTemplate::OrganizationRole.get_message_content(receivers, organization, role)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id, role: role})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::OrganizationRole.get_email_message_content(receiver, organization, role)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectIssue'
+ operator_id, issue_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ issue = Issue.find_by_id(issue_id)
+ return unless operator.present? && issue.present? && issue&.project.present?
+ managers = issue&.project&.all_managers.where.not(id: operator&.id)
+ followers = User.none # TODO
+ receivers_string, content, notification_url = MessageTemplate::ProjectIssue.get_message_content(managers, followers, operator, issue)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id})
+ managers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectIssue.get_email_message_content(receiver, true, operator, issue)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ followers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectIssue.get_email_message_content(receiver, false, operator, issue)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectJoined'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectJoined.get_message_content(receivers, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectJoined.get_email_message_content(receiver, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectLeft'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectLeft.get_message_content(receivers, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectLeft.get_email_message_content(receiver, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectMemberJoined'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = project&.all_managers.where.not(id: [operator&.id, user&.id])
+ receivers_string, content, notification_url = MessageTemplate::ProjectMemberJoined.get_message_content(receivers, user, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberJoined.get_email_message_content(receiver, user, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectMemberLeft'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = project&.all_managers.where.not(id: [operator&.id, user&.id])
+ receivers_string, content, notification_url = MessageTemplate::ProjectMemberLeft.get_message_content(receivers, user, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ 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 'ProjectPullRequest'
+ operator_id, pull_request_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ return unless operator.present? && pull_request.present? && pull_request&.project.present?
+ managers = pull_request&.project&.all_managers.where.not(id: operator&.id)
+ followers = User.none # TODO
+ receivers_string, content, notification_url = MessageTemplate::ProjectPullRequest.get_message_content(managers, followers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id})
+ managers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectPullRequest.get_email_message_content(receiver, true, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ followers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectPullRequest.get_email_message_content(receiver, false, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectRole'
+ operator_id, user_id, project_id, role = args[0], args[1], args[2], args[3]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectRole.get_message_content(receivers, project, role)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id, role: role})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectRole.get_email_message_content(receiver, project, role)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectSettingChanged'
+ operator_id, project_id, change_params = args[0], args[1], args[2]
+ 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::ProjectSettingChanged.get_message_content(receivers, operator, project, change_params.symbolize_keys)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id, change_params: change_params.symbolize_keys})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectSettingChanged.get_email_message_content(receiver, operator, project, change_params.symbolize_keys)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'PullRequestAssigned'
+ operator_id, pull_request_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ issue = Issue.find_by_id(pull_request&.issue_id)
+ return unless operator.present? && pull_request.present? && issue.present?
+ receivers = User.where(id: issue&.assigned_to_id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::PullRequestAssigned.get_message_content(receivers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::PullRequestAssigned.get_email_message_content(receiver, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'PullRequestAtme'
+ receivers, operator_id, pull_request_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ return unless operator.present? && pull_request.present?
+ # receivers = receivers.where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::PullRequestAtme.get_message_content(receivers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}, 2, operator_id)
+ when 'PullRequestChanged'
+ operator_id, pull_request_id, change_params = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ issue = Issue.find_by_id(pull_request&.issue_id)
+ return unless operator.present? && pull_request.present? && issue.present?
+ receivers = User.where(id: [issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::PullRequestChanged.get_message_content(receivers, operator, pull_request, change_params.symbolize_keys)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id, change_params: change_params})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::PullRequestChanged.get_email_message_content(receiver, operator, pull_request, change_params.symbolize_keys)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'PullRequestClosed'
+ operator_id, pull_request_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ return unless operator.present? && pull_request.present?
+ receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::PullRequestClosed.get_message_content(receivers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::PullRequestClosed.get_email_message_content(receiver, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'PullRequestMerged'
+ operator_id, pull_request_id = args[0], args[1]
+ operator = User.find_by_id(operator_id)
+ pull_request = PullRequest.find_by_id(pull_request_id)
+ return unless operator.present? && pull_request.present?
+ receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::PullRequestMerged.get_message_content(receivers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::PullRequestMerged.get_email_message_content(receiver, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/jobs/sync_mirrored_repository_job.rb b/app/jobs/sync_mirrored_repository_job.rb
index a1408153f..63abbfd80 100644
--- a/app/jobs/sync_mirrored_repository_job.rb
+++ b/app/jobs/sync_mirrored_repository_job.rb
@@ -26,6 +26,7 @@ class SyncMirroredRepositoryJob < ApplicationJob
result = Gitea::Repository::SyncMirroredService.call(repo.owner.login,
repo.identifier, token: user.gitea_token)
repo&.mirror.set_status! if result[:status] === 200
+ BroadcastMirrorRepoMsgJob.perform_later(repo.id) unless repo&.mirror.waiting?
end
end
diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb
index 4aa6fac2d..bbc061250 100644
--- a/app/libs/custom_regexp.rb
+++ b/app/libs/custom_regexp.rb
@@ -1,9 +1,14 @@
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_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
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/
URL = /\Ahttps?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]\z/
IP = /^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
+
+ 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_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
+
end
diff --git a/app/libs/notice.rb b/app/libs/notice.rb
new file mode 100644
index 000000000..93d5cb42d
--- /dev/null
+++ b/app/libs/notice.rb
@@ -0,0 +1,21 @@
+module Notice
+ class << self
+ def notice_config
+ notice_config = {}
+
+ begin
+ config = Rails.application.config_for(:configuration).symbolize_keys!
+ notice_config = config[:notice].symbolize_keys!
+ raise 'notice config missing' if notice_config.blank?
+ rescue => exception
+ 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}
+ notice_config = {}
+ end
+
+ notice_config
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index 6e957b4df..acd34fbbd 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -1,17 +1,11 @@
class UserMailer < ApplicationMailer
# 注意:这个地方一定要和你的邮箱服务域名一致
- default from: 'educoder@trustie.org'
+ default from: 'notification@trustie.org'
# 用户注册验证码
def register_email(mail, code)
@code = code
- mail(to: mail, subject: '验证你的电子邮件')
+ mail(to: mail, subject: 'Gitink | 注册验证码')
end
- # 课堂讨论区的邮件通知
- def course_message_email(mail, message_id)
- @message = Message.find_by(id: message_id)
- @course = @message&.board&.course
- mail(to: mail, subject: '课堂发布了新的帖子') if @message.present? && @course.present?
- end
end
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
index 3ab2b11e8..77e5fe2db 100644
--- a/app/models/application_record.rb
+++ b/app/models/application_record.rb
@@ -17,11 +17,11 @@ class ApplicationRecord < ActiveRecord::Base
Rails.env.production? && EduSetting.get('host_name') == 'https://www.educoder.net'
end
- def reset_user_cache_async_job(user)
- ResetUserCacheJob.perform_later(user)
+ def self.strip_param(key)
+ key.to_s.strip.presence
end
- def reset_platform_cache_async_job
- ResetPlatformCacheJob.perform_later
+ def strip_param(key)
+ key.to_s.strip.presence
end
end
diff --git a/app/models/applied_message.rb b/app/models/applied_message.rb
index 5c942b7b3..01f5fa7e5 100644
--- a/app/models/applied_message.rb
+++ b/app/models/applied_message.rb
@@ -1,19 +1,26 @@
# == Schema Information
#
-# Table name: applied_messages
+# Table name: forge_applied_messages
#
# id :integer not null, primary key
# user_id :integer
-# applied_id :integer
# applied_type :string(255)
+# applied_id :integer
# viewed :integer default("0")
# status :integer default("0")
-# created_at :datetime not null
-# updated_at :datetime not null
# name :string(255)
# applied_user_id :integer
# role :integer
# project_id :integer
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_forge_applied_messages_on_applied_type_and_applied_id (applied_type,applied_id)
+# index_forge_applied_messages_on_applied_user_id (applied_user_id)
+# index_forge_applied_messages_on_project_id (project_id)
+# index_forge_applied_messages_on_user_id (user_id)
#
class AppliedMessage < ApplicationRecord
diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb
index e0b4b6c48..ea7ca6eee 100644
--- a/app/models/applied_project.rb
+++ b/app/models/applied_project.rb
@@ -1,14 +1,19 @@
# == Schema Information
#
-# Table name: applied_projects
+# Table name: forge_applied_projects
#
# id :integer not null, primary key
-# project_id :integer not null
-# user_id :integer not null
+# project_id :integer
+# user_id :integer
# role :integer default("0")
# status :integer default("0")
-# created_at :datetime
-# updated_at :datetime
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_forge_applied_projects_on_project_id (project_id)
+# index_forge_applied_projects_on_user_id (user_id)
#
class AppliedProject < ApplicationRecord
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index c6a50d93e..3451246af 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -1,41 +1,42 @@
-# == Schema Information
-#
-# Table name: attachments
-#
-# id :integer not null, primary key
-# container_id :integer
-# container_type :string(30)
-# filename :string(255) default(""), not null
-# disk_filename :string(255) default(""), not null
-# filesize :integer default("0"), not null
-# content_type :string(255) default("")
-# digest :string(60) default(""), not null
-# downloads :integer default("0"), not null
-# author_id :integer default("0"), not null
-# created_on :datetime
-# description :text(65535)
-# disk_directory :string(255)
-# attachtype :integer default("1")
-# is_public :integer default("1")
-# copy_from :integer
-# quotes :integer default("0")
-# is_publish :integer default("1")
-# publish_time :datetime
-# resource_bank_id :integer
-# unified_setting :boolean default("1")
-# cloud_url :string(255) default("")
-# course_second_category_id :integer default("0")
-# delay_publish :boolean default("0")
-#
-# Indexes
-#
-# index_attachments_on_author_id (author_id)
-# index_attachments_on_container_id_and_container_type (container_id,container_type)
-# index_attachments_on_course_second_category_id (course_second_category_id)
-# index_attachments_on_created_on (created_on)
-# index_attachments_on_is_public (is_public)
-# index_attachments_on_quotes (quotes)
-#
+# == Schema Information
+#
+# Table name: attachments
+#
+# id :integer not null, primary key
+# container_id :integer
+# container_type :string(30)
+# filename :string(255) default(""), not null
+# disk_filename :string(255) default(""), not null
+# filesize :integer default("0"), not null
+# content_type :string(255) default("")
+# digest :string(60) default(""), not null
+# downloads :integer default("0"), not null
+# author_id :integer default("0"), not null
+# created_on :datetime
+# description :text(65535)
+# disk_directory :string(255)
+# attachtype :integer default("1")
+# is_public :integer default("1")
+# copy_from :string(255)
+# quotes :integer default("0")
+# is_publish :integer default("1")
+# publish_time :datetime
+# resource_bank_id :integer
+# unified_setting :boolean default("1")
+# cloud_url :string(255) default("")
+# course_second_category_id :integer default("0")
+# delay_publish :boolean default("0")
+# link :string(255)
+# clone_id :integer
+#
+# Indexes
+#
+# index_attachments_on_author_id (author_id)
+# index_attachments_on_clone_id (clone_id)
+# index_attachments_on_container_id_and_container_type (container_id,container_type)
+# index_attachments_on_created_on (created_on)
+#
+
class Attachment < ApplicationRecord
diff --git a/app/models/ci/user.rb b/app/models/ci/user.rb
index c263a1723..e4a4d0623 100644
--- a/app/models/ci/user.rb
+++ b/app/models/ci/user.rb
@@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
-# platform :string(255) default("0")
-# gitea_token :string(255)
-# gitea_uid :integer
# is_shixun_marker :boolean default("0")
+# admin_visitable :boolean default("0")
+# collaborator :boolean default("0")
+# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
-# sponsor_certification :integer default("0")
-# sponsor_num :integer default("0")
-# sponsored_num :integer default("0")
-# award_time :datetime
+# gitea_token :string(255)
+# platform :string(255)
#
# Indexes
#
@@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
-# index_users_on_login (login)
-# index_users_on_mail (mail)
+# index_users_on_login (login) UNIQUE
+# index_users_on_mail (mail) UNIQUE
+# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#
diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb
index 79d099a2e..a6dc0dd35 100644
--- a/app/models/concerns/project_operable.rb
+++ b/app/models/concerns/project_operable.rb
@@ -65,7 +65,7 @@ module ProjectOperable
if owner.is_a?(User)
managers.exists?(user_id: user.id)
elsif owner.is_a?(Organization)
- managers.exists?(user_id: user.id) || owner.is_only_admin?(user.id)
+ managers.exists?(user_id: user.id) || owner.is_owner?(user.id) || owner.is_only_admin?(user.id)
else
false
end
@@ -94,7 +94,7 @@ module ProjectOperable
end
def operator?(user)
- user.admin? || !reporter?(user)
+ user.admin? || (member?(user.id) && !reporter?(user))
end
def set_developer_role(member, role_name)
diff --git a/app/models/edu_setting.rb b/app/models/edu_setting.rb
index 6968b008e..22575ff15 100644
--- a/app/models/edu_setting.rb
+++ b/app/models/edu_setting.rb
@@ -1,22 +1,24 @@
-# == Schema Information
-#
-# Table name: edu_settings
-#
-# id :integer not null, primary key
-# name :string(255)
-# value :string(255)
-# created_at :datetime not null
-# updated_at :datetime not null
-# description :string(255)
-#
-# Indexes
-#
-# index_edu_settings_on_name (name) UNIQUE
-#
-
+# == Schema Information
+#
+# Table name: edu_settings
+#
+# id :integer not null, primary key
+# name :string(255)
+# value :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+# description :string(255)
+#
+# Indexes
+#
+# index_edu_settings_on_name (name) UNIQUE
+#
+
class EduSetting < ApplicationRecord
after_commit :expire_value_cache
+ scope :by_search, -> (keyword){ where("name LIKE :keyword OR value LIKE :keyword", keyword: "%#{strip_param(keyword)}%") unless strip_param(keyword).blank? }
+
def value_cache_key
self.class.value_cache_key(name)
end
diff --git a/app/models/fork_user.rb b/app/models/fork_user.rb
index 0936f6bfa..bddf8f75c 100644
--- a/app/models/fork_user.rb
+++ b/app/models/fork_user.rb
@@ -20,12 +20,30 @@ class ForkUser < ApplicationRecord
belongs_to :user
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
- after_save :reset_cache_data
- after_destroy :reset_cache_data
+ after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
+ after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
- def reset_cache_data
- self.reset_platform_cache_async_job
- self.reset_user_cache_async_job(self.project.owner)
+ def incre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {forks: 1}, self.project_id)
end
+ def decre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {forks: -1}, self.project_id)
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {fork_count: 1}, self.project&.user_id)
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {fork_count: -1}, self.project&.user_id)
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {fork_count: 1})
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {fork_count: -1})
+ end
end
diff --git a/app/models/gitea/base.rb b/app/models/gitea/base.rb
index d14249bf6..652fd777d 100644
--- a/app/models/gitea/base.rb
+++ b/app/models/gitea/base.rb
@@ -1,4 +1,6 @@
-class Gitea::Base < Gitea::Database
- self.abstract_class = true
-
+class Gitea::Base < ApplicationRecord
+ db_config = Rails.configuration.database_configuration[Rails.env]["gitea_server"]
+ raise 'gitea database config missing' if db_config.blank?
+
+ establish_connection db_config
end
diff --git a/app/models/gitea/public_key.rb b/app/models/gitea/public_key.rb
new file mode 100644
index 000000000..bb2192358
--- /dev/null
+++ b/app/models/gitea/public_key.rb
@@ -0,0 +1,9 @@
+class Gitea::PublicKey < Gitea::Base
+ self.inheritance_column = nil # FIX The single-table inheritance mechanism failed
+ # establish_connection :gitea_db
+
+ self.table_name = "public_key"
+
+ belongs_to :user, class_name: '::User', primary_key: :gitea_uid, foreign_key: :owner_id, optional: true
+
+end
diff --git a/app/models/gitea/pull.rb b/app/models/gitea/pull.rb
new file mode 100644
index 000000000..591e36c42
--- /dev/null
+++ b/app/models/gitea/pull.rb
@@ -0,0 +1,44 @@
+# == Schema Information
+#
+# Table name: pull_request
+#
+# id :integer not null, primary key
+# type :integer
+# status :integer
+# conflicted_files :text(65535)
+# commits_ahead :integer
+# commits_behind :integer
+# changed_protected_files :text(65535)
+# issue_id :integer
+# index :integer
+# head_repo_id :integer
+# base_repo_id :integer
+# head_branch :string(255)
+# base_branch :string(255)
+# merge_base :string(40)
+# has_merged :boolean
+# merged_commit_id :string(40)
+# merger_id :integer
+# merged_unix :integer
+#
+# Indexes
+#
+# IDX_pull_request_base_repo_id (base_repo_id)
+# IDX_pull_request_has_merged (has_merged)
+# IDX_pull_request_head_repo_id (head_repo_id)
+# IDX_pull_request_issue_id (issue_id)
+# IDX_pull_request_merged_unix (merged_unix)
+# IDX_pull_request_merger_id (merger_id)
+#
+
+class Gitea::Pull < Gitea::Base
+ self.inheritance_column = nil # FIX The single-table inheritance mechanism failed
+ # establish_connection :gitea_db
+
+ self.table_name = "pull_request"
+
+ serialize :conflicted_files, Array
+
+ belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_number, optional: true
+
+end
diff --git a/app/models/gitea/webhook.rb b/app/models/gitea/webhook.rb
new file mode 100644
index 000000000..f60f56788
--- /dev/null
+++ b/app/models/gitea/webhook.rb
@@ -0,0 +1,13 @@
+class Gitea::Webhook < Gitea::Base
+ serialize :events, JSON
+ self.inheritance_column = nil
+
+ self.table_name = 'webhook'
+
+ has_many :tasks, class_name: "Gitea::WebhookTask", foreign_key: :hook_id
+ belongs_to :project, class_name: "::Project", primary_key: :gpid, foreign_key: :repo_id, optional: true
+
+ enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9}
+ enum last_status: {waiting: 0, succeed: 1, fail: 2}
+ enum content_type: {json: 1, form: 2}
+end
\ No newline at end of file
diff --git a/app/models/gitea/webhook_task.rb b/app/models/gitea/webhook_task.rb
new file mode 100644
index 000000000..d19a163aa
--- /dev/null
+++ b/app/models/gitea/webhook_task.rb
@@ -0,0 +1,13 @@
+class Gitea::WebhookTask < Gitea::Base
+ serialize :payload_content, JSON
+ serialize :request_content, JSON
+ serialize :response_content, JSON
+
+ self.inheritance_column = nil
+
+ self.table_name = 'hook_task'
+
+ belongs_to :webhook, class_name: "Gitea::Webhook", foreign_key: :hook_id
+
+ enum type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9}
+end
\ No newline at end of file
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 826ad3a5b..c642e642b 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -74,13 +74,32 @@ class Issue < ApplicationRecord
scope :issue_pull_request, ->{where(issue_classify: "pull_request")}
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 :reset_cache_data
- after_destroy :update_closed_issues_count_in_project!, :reset_cache_data
+ after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic
- def reset_cache_data
- self.reset_platform_cache_async_job
- self.reset_user_cache_async_job(self.user)
+ def incre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {issues: 1}, self.project_id)
+ end
+
+ def decre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {issues: -1}, self.project_id)
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: 1}, self.author_id)
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: -1}, self.author_id)
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: 1})
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: -1})
end
def get_assign_user
diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb
index 699800c92..9b409c170 100644
--- a/app/models/laboratory.rb
+++ b/app/models/laboratory.rb
@@ -10,6 +10,7 @@
# sync_course :boolean default("0")
# sync_subject :boolean default("0")
# sync_shixun :boolean default("0")
+# is_local :boolean default("0")
#
# Indexes
#
@@ -43,7 +44,7 @@ class Laboratory < ApplicationRecord
def site
rails_env = EduSetting.get('rails_env')
- suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.trustie.net" : '.trustie.net'
+ suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.gitlink.org.cn" : '.gitlink.org.cn'
identifier ? "#{identifier}#{suffix}" : ''
end
@@ -73,74 +74,6 @@ class Laboratory < ApplicationRecord
RequestStore.store[:current_laboratory] ||= User.anonymous
end
- def shixuns
- if main_site?
- not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{Laboratory.current.id}")
- Shixun.where.not(id: not_shixun_ids.pluck(:shixun_id))
- elsif sync_shixun
- laboratory_shixun_ids = laboratory_shixuns.pluck(:shixun_id)
- school_shixun_ids = Shixun.joins("join user_extensions on shixuns.user_id=user_extensions.user_id").where(user_extensions: { school_id: school_id }).pluck(:id)
- shixun_ids = laboratory_shixun_ids + school_shixun_ids
- Shixun.where(id: shixun_ids.uniq)
- else
- Shixun.joins(:laboratory_shixuns).where(laboratory_shixuns: { laboratory_id: id })
- end
- end
-
- def subjects
- if main_site?
- not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{Laboratory.current.id}")
- Subject.where.not(id: not_subject_ids.pluck(:subject_id))
- elsif sync_subject
- laboratory_subject_ids = laboratory_subjects.pluck(:subject_id)
- school_subject_ids = Subject.joins("join user_extensions on subjects.user_id=user_extensions.user_id").where(user_extensions: { school_id: school_id }).pluck(:id)
- subject_ids = laboratory_subject_ids + school_subject_ids
- Subject.where(id: subject_ids.uniq)
- else
- Subject.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
- end
- end
-
- def all_courses
- main_site? || !sync_course ? courses : courses.or(Course.where(school_id: school_id))
- end
-
- def shixun_repertoires
- where_sql = ShixunTagRepertoire.where("shixun_tag_repertoires.tag_repertoire_id = tag_repertoires.id")
-
- # 云上实验室过滤
- unless main_site?
- where_sql = where_sql.joins("JOIN laboratory_shixuns ls ON ls.shixun_id = shixun_tag_repertoires.shixun_id "\
- "AND ls.laboratory_id = #{id}")
- end
- where_sql = where_sql.select('1').to_sql
- tags = TagRepertoire.where("EXISTS(#{where_sql})").distinct.includes(sub_repertoire: :repertoire)
-
- tags_map = tags.group_by(&:sub_repertoire)
- sub_reps_map = tags_map.keys.group_by(&:repertoire)
-
- sub_reps_map.keys.sort_by(&:updated_at).reverse.map do |repertoire|
- repertoire_hash = repertoire.as_json(only: %i[id name])
- repertoire_hash[:sub_repertoires] =
- sub_reps_map[repertoire].sort_by(&:updated_at).reverse.map do |sub_repertoire|
- sub_repertoire_hash = sub_repertoire.as_json(only: %i[id name])
- sub_repertoire_hash[:tags] = tags_map[sub_repertoire].sort_by(&:updated_at).reverse.map { |tag| tag.as_json(only: %i[id name]) }
- sub_repertoire_hash
- end
- repertoire_hash
- end
- end
-
- def subject_repertoires
- exist_sql = Subject.where('subjects.repertoire_id = repertoires.id')
-
- unless main_site?
- exist_sql = exist_sql.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
- end
-
- Repertoire.where("EXISTS(#{exist_sql.select('1').to_sql})").order(updated_at: :desc).distinct
- end
-
# 是否为主站
def main_site?
id == 1
diff --git a/app/models/license.rb b/app/models/license.rb
index dcd5528fb..0a14fb85e 100644
--- a/app/models/license.rb
+++ b/app/models/license.rb
@@ -7,7 +7,6 @@
# content :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
-# is_secret :boolean default("0")
#
class License < ApplicationRecord
diff --git a/app/models/member.rb b/app/models/member.rb
index 408710a03..e72ae7c6b 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -11,7 +11,6 @@
# course_group_id :integer default("0")
# is_collect :integer default("1")
# graduation_group_id :integer default("0")
-# is_apply_signature :boolean default("0")
#
# Indexes
#
diff --git a/app/models/message_template.rb b/app/models/message_template.rb
new file mode 100644
index 000000000..a6e894c70
--- /dev/null
+++ b/app/models/message_template.rb
@@ -0,0 +1,106 @@
+# == 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 < ApplicationRecord
+
+ def self.build_init_data
+ self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '{nickname} 关注了你', notification_url: '{baseurl}/{login}')
+ email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
+ self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 {nickname2}/{repository} 指派给你一个易修:{title} ', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个易修')
+ self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的易修 {title} 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
+ self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '{nickname} 在易修 {title} 中@我', 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: '在项目 {nickname2}/{repository} 的易修 {title} 中:{ifassigner}{nickname1}将负责人从 {assigner1} 修改为 {assigner2} {endassigner}{ifstatus}{nickname1}将状态从 {status1} 修改为 {status2} {endstatus}{iftracker}{nickname1}将类型从 {tracker1} 修改为 {tracker2} {endtracker}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifdoneratio}{nickname1}将完成度从 {doneratio1} 修改为 {doneratio2} {enddoneratio}{ifbranch}{nickname1}将指定分支从 {branch1} 修改为 {branch2} {endbranch}{ifstartdate}{nickname1}将开始日期从 {startdate1} 修改为 {startdate2} {endstartdate}{ifduedate}{nickname1}将结束日期从 {duedate1} 修改为 {duedate2} {endduedate}', email: email_html, email_title: 'GitLink: 易修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
+ self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的易修 {title} 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
+ email_html = File.read("#{email_template_html_dir}/issue_deleted.html")
+ self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将易修 {title} 删除', email: email_html, email_title: 'GitLink: 易修 {title} 有状态变更', notification_url: '')
+ self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论易修{title}:{notes} ', 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: '你已加入 {organization} 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: 'GitLink: 你已加入 {organization} 组织')
+ email_html = File.read("#{email_template_html_dir}/organization_left.html")
+ self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 {organization} 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织')
+ email_html = File.read("#{email_template_html_dir}/organization_role.html")
+ self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 {organization} 已把你的角色改为 {role} ', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
+ self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '')
+ self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '{nickname} 关注了你管理的仓库', notification_url: '{baseurl}/{login}')
+ self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '{nickname1} 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
+ email_html = File.read("#{email_template_html_dir}/project_issue.html")
+ self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 {nickname2}/{repository} 新建易修:{title} ', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个易修')
+ email_html = File.read("#{email_template_html_dir}/project_joined.html")
+ self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 {repository} 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: 你已加入 {repository} 项目')
+ email_html = File.read("#{email_template_html_dir}/project_left.html")
+ self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 {repository} 项目', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {repository} 项目')
+ email_html = File.read("#{email_template_html_dir}/project_member_joined.html")
+ self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '{nickname1} 已加入项目 {nickname2}/{repository} ', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已加入项目 {nickname2}/{repository}')
+ email_html = File.read("#{email_template_html_dir}/project_member_left.html")
+ self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '{nickname1} 已被移出项目 {nickname2}/{repository} ', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已被移出项目 {nickname2}/{repository}')
+ self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 {nickname2}/{repository} 创建了一个里程碑:{title} ', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}')
+ self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '{nickname} 点赞了你管理的仓库', notification_url: '{baseurl}/{login}')
+ email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
+ self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title} ', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求')
+ email_html = File.read("#{email_template_html_dir}/project_role.html")
+ self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 {nickname}/{repository} 已把你的角色改为 {role} ', email: email_html, email_title: 'GitLink: 在 {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}更改了 {nickname2}/{repository} 仓库设置:{ifname}更改项目名称为"{name} "{endname}{ifidentifier}更改项目标识为"{identifier} "{endidentifier}{ifdescription}更改项目简介为"{description} "{enddescription}{ifcategory}更改项目类别为"{category} "{endcategory}{iflanguage}更改项目语言为"{language} "{endlanguage}{ifpermission}将仓库设为"{permission} "{endpermission}{ifnavbar}将项目导航更改为"{navbar} "{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: 'GitLink: 您管理的仓库 {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}在 {nickname2}/{repository} 创建了发行版:{title} ', 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}在 {nickname2}/{repository} 指派给你一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求')
+ self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '{nickname} 在合并请求 {title} 中@我', 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}的合并请求 {title} 中:{ifassigner}{nickname1}将审查成员从 {assigner1} 修改为 {assigner2} {endassigner}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}', email: email_html, email_title: 'GitLink: 合并请求 {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} 被拒绝 ', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '')
+ self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}:{notes} ', 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} 已通过 ', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
+ end
+
+ def self.sys_notice
+ self.last&.sys_notice
+ end
+
+ def self.email
+ self.last&.email
+ end
+
+ def self.email_title
+ self.last&.email_title
+ end
+
+ def self.notification_url
+ self.last&.notification_url.gsub('{baseurl}', base_url)
+ end
+
+ def self.base_url
+ Rails.application.config_for(:configuration)['platform_url']
+ end
+
+ def self.receivers_string(receivers)
+ receivers.pluck(:id).join(",")
+ end
+
+ def self.receivers_email_string(receivers)
+ receivers.pluck(:mail).join(",")
+ end
+
+ def self.email_template_html_dir
+ "#{Rails.root}/public/message_template"
+ end
+
+ def simple_type
+ self.type.split("::")[-1]
+ end
+end
diff --git a/app/models/message_template/followed_tip.rb b/app/models/message_template/followed_tip.rb
new file mode 100644
index 000000000..6231db595
--- /dev/null
+++ b/app/models/message_template/followed_tip.rb
@@ -0,0 +1,24 @@
+# == 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::FollowedTip < MessageTemplate
+
+ # MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
+ def self.get_message_content(receivers, followeder)
+ return receivers_string(receivers), sys_notice.gsub('{nickname}', followeder&.real_name), notification_url.gsub('{login}', followeder.login)
+ rescue
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_assigned.rb b/app/models/message_template/issue_assigned.rb
new file mode 100644
index 000000000..23632c3ef
--- /dev/null
+++ b/app/models/message_template/issue_assigned.rb
@@ -0,0 +1,63 @@
+# == 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::IssueAssigned < MessageTemplate
+
+ # MessageTemplate::IssueAssigned.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last)
+ def self.get_message_content(receivers, operator, issue)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::IssueAssigned"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ project = issue&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).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::IssueAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, issue)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::IssueAssigned"]
+ end
+ project = issue&.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!('{nickname1}', operator&.real_name)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{login2}', 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)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueAssigned.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_assigner_expire.rb b/app/models/message_template/issue_assigner_expire.rb
new file mode 100644
index 000000000..405d44bb4
--- /dev/null
+++ b/app/models/message_template/issue_assigner_expire.rb
@@ -0,0 +1,29 @@
+# == 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::IssueAssignerExpire < MessageTemplate
+
+ # MessageTemplate::IssueAssignerExpire.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
diff --git a/app/models/message_template/issue_atme.rb b/app/models/message_template/issue_atme.rb
new file mode 100644
index 000000000..d9dfd1957
--- /dev/null
+++ b/app/models/message_template/issue_atme.rb
@@ -0,0 +1,29 @@
+# == 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::IssueAtme < MessageTemplate
+
+ # MessageTemplate::IssueAtme.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last)
+ def self.get_message_content(receivers, operator, issue)
+ project = issue&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname}', operator&.real_name).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::IssueAtme.get_message_content [ERROR] #{e}")
+ return 0, '', ''
+ end
+end
diff --git a/app/models/message_template/issue_changed.rb b/app/models/message_template/issue_changed.rb
new file mode 100644
index 000000000..90a72d1a0
--- /dev/null
+++ b/app/models/message_template/issue_changed.rb
@@ -0,0 +1,369 @@
+# == 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::IssueChanged < MessageTemplate
+
+ # MessageTemplate::IssueChanged.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last, {status_id: [1, 2], assigned_to_id: [nil, 203], tracker_id: [4, 3], priority_id: [2, 4], fixed_version_id: [nil, 5], due_date: ['', '2021-09-11'], done_ratio: [0, 40], issue_tags_value: ["", "7"], branch_name: ["", "master"]})
+ def self.get_message_content(receivers, operator, issue, change_params)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ return '', '', '' if change_params.blank?
+ project = issue&.project
+ owner = project&.owner
+ content = MessageTemplate::IssueChanged.sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{title}', issue&.subject)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
+ change_count = change_params.keys.size
+ # 易修负责人修改
+ if change_params[:assigned_to_id].present?
+ assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
+ assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
+ if change_count > 1
+ content.sub!('{ifassigner}', ' ')
+ else
+ content.sub!('{ifassigner}', '')
+ end
+ content.sub!('{endassigner}', '')
+ content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员')
+ content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员')
+ else
+ content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
+ end
+ # 易修状态修改
+ if change_params[:status_id].present?
+ status1 = IssueStatus.find_by_id(change_params[:status_id][0])
+ status2 = IssueStatus.find_by_id(change_params[:status_id][1])
+ if change_count > 1
+ content.sub!('{ifstatus}', ' ')
+ else
+ content.sub!('{ifstatus}', '')
+ end
+ content.sub!('{endstatus}', '')
+ content.gsub!('{status1}', status1&.name)
+ content.gsub!('{status2}', status2&.name)
+ else
+ content.gsub!(/({ifstatus})(.*)({endstatus})/, '')
+ end
+ # 易修类型修改
+ if change_params[:tracker_id].present?
+ tracker1 = Tracker.find_by_id(change_params[:tracker_id][0])
+ tracker2 = Tracker.find_by_id(change_params[:tracker_id][1])
+ if change_count > 1
+ content.sub!('{iftracker}', ' ')
+ else
+ content.sub!('{iftracker}', '')
+ end
+ content.sub!('{endtracker}', '')
+ content.gsub!('{tracker1}', tracker1&.name)
+ content.gsub!('{tracker2}', tracker2&.name)
+ else
+ content.gsub!(/({iftracker})(.*)({endtracker})/, '')
+ end
+ # 易修里程碑修改
+ if change_params[:fixed_version_id].present?
+ fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
+ fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
+ if change_count > 1
+ content.sub!('{ifmilestone}', ' ')
+ else
+ content.sub!('{ifmilestone}', '')
+ end
+ content.sub!('{endmilestone}', '')
+ content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑')
+ content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑')
+ else
+ content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
+ end
+ # 易修标记修改
+ if change_params[:issue_tags_value].present?
+ issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
+ issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
+ tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",")
+ tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",")
+ if change_count > 1
+ content.sub!('{iftag}', ' ')
+ else
+ content.sub!('{iftag}', '')
+ end
+ content.sub!('{endtag}', '')
+ content.gsub!('{tag1}', tag1)
+ content.gsub!('{tag2}', tag2)
+ else
+ content.gsub!(/({iftag})(.*)({endtag})()/, '')
+ end
+ # 易修优先级修改
+ if change_params[:priority_id].present?
+ priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
+ priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
+ if change_count > 1
+ content.sub!('{ifpriority}', ' ')
+ else
+ content.sub!('{ifpriority}', '')
+ end
+ content.sub!('{endpriority}', '')
+ content.gsub!('{priority1}', priority1&.name)
+ content.gsub!('{priority2}', priority2&.name)
+ else
+ content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
+ end
+ # 易修完成度修改
+ if change_params[:done_ratio].present?
+ doneratio1 = change_params[:done_ratio][0]
+ doneratio2 = change_params[:done_ratio][1]
+ if change_count > 1
+ content.sub!('{ifdoneratio}', ' ')
+ else
+ content.sub!('{ifdoneratio}', '')
+ end
+ content.sub!('{enddoneratio}', '')
+ content.gsub!('{doneratio1}', "#{doneratio1}%")
+ content.gsub!('{doneratio2}', "#{doneratio2}%")
+ else
+ content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '')
+ end
+ # 易修指定分支修改
+ if change_params[:branch_name].present?
+ branch1 = change_params[:branch_name][0].blank? ? '分支未指定' : change_params[:branch_name][0]
+ branch2 = change_params[:branch_name][1].blank? ? '分支未指定' : change_params[:branch_name][1]
+ if change_count > 1
+ content.sub!('{ifbranch}', ' ')
+ else
+ content.sub!('{ifbranch}', '')
+ end
+ content.sub!('{endbranch}', '')
+ content.gsub!('{branch1}', branch1)
+ content.gsub!('{branch2}', branch2)
+ else
+ content.gsub!(/({ifbranch})(.*)({endbranch})/, '')
+ end
+ # 易修开始日期修改
+ if change_params[:start_date].present?
+ startdate1 = change_params[:start_date][0].blank? ? "未选择开始日期" : change_params[:start_date][0]
+ startdate2 = change_params[:start_date][1].blank? ? "未选择开始日期" : change_params[:start_date][1]
+ if change_count > 1
+ content.sub!('{ifstartdate}', ' ')
+ else
+ content.sub!('{ifstartdate}', '')
+ end
+ content.sub!('{endstartdate}', '')
+ content.gsub!('{startdate1}', startdate1 )
+ content.gsub!('{startdate2}', startdate2)
+ else
+ content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '')
+ end
+ # 易修结束日期修改
+ if change_params[:due_date].present?
+ duedate1 = change_params[:due_date][0].blank? ? '未选择结束日期' : change_params[:due_date][0]
+ duedate2 = change_params[:due_date][1].blank? ? '未选择结束日期' : change_params[:due_date][1]
+ if change_count > 1
+ content.sub!('{ifduedate}', ' ')
+ else
+ content.sub!('{ifduedate}', '')
+ end
+ content.sub!('{endduedate}', '')
+ content.gsub!('{duedate1}', duedate1)
+ content.gsub!('{duedate2}', duedate2)
+ else
+ content.gsub!(/({ifduedate})(.*)({endduedate})/, '')
+ end
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, issue, change_params)
+ return '', '', '' if change_params.blank?
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::IssueChanged"]
+ end
+ project = issue&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{title}', issue&.subject)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{title}', issue&.subject)
+ content.gsub!('{id}', issue&.id.to_s)
+ change_count = change_params.keys.size
+ # 易修负责人修改
+ if change_params[:assigned_to_id].present?
+ assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
+ assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
+ if change_count > 1
+ content.sub!('{ifassigner}', ' ')
+ else
+ content.sub!('{ifassigner}', '')
+ end
+ content.sub!('{endassigner}', '')
+ content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员')
+ content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员')
+ else
+ content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
+ end
+ # 易修状态修改
+ if change_params[:status_id].present?
+ status1 = IssueStatus.find_by_id(change_params[:status_id][0])
+ status2 = IssueStatus.find_by_id(change_params[:status_id][1])
+ if change_count > 1
+ content.sub!('{ifstatus}', ' ')
+ else
+ content.sub!('{ifstatus}', '')
+ end
+ content.sub!('{endstatus}', '')
+ content.gsub!('{status1}', status1&.name)
+ content.gsub!('{status2}', status2&.name)
+ else
+ content.gsub!(/({ifstatus})(.*)({endstatus})/, '')
+ end
+ # 易修类型修改
+ if change_params[:tracker_id].present?
+ tracker1 = Tracker.find_by_id(change_params[:tracker_id][0])
+ tracker2 = Tracker.find_by_id(change_params[:tracker_id][1])
+ if change_count > 1
+ content.sub!('{iftracker}', ' ')
+ else
+ content.sub!('{iftracker}', '')
+ end
+ content.sub!('{endtracker}', '')
+ content.gsub!('{tracker1}', tracker1&.name)
+ content.gsub!('{tracker2}', tracker2&.name)
+ else
+ content.gsub!(/({iftracker})(.*)({endtracker})/, '')
+ end
+ # 易修里程碑修改
+ if change_params[:fixed_version_id].present?
+ fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
+ fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
+ if change_count > 1
+ content.sub!('{ifmilestone}', ' ')
+ else
+ content.sub!('{ifmilestone}', '')
+ end
+ content.sub!('{endmilestone}', '')
+ content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑')
+ content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑')
+ else
+ content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
+ end
+ # 易修标记修改
+ if change_params[:issue_tags_value].present?
+ issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
+ issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
+ tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",")
+ tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",")
+ if change_count > 1
+ content.sub!('{iftag}', ' ')
+ else
+ content.sub!('{iftag}', '')
+ end
+ content.sub!('{endtag}', '')
+ content.gsub!('{tag1}', tag1)
+ content.gsub!('{tag2}', tag2)
+ else
+ content.gsub!(/({iftag})(.*)({endtag})()/, '')
+ end
+ # 易修优先级修改
+ if change_params[:priority_id].present?
+ priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
+ priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
+ if change_count > 1
+ content.sub!('{ifpriority}', ' ')
+ else
+ content.sub!('{ifpriority}', '')
+ end
+ content.sub!('{endpriority}', '')
+ content.gsub!('{priority1}', priority1&.name)
+ content.gsub!('{priority2}', priority2&.name)
+ else
+ content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
+ end
+ # 易修完成度修改
+ if change_params[:done_ratio].present?
+ doneratio1 = change_params[:done_ratio][0]
+ doneratio2 = change_params[:done_ratio][1]
+ if change_count > 1
+ content.sub!('{ifdoneratio}', ' ')
+ else
+ content.sub!('{ifdoneratio}', '')
+ end
+ content.sub!('{enddoneratio}', '')
+ content.gsub!('{doneratio1}', "#{doneratio1}%")
+ content.gsub!('{doneratio2}', "#{doneratio2}%")
+ else
+ content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '')
+ end
+ # 易修指定分支修改
+ if change_params[:branch_name].present?
+ branch1 = change_params[:branch_name][0].blank? ? '分支未指定' : change_params[:branch_name][0]
+ branch2 = change_params[:branch_name][1].blank? ? '分支未指定' : change_params[:branch_name][1]
+ if change_count > 1
+ content.sub!('{ifbranch}', ' ')
+ else
+ content.sub!('{ifbranch}', '')
+ end
+ content.sub!('{endbranch}', '')
+ content.gsub!('{branch1}', branch1)
+ content.gsub!('{branch2}', branch2)
+ else
+ content.gsub!(/({ifbranch})(.*)({endbranch})/, '')
+ end
+ # 易修开始日期修改
+ if change_params[:start_date].present?
+ startdate1 = change_params[:start_date][0].blank? ? "未选择开始日期" : change_params[:start_date][0]
+ startdate2 = change_params[:start_date][1].blank? ? "未选择开始日期" : change_params[:start_date][1]
+ if change_count > 1
+ content.sub!('{ifstartdate}', ' ')
+ else
+ content.sub!('{ifstartdate}', '')
+ end
+ content.sub!('{endstartdate}', '')
+ content.gsub!('{startdate1}', startdate1 )
+ content.gsub!('{startdate2}', startdate2)
+ else
+ content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '')
+ end
+ # 易修结束日期修改
+ if change_params[:due_date].present?
+ duedate1 = change_params[:due_date][0].blank? ? '未选择结束日期' : change_params[:due_date][0]
+ duedate2 = change_params[:due_date][1].blank? ? '未选择结束日期' : change_params[:due_date][1]
+ if change_count > 1
+ content.sub!('{ifduedate}', ' ')
+ else
+ content.sub!('{ifduedate}', '')
+ end
+ content.sub!('{endduedate}', '')
+ content.gsub!('{duedate1}', duedate1)
+ content.gsub!('{duedate2}', duedate2)
+ else
+ content.gsub!(/({ifduedate})(.*)({endduedate})/, '')
+ end
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueChanged.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_creator_expire.rb b/app/models/message_template/issue_creator_expire.rb
new file mode 100644
index 000000000..38ef2fe29
--- /dev/null
+++ b/app/models/message_template/issue_creator_expire.rb
@@ -0,0 +1,29 @@
+# == 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
diff --git a/app/models/message_template/issue_deleted.rb b/app/models/message_template/issue_deleted.rb
new file mode 100644
index 000000000..c08ee0439
--- /dev/null
+++ b/app/models/message_template/issue_deleted.rb
@@ -0,0 +1,51 @@
+# == 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::IssueDeleted < MessageTemplate
+
+ # MessageTemplate::IssueDeleted.get_message_content(User.where(login: 'yystopf'), User.last, "hahah")
+ def self.get_message_content(receivers, operator, issue_title)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{nickname}', operator&.real_name).gsub('{title}', issue_title)
+ return receivers_string(receivers), content, notification_url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueDeleted.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, issue_title)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::IssueChanged"]
+ end
+ title = email_title
+ title.gsub!('{title}', issue_title)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{nickname}', operator&.real_name)
+ content.gsub!('{login}', operator&.login)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{title}', issue_title)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueDeleted.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_journal.rb b/app/models/message_template/issue_journal.rb
new file mode 100644
index 000000000..0b3851475
--- /dev/null
+++ b/app/models/message_template/issue_journal.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我创建或负责的易修有新的评论
+class MessageTemplate::IssueJournal < MessageTemplate
+
+ # MessageTemplate::IssueJournal.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueJournal.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/login_ip_tip.rb b/app/models/message_template/login_ip_tip.rb
new file mode 100644
index 000000000..5c7caa936
--- /dev/null
+++ b/app/models/message_template/login_ip_tip.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 登录异常提示
+class MessageTemplate::LoginIpTip < MessageTemplate
+
+ # MessageTemplate::LoginIpTip.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::LoginIpTip.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_joined.rb b/app/models/message_template/organization_joined.rb
new file mode 100644
index 000000000..22cfb48d0
--- /dev/null
+++ b/app/models/message_template/organization_joined.rb
@@ -0,0 +1,51 @@
+# == 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::OrganizationJoined < MessageTemplate
+
+ # MessageTemplate::OrganizationJoined.get_message_content(User.where(login: 'yystopf'), Organization.last)
+ def self.get_message_content(receivers, organization)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Organization"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{organization}', organization&.real_name)
+ url = notification_url.gsub('{login}', organization&.name)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Organization"]
+ end
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_left.rb b/app/models/message_template/organization_left.rb
new file mode 100644
index 000000000..eee752f05
--- /dev/null
+++ b/app/models/message_template/organization_left.rb
@@ -0,0 +1,51 @@
+# == 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::OrganizationLeft < MessageTemplate
+
+ # MessageTemplate::OrganizationLeft.get_message_content(User.where(login: 'yystopf'), Organization.last)
+ def self.get_message_content(receivers, organization)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Organization"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{organization}', organization&.real_name)
+ url = notification_url.gsub('{login}', organization&.name)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Organization"]
+ end
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_role.rb b/app/models/message_template/organization_role.rb
new file mode 100644
index 000000000..b6024f614
--- /dev/null
+++ b/app/models/message_template/organization_role.rb
@@ -0,0 +1,53 @@
+# == 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::OrganizationRole < MessageTemplate
+
+ # MessageTemplate::OrganizationRole.get_message_content(User.where(login: 'yystopf'), Organization.last, '管理员')
+ def self.get_message_content(receivers, organization, role)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Permission"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{organization}', organization&.real_name).gsub('{role}', role)
+ url = notification_url.gsub('{login}', organization&.login)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationRole.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization, role)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Permission"]
+ end
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ title.gsub!('{role}', role)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+ content.gsub!('{role}', role)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationRole.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_deleted.rb b/app/models/message_template/project_deleted.rb
new file mode 100644
index 000000000..aa45e818e
--- /dev/null
+++ b/app/models/message_template/project_deleted.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库被删除
+class MessageTemplate::ProjectDeleted < MessageTemplate
+
+ # MessageTemplate::ProjectDeleted.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectDeleted.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_followed.rb b/app/models/message_template/project_followed.rb
new file mode 100644
index 000000000..e9dd9a2a8
--- /dev/null
+++ b/app/models/message_template/project_followed.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被关注
+class MessageTemplate::ProjectFollowed < MessageTemplate
+
+ # MessageTemplate::ProjectFollowed.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectFollowed.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_forked.rb b/app/models/message_template/project_forked.rb
new file mode 100644
index 000000000..7cd17222d
--- /dev/null
+++ b/app/models/message_template/project_forked.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被复刻
+class MessageTemplate::ProjectForked < MessageTemplate
+
+ # MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_issue.rb b/app/models/message_template/project_issue.rb
new file mode 100644
index 000000000..9106bcc8f
--- /dev/null
+++ b/app/models/message_template/project_issue.rb
@@ -0,0 +1,66 @@
+# == 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)
+#
+
+# TODO 我管理/关注的仓库有新的易修
+class MessageTemplate::ProjectIssue < MessageTemplate
+
+ # MessageTemplate::ProjectIssue.get_message_content(User.where(login: 'yystopf'), User.where(login: 'forgetest1'), User.last, Issue.last)
+ def self.get_message_content(managers, followers, operator, issue)
+ managers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ managers = managers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Issue"]
+ end
+ end
+ project = issue&.project
+ owner = project&.owner
+ receivers = managers + followers
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).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::ProjectIssue.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, is_manager, operator, issue)
+ if receiver.user_template_message_setting.present? && is_manager
+ return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::Issue"]
+ end
+ project = issue&.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!('{login1}', operator&.login)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{id}', issue&.id.to_s)
+ content.gsub!('{title}', issue&.subject)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectIssue.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_joined.rb b/app/models/message_template/project_joined.rb
new file mode 100644
index 000000000..b46dc51a7
--- /dev/null
+++ b/app/models/message_template/project_joined.rb
@@ -0,0 +1,54 @@
+# == 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::ProjectJoined < MessageTemplate
+
+ # MessageTemplate::ProjectJoined.get_message_content(User.where(login: 'yystopf'), Project.last)
+ def self.get_message_content(receivers, project)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Project"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, project)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Project"]
+ end
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_left.rb b/app/models/message_template/project_left.rb
new file mode 100644
index 000000000..3dfa7bb61
--- /dev/null
+++ b/app/models/message_template/project_left.rb
@@ -0,0 +1,53 @@
+# == 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::ProjectLeft < MessageTemplate
+
+ # MessageTemplate::ProjectLeft.get_message_content(User.where(login: 'yystopf'), Project.last)
+ def self.get_message_content(receivers, project)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Project"]
+ end
+ end
+ content = sys_notice.gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, project)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Project"]
+ end
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_member_joined.rb b/app/models/message_template/project_member_joined.rb
new file mode 100644
index 000000000..7a781750c
--- /dev/null
+++ b/app/models/message_template/project_member_joined.rb
@@ -0,0 +1,58 @@
+# == 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::ProjectMemberJoined < MessageTemplate
+
+ # MessageTemplate::ProjectMemberJoined.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers, user, project)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Member"]
+ 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}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, user, project)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::Member"]
+ end
+ title = email_title
+ title.gsub!('{nickname1}', user&.real_name)
+ title.gsub!('{nickname2}', project&.owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login1}', user&.login)
+ content.gsub!('{login2}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname1}', user&.real_name)
+ content.gsub!('{nickname2}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_member_left.rb b/app/models/message_template/project_member_left.rb
new file mode 100644
index 000000000..f41791233
--- /dev/null
+++ b/app/models/message_template/project_member_left.rb
@@ -0,0 +1,58 @@
+# == 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::ProjectMemberLeft < MessageTemplate
+
+ # MessageTemplate::ProjectMemberLeft.get_message_content(User.where(login: 'yystopf'), User.last, Project.last)
+ def self.get_message_content(receivers, user, project)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Member"]
+ 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}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, user, project)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::Member"]
+ end
+ title = email_title
+ title.gsub!('{nickname1}', user&.real_name)
+ title.gsub!('{nickname2}', project&.owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login1}', user&.login)
+ content.gsub!('{login2}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname1}', user&.real_name)
+ content.gsub!('{nickname2}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_milestone.rb b/app/models/message_template/project_milestone.rb
new file mode 100644
index 000000000..14f992cdd
--- /dev/null
+++ b/app/models/message_template/project_milestone.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库有新的里程碑
+class MessageTemplate::ProjectMilestone < MessageTemplate
+
+ # MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_praised.rb b/app/models/message_template/project_praised.rb
new file mode 100644
index 000000000..e6acee6f5
--- /dev/null
+++ b/app/models/message_template/project_praised.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被点赞
+class MessageTemplate::ProjectPraised < MessageTemplate
+
+ # MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_pull_request.rb b/app/models/message_template/project_pull_request.rb
new file mode 100644
index 000000000..ac04651ef
--- /dev/null
+++ b/app/models/message_template/project_pull_request.rb
@@ -0,0 +1,66 @@
+# == 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)
+#
+
+# TODO 我管理/关注的仓库有新的合并请求
+class MessageTemplate::ProjectPullRequest < MessageTemplate
+
+ # MessageTemplate::ProjectPullRequest.get_message_content(User.where(login: 'yystopf'), User.where(login: 'testforge2'), User.last, PullRequest.last)
+ def self.get_message_content(managers, followers, operator, pull_request)
+ managers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ managers = managers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::PullRequest"]
+ end
+ end
+ project = pull_request&.project
+ owner = project&.owner
+ receivers = managers + followers
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPullRequest.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, is_manager, operator, pull_request)
+ if receiver.user_template_message_setting.present? && is_manager
+ return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::PullRequest"]
+ end
+ project = pull_request&.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!('{login1}', operator&.login)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{id}', pull_request&.id.to_s)
+ content.gsub!('{title}', pull_request&.title)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPullRequest.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_role.rb b/app/models/message_template/project_role.rb
new file mode 100644
index 000000000..e306f5c02
--- /dev/null
+++ b/app/models/message_template/project_role.rb
@@ -0,0 +1,56 @@
+# == 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::ProjectRole < MessageTemplate
+
+ # MessageTemplate::ProjectRole.get_message_content(User.where(login: 'yystopf'), Project.last, '管理员')
+ def self.get_message_content(receivers, project, role)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Permission"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ content = sys_notice.gsub('{nickname}', project&.owner&.real_name).gsub('{repository}', project&.name).gsub('{role}', role)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectRole.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, project, role)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Permission"]
+ end
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+ title.gsub!('{role}', role)
+ title.gsub!('{nickname}', project&.owner&.real_name)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{nickname}', project&.owner&.real_name)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{role}', role)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectRole.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_setting_changed.rb b/app/models/message_template/project_setting_changed.rb
new file mode 100644
index 000000000..457ab9207
--- /dev/null
+++ b/app/models/message_template/project_setting_changed.rb
@@ -0,0 +1,310 @@
+# == 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::ProjectSettingChanged < MessageTemplate
+
+ # MessageTemplate::ProjectSettingChanged.get_message_content(User.where(login: 'yystopf'), User.last, Project.last, {description: '测试修改项目简介', category: '大数据', language: 'Ruby', permission: '公有', navbar: '易修, 合并请求'})
+ def self.get_message_content(receivers, operator, project, change_params)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::SettingChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ return '', '', '' if change_params.blank?
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier)
+ change_count = change_params.keys.size
+ # 项目名称更改
+ if change_params[:name].present?
+ if change_count > 1
+ content.sub!('{ifname}', ' ')
+ else
+ content.sub!('{ifname}', '')
+ end
+ content.sub!('{endname}', '')
+ content.gsub!('{name}', change_params[:name][1])
+ else
+ content.gsub!(/({ifname})(.*)({endname})/, '')
+ end
+ # 项目标识更改
+ if change_params[:identifier].present?
+ if change_count > 1
+ content.sub!('{ifidentifier}', ' ')
+ else
+ content.sub!('{ifidentifier}', '')
+ end
+ content.sub!('{endidentifier}', '')
+ content.gsub!('{identifier}', change_params[:identifier][1])
+ else
+ content.gsub!(/({ifidentifier})(.*)({endidentifier})/, '')
+ end
+ # 项目简介更改
+ if change_params[:description].present?
+ if change_params[:description][1].blank?
+ if change_count > 1
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, ' 删除了项目简介')
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '删除了项目简介')
+ end
+ else
+ if change_count > 1
+ content.sub!('{ifdescription}', ' ')
+ else
+ content.sub!('{ifdescription}', '')
+ end
+ content.sub!('{enddescription}', '')
+ content.gsub!('{description}', change_params[:description][1])
+ end
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '')
+ end
+ # 项目类别更改
+ if change_params[:project_category_id].present?
+ category = ProjectCategory.find_by_id(change_params[:project_category_id][1])
+ if category.present?
+ if change_count > 1
+ content.sub!('{ifcategory}', ' ')
+ else
+ content.sub!('{ifcategory}', '')
+ end
+ content.sub!('{endcategory}', '')
+ content.gsub!('{category}', category&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, ' 删除了项目类别')
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '删除了项目类别')
+ end
+ end
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '')
+ end
+ # 项目语言更改
+ if change_params[:project_language_id].present?
+ language = ProjectLanguage.find_by_id(change_params[:project_language_id][1])
+ if language.present?
+ if change_count > 1
+ content.sub!('{iflanguage}', ' ')
+ else
+ content.sub!('{iflanguage}', '')
+ end
+ content.sub!('{endlanguage}', '')
+ content.gsub!('{language}', language&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, ' 删除了项目语言')
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '删除了项目语言')
+ end
+ end
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '')
+ end
+ # 项目公私有更改
+ if change_params[:is_public].present?
+ permission = change_params[:is_public][1] ? '公有' : '私有'
+ if change_count > 1
+ content.sub!('{ifpermission}', ' ')
+ else
+ content.sub!('{ifpermission}', '')
+ end
+ content.sub!('{endpermission}', '')
+ content.gsub!('{permission}', permission)
+ else
+ content.gsub!(/({ifpermission})(.*)({endpermission})/, '')
+ end
+ # 项目导航更改
+ if change_params[:navbar].present?
+ unit_types = project.project_units.order(unit_type: :asc).pluck(:unit_type)
+ unit_types.delete('code')
+ unit_types.unshift('代码库')
+ unit_types.unshift('主页')
+ unit_types.append('动态')
+ navbar = unit_types.join(',')
+ navbar.gsub!('issues', '易修')
+ navbar.gsub!('pulls', '合并请求')
+ navbar.gsub!('wiki', 'Wiki')
+ navbar.gsub!('devops', '工作流')
+ navbar.gsub!('versions', '里程碑')
+ navbar.gsub!('resources', '资源库')
+ if change_count > 1
+ content.sub!('{ifnavbar}', ' ')
+ else
+ content.sub!('{ifnavbar}', '')
+ end
+ content.sub!('{endnavbar}', '')
+ content.gsub!('{navbar}', navbar)
+ else
+ content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
+ end
+
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, project, change_params)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::SettingChanged"]
+ end
+ return '', '', '' if change_params.blank?
+ owner = project&.owner
+ title = email_title
+ 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!('{login1}', operator&.login)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ change_count = change_params.keys.size
+ # 项目名称更改
+ if change_params[:name].present?
+ if change_count > 1
+ content.sub!('{ifname}', ' ')
+ else
+ content.sub!('{ifname}', '')
+ end
+ content.sub!('{endname}', '')
+ content.gsub!('{name}', change_params[:name][1])
+ else
+ content.gsub!(/({ifname})(.*)({endname})/, '')
+ end
+ # 项目标识更改
+ if change_params[:identifier].present?
+ if change_count > 1
+ content.sub!('{ifidentifier}', ' ')
+ else
+ content.sub!('{ifidentifier}', '')
+ end
+ content.sub!('{endidentifier}', '')
+ content.gsub!('{identifier}', change_params[:identifier][1])
+ else
+ content.gsub!(/({ifidentifier})(.*)({endidentifier})/, '')
+ end
+ # 项目简介更改
+ if change_params[:description].present?
+ if change_params[:description][1].blank?
+ if change_count > 1
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, ' 删除了项目简介')
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '删除了项目简介')
+ end
+ else
+ if change_count > 1
+ content.sub!('{ifdescription}', ' ')
+ else
+ content.sub!('{ifdescription}', '')
+ end
+ content.sub!('{enddescription}', '')
+ content.gsub!('{description}', change_params[:description][1])
+ end
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '')
+ end
+ # 项目类别更改
+ if change_params[:project_category_id].present?
+ category = ProjectCategory.find_by_id(change_params[:project_category_id][1])
+ if category.present?
+ if change_count > 1
+ content.sub!('{ifcategory}', ' ')
+ else
+ content.sub!('{ifcategory}', '')
+ end
+ content.sub!('{endcategory}', '')
+ content.gsub!('{category}', category&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, ' 删除了项目类别')
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '删除了项目类别')
+ end
+ end
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '')
+ end
+ # 项目语言更改
+ if change_params[:project_language_id].present?
+ language = ProjectLanguage.find_by_id(change_params[:project_language_id][1])
+ if language.present?
+ if change_count > 1
+ content.sub!('{iflanguage}', ' ')
+ else
+ content.sub!('{iflanguage}', '')
+ end
+ content.sub!('{endlanguage}', '')
+ content.gsub!('{language}', language&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, ' 删除了项目语言')
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '删除了项目语言')
+ end
+ end
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '')
+ end
+ # 项目公私有更改
+ if change_params[:is_public].present?
+ permission = change_params[:is_public][1] ? '公有' : '私有'
+ if change_count > 1
+ content.sub!('{ifpermission}', ' ')
+ else
+ content.sub!('{ifpermission}', '')
+ end
+ content.sub!('{endpermission}', '')
+ content.gsub!('{permission}', permission)
+ else
+ content.gsub!(/({ifpermission})(.*)({endpermission})/, '')
+ end
+ # 项目导航更改
+ if change_params[:navbar].present?
+ unit_types = project.project_units.order(unit_type: :asc).pluck(:unit_type)
+ unit_types.delete('code')
+ unit_types.unshift('代码库')
+ unit_types.unshift('主页')
+ unit_types.append('动态')
+ navbar = unit_types.join(',')
+ navbar.gsub!('issues', '易修')
+ navbar.gsub!('pulls', '合并请求')
+ navbar.gsub!('wiki', 'Wiki')
+ navbar.gsub!('devops', '工作流')
+ navbar.gsub!('versions', '里程碑')
+ navbar.gsub!('resources', '资源库')
+ if change_count > 1
+ content.sub!('{ifnavbar}', ' ')
+ else
+ content.sub!('{ifnavbar}', '')
+ end
+ content.sub!('{endnavbar}', '')
+ content.gsub!('{navbar}', navbar)
+ else
+ content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
+ end
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_transfer.rb b/app/models/message_template/project_transfer.rb
new file mode 100644
index 000000000..7a99276ba
--- /dev/null
+++ b/app/models/message_template/project_transfer.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库被转移
+class MessageTemplate::ProjectTransfer < MessageTemplate
+
+ # MessageTemplate::ProjectTransfer.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectTransfer.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_version.rb b/app/models/message_template/project_version.rb
new file mode 100644
index 000000000..14ae46306
--- /dev/null
+++ b/app/models/message_template/project_version.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库有新的发行版
+class MessageTemplate::ProjectVersion < MessageTemplate
+
+ # MessageTemplate::ProjectVersion.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectVersion.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_assigned.rb b/app/models/message_template/pull_request_assigned.rb
new file mode 100644
index 000000000..1101ca46b
--- /dev/null
+++ b/app/models/message_template/pull_request_assigned.rb
@@ -0,0 +1,63 @@
+# == 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::PullRequestAssigned < MessageTemplate
+
+ # MessageTemplate::PullRequestAssigned.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::PullRequestAssigned"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, pull_request)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::PullRequestAssigned"]
+ end
+ project = pull_request&.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!('{nickname1}', operator&.real_name)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{title}', pull_request&.title)
+ content.gsub!('{id}', pull_request&.id.to_s)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestAssigned.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_atme.rb b/app/models/message_template/pull_request_atme.rb
new file mode 100644
index 000000000..54f8c9585
--- /dev/null
+++ b/app/models/message_template/pull_request_atme.rb
@@ -0,0 +1,29 @@
+# == 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::PullRequestAtme < MessageTemplate
+
+ # MessageTemplate::PullRequestAtme.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname}', operator&.real_name).gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestAtme.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_changed.rb b/app/models/message_template/pull_request_changed.rb
new file mode 100644
index 000000000..fc4457f37
--- /dev/null
+++ b/app/models/message_template/pull_request_changed.rb
@@ -0,0 +1,193 @@
+# == 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::PullRequestChanged < MessageTemplate
+
+ # MessageTemplate::PullRequestChanged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last, {assigned_to_id: [nil, 203], priority_id: [2, 4], fixed_version_id: [nil, 5], issue_tags_value: ["", "7"]})
+ def self.get_message_content(receivers, operator, pull_request, change_params)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ return '', '', '' if change_params.blank?
+ project = pull_request&.project
+ owner = project&.owner
+ issue = pull_request&.issue
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub("{title}", pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ change_count = change_params.keys.size
+ # 合并请求审查成员修改
+ if change_params[:assigned_to_id].present?
+ assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
+ assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
+ if change_count > 1
+ content.sub!('{ifassigner}', ' ')
+ else
+ content.sub!('{ifassigner}', '')
+ end
+ content.sub!('{endassigner}', '')
+ content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员')
+ content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员')
+ else
+ content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
+ end
+ # 合并请求里程碑修改
+ if change_params[:fixed_version_id].present?
+ fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
+ fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
+ if change_count > 1
+ content.sub!('{ifmilestone}', ' ')
+ else
+ content.sub!('{ifmilestone}', '')
+ end
+ content.sub!('{endmilestone}', '')
+ content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑')
+ content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑')
+ else
+ content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
+ end
+ # 合并请求标记修改
+ if change_params[:issue_tags_value].present?
+ issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
+ issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
+ tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",")
+ tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",")
+ if change_count > 1
+ content.sub!('{iftag}', ' ')
+ else
+ content.sub!('{iftag}', '')
+ end
+ content.sub!('{endtag}', '')
+ content.gsub!('{tag1}', tag1)
+ content.gsub!('{tag2}', tag2)
+ else
+ content.gsub!(/({iftag})(.*)({endtag})()/, '')
+ end
+ # 合并请求优先级修改
+ if change_params[:priority_id].present?
+ priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
+ priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
+ if change_count > 1
+ content.sub!('{ifpriority}', ' ')
+ else
+ content.sub!('{ifpriority}', '')
+ end
+ content.sub!('{ifpriority}', '')
+ content.sub!('{endpriority}', '')
+ content.gsub!('{priority1}', priority1&.name)
+ content.gsub!('{priority2}', priority2&.name)
+ else
+ content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
+ end
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestChanged.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, pull_request, change_params)
+ return '', '', '' if change_params.blank?
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"]
+ end
+ project = pull_request&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{title}', pull_request&.title)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{title}', pull_request&.title)
+ content.gsub!('{id}', pull_request&.id.to_s)
+
+ change_count = change_params.keys.size
+ # 合并请求审查成员修改
+ if change_params[:assigned_to_id].present?
+ assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
+ assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
+ if change_count > 1
+ content.sub!('{ifassigner}', ' ')
+ else
+ content.sub!('{ifassigner}', '')
+ end
+ content.sub!('{endassigner}', '')
+ content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员')
+ content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员')
+ else
+ content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
+ end
+ # 合并请求里程碑修改
+ if change_params[:fixed_version_id].present?
+ fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
+ fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
+ if change_count > 1
+ content.sub!('{ifmilestone}', ' ')
+ else
+ content.sub!('{ifmilestone}', '')
+ end
+ content.sub!('{endmilestone}', '')
+ content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑')
+ content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑')
+ else
+ content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
+ end
+ # 合并请求标记修改
+ if change_params[:issue_tags_value].present?
+ issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
+ issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
+ tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",")
+ tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",")
+ if change_count > 1
+ content.sub!('{iftag}', ' ')
+ else
+ content.sub!('{iftag}', '')
+ end
+ content.sub!('{endtag}', '')
+ content.gsub!('{tag1}', tag1)
+ content.gsub!('{tag2}', tag2)
+ else
+ content.gsub!(/({iftag})(.*)({endtag})()/, '')
+ end
+ # 合并请求优先级修改
+ if change_params[:priority_id].present?
+ priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
+ priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
+ if change_count > 1
+ content.sub!('{ifpriority}', ' ')
+ else
+ content.sub!('{ifpriority}', '')
+ end
+ content.sub!('{ifpriority}', '')
+ content.sub!('{endpriority}', '')
+ content.gsub!('{priority1}', priority1&.name)
+ content.gsub!('{priority2}', priority2&.name)
+ else
+ content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
+ end
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestChanged.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_closed.rb b/app/models/message_template/pull_request_closed.rb
new file mode 100644
index 000000000..f160ebf20
--- /dev/null
+++ b/app/models/message_template/pull_request_closed.rb
@@ -0,0 +1,61 @@
+# == 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::PullRequestClosed < MessageTemplate
+
+ # MessageTemplate::PullRequestClosed.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', pull_request&.title)
+ url = notification_url
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestClosed.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, pull_request)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"]
+ end
+ project = pull_request&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{title}', pull_request&.title)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{title}', pull_request&.title)
+ content.gsub!('{id}', pull_request&.id.to_s)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestClosed.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_journal.rb b/app/models/message_template/pull_request_journal.rb
new file mode 100644
index 000000000..9b2fae949
--- /dev/null
+++ b/app/models/message_template/pull_request_journal.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我创建或负责的合并请求有新的评论
+class MessageTemplate::PullRequestJournal < MessageTemplate
+
+ # MessageTemplate::PullRequestJournal.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestJournal.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_merged.rb b/app/models/message_template/pull_request_merged.rb
new file mode 100644
index 000000000..3dccffdd7
--- /dev/null
+++ b/app/models/message_template/pull_request_merged.rb
@@ -0,0 +1,61 @@
+# == 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::PullRequestMerged < MessageTemplate
+
+ # MessageTemplate::PullRequestMerged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ receivers.each do |receiver|
+ if receiver.user_template_message_setting.present?
+ receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"]
+ end
+ end
+ return '', '', '' if receivers.blank?
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestMerged.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, pull_request)
+ if receiver.user_template_message_setting.present?
+ return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"]
+ end
+ project = pull_request&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{title}', pull_request&.title)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{nickname1}', operator&.real_name)
+ content.gsub!('{login1}', operator&.login)
+ content.gsub!('{nickname2}', owner&.real_name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{title}', pull_request&.title)
+ content.gsub!('{id}', pull_request&.id.to_s)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestMerged.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/mirror.rb b/app/models/mirror.rb
index 67ef73775..b71dce3fb 100644
--- a/app/models/mirror.rb
+++ b/app/models/mirror.rb
@@ -18,7 +18,7 @@ class Mirror < ApplicationRecord
# 0: 同步镜像成功;1: 正在同步镜像;2: 同步失败; 默认值为0
enum status: { succeeded: 0, waiting: 1, failed: 2 }
- after_update :websocket_boardcast, if: :saved_change_to_status?
+ # after_update :websocket_boardcast, if: :saved_change_to_status?
belongs_to :repository, foreign_key: :repo_id
diff --git a/app/models/organization.rb b/app/models/organization.rb
index 666e13ff2..40c676e05 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
-# platform :string(255) default("0")
-# gitea_token :string(255)
-# gitea_uid :integer
# is_shixun_marker :boolean default("0")
+# admin_visitable :boolean default("0")
+# collaborator :boolean default("0")
+# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
-# sponsor_certification :integer default("0")
-# sponsor_num :integer default("0")
-# sponsored_num :integer default("0")
-# award_time :datetime
+# gitea_token :string(255)
+# platform :string(255)
#
# Indexes
#
@@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
-# index_users_on_login (login)
-# index_users_on_mail (mail)
+# index_users_on_login (login) UNIQUE
+# index_users_on_mail (mail) UNIQUE
+# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#
@@ -77,11 +76,17 @@ class Organization < Owner
validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false
validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
- delegate :description, :website, :location, :repo_admin_change_team_access,
+ delegate :description, :website, :location, :repo_admin_change_team_access, :recommend,
:visibility, :max_repo_creation, :num_projects, :num_users, :num_teams, to: :organization_extension, allow_nil: true
scope :with_visibility, ->(visibility) { joins(:organization_extension).where(organization_extensions: {visibility: visibility}) if visibility.present? }
+ after_save :reset_cache_data
+
+ def reset_cache_data
+ Cache::V2::OwnerCommonService.new(self.id).reset
+ end
+
def self.build(name, nickname, gitea_token=nil)
self.create!(login: name, nickname: nickname, gitea_token: gitea_token)
end
diff --git a/app/models/organization_extension.rb b/app/models/organization_extension.rb
index 8b9946cd7..4b0935208 100644
--- a/app/models/organization_extension.rb
+++ b/app/models/organization_extension.rb
@@ -15,6 +15,7 @@
# num_projects :integer default("0")
# num_users :integer default("0")
# num_teams :integer default("0")
+# recommend :boolean default("0")
#
# Indexes
#
@@ -30,6 +31,8 @@ class OrganizationExtension < ApplicationRecord
enum visibility: {common: 0, limited: 1, privacy: 2}
+ before_save :set_recommend
+
def self.build(organization_id, description, website, location, repo_admin_change_team_access, visibility, max_repo_creation)
self.create!(organization_id: organization_id,
description: description,
@@ -39,4 +42,9 @@ class OrganizationExtension < ApplicationRecord
visibility: visibility,
max_repo_creation: max_repo_creation)
end
+
+ private
+ def set_recommend
+ self.recommend = false unless self.common?
+ end
end
diff --git a/app/models/organization_user.rb b/app/models/organization_user.rb
index cf9e22371..4ff6946b7 100644
--- a/app/models/organization_user.rb
+++ b/app/models/organization_user.rb
@@ -22,6 +22,9 @@ class OrganizationUser < ApplicationRecord
validates :user_id, uniqueness: {scope: :organization_id}
+ after_create :send_create_message_to_notice_system
+ after_destroy :send_destroy_message_to_notice_system
+
def self.build(organization_id, user_id)
org_user = self.find_by(organization_id: organization_id, user_id: user_id)
return org_user unless org_user.nil?
@@ -31,4 +34,12 @@ class OrganizationUser < ApplicationRecord
def teams
organization.teams.joins(:team_users).where(team_users: {user_id: user_id})
end
+
+ def send_create_message_to_notice_system
+ SendTemplateMessageJob.perform_later('OrganizationJoined', self.user_id, self.organization_id) if Site.has_notice_menu?
+ end
+
+ def send_destroy_message_to_notice_system
+ SendTemplateMessageJob.perform_later('OrganizationLeft', self.user_id, self.organization_id) if Site.has_notice_menu?
+ end
end
diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb
index 5a9c19164..5d4ae0d80 100644
--- a/app/models/praise_tread.rb
+++ b/app/models/praise_tread.rb
@@ -1,35 +1,51 @@
-# == Schema Information
-#
-# Table name: praise_treads
-#
-# id :integer not null, primary key
-# user_id :integer not null
-# praise_tread_object_id :integer
-# praise_tread_object_type :string(255)
-# praise_or_tread :integer default("1")
-# created_at :datetime not null
-# updated_at :datetime not null
-#
-# Indexes
-#
-# praise_tread (praise_tread_object_id,praise_tread_object_type)
-#
-
+# == Schema Information
+#
+# Table name: praise_treads
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# praise_tread_object_id :integer
+# praise_tread_object_type :string(255)
+# praise_or_tread :integer default("1")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# praise_tread (praise_tread_object_id,praise_tread_object_type)
+#
+
class PraiseTread < ApplicationRecord
belongs_to :user
belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count
has_many :tidings, :as => :container, :dependent => :destroy
- after_create :send_tiding
- after_save :reset_cache_data
- after_destroy :reset_cache_data
+ after_create :send_tiding, :incre_project_common, :incre_user_statistic, :incre_platform_statistic
+ after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
- def reset_cache_data
- self.reset_platform_cache_async_job
- if self.praise_tread_object.is_a?(Project)
- self.reset_user_cache_async_job(self.praise_tread_object&.owner)
- end
+ def incre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {praises: 1}, self.praise_tread_object_id) if self.praise_tread_object_type == "Project"
+ end
+
+ def decre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {praises: -1}, self.praise_tread_object_id) if self.praise_tread_object_type == "Project"
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_praise_count: 1}, self.praise_tread_object&.user_id) if self.praise_tread_object_type == "Project"
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_praise_count: -1}, self.praise_tread_object&.user_id) if self.praise_tread_object_type == "Project"
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_praise_count: 1}) if self.praise_tread_object_type == "Project"
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_praise_count: -1}) if self.praise_tread_object_type == "Project"
end
def send_tiding
diff --git a/app/models/project.rb b/app/models/project.rb
index eb8a0bbf4..45b93cd00 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1,78 +1,83 @@
-# == Schema Information
-#
-# Table name: projects
-#
-# id :integer not null, primary key
-# name :string(255) default(""), not null
-# description :text(4294967295)
-# homepage :string(255) default("")
-# is_public :boolean default("1"), not null
-# parent_id :integer
-# created_on :datetime
-# updated_on :datetime
-# identifier :string(255)
-# status :integer default("1"), not null
-# lft :integer
-# rgt :integer
-# inherit_members :boolean default("0"), not null
-# project_type :integer default("0")
-# hidden_repo :boolean default("0"), not null
-# attachmenttype :integer default("1")
-# user_id :integer
-# dts_test :integer default("0")
-# enterprise_name :string(255)
-# organization_id :integer
-# project_new_type :integer
-# gpid :integer
-# forked_from_project_id :integer
-# forked_count :integer default("0")
-# publish_resource :integer default("0")
-# visits :integer default("0")
-# hot :integer default("0")
-# invite_code :string(255)
-# qrcode :string(255)
-# qrcode_expiretime :integer default("0")
-# script :text(65535)
-# training_status :integer default("0")
-# rep_identifier :string(255)
-# project_category_id :integer
-# project_language_id :integer
-# license_id :integer
-# ignore_id :integer
-# praises_count :integer default("0")
-# watchers_count :integer default("0")
-# issues_count :integer default("0")
-# pull_requests_count :integer default("0")
-# language :string(255)
-# versions_count :integer default("0")
-# issue_tags_count :integer default("0")
-# closed_issues_count :integer default("0")
-# open_devops :boolean default("0")
-# gitea_webhook_id :integer
-# open_devops_count :integer default("0")
-# recommend :boolean default("0")
-# platform :integer default("0")
-# default_branch :string(255) default("master")
-# website :string(255)
-# order_index :integer default("0")
-# lesson_url :string(255)
-#
-# Indexes
-#
-# index_projects_on_forked_from_project_id (forked_from_project_id)
-# index_projects_on_identifier (identifier)
-# index_projects_on_invite_code (invite_code)
-# index_projects_on_is_public (is_public)
-# index_projects_on_lft (lft)
-# index_projects_on_name (name)
-# index_projects_on_platform (platform)
-# index_projects_on_project_type (project_type)
-# index_projects_on_recommend (recommend)
-# index_projects_on_rgt (rgt)
-# index_projects_on_status (status)
-# index_projects_on_updated_on (updated_on)
-#
-
+
+# == Schema Information
+#
+# Table name: projects
+#
+# id :integer not null, primary key
+# name :string(255) default(""), not null
+# description :text(4294967295)
+# homepage :string(255) default("")
+# is_public :boolean default("1"), not null
+# parent_id :integer
+# created_on :datetime
+# updated_on :datetime
+# identifier :string(255)
+# status :integer default("1"), not null
+# lft :integer
+# rgt :integer
+# inherit_members :boolean default("0"), not null
+# project_type :integer default("0")
+# hidden_repo :boolean default("0"), not null
+# attachmenttype :integer default("1")
+# user_id :integer
+# dts_test :integer default("0")
+# enterprise_name :string(255)
+# organization_id :integer
+# project_new_type :integer
+# gpid :integer
+# forked_from_project_id :integer
+# forked_count :integer default("0")
+# publish_resource :integer default("0")
+# visits :integer default("0")
+# hot :integer default("0")
+# invite_code :string(255)
+# qrcode :string(255)
+# qrcode_expiretime :integer default("0")
+# script :text(65535)
+# training_status :integer default("0")
+# rep_identifier :string(255)
+# project_category_id :integer
+# project_language_id :integer
+# license_id :integer
+# ignore_id :integer
+# praises_count :integer default("0")
+# watchers_count :integer default("0")
+# issues_count :integer default("0")
+# pull_requests_count :integer default("0")
+# language :string(255)
+# versions_count :integer default("0")
+# issue_tags_count :integer default("0")
+# closed_issues_count :integer default("0")
+# open_devops :boolean default("0")
+# gitea_webhook_id :integer
+# open_devops_count :integer default("0")
+# recommend :boolean default("0")
+# platform :integer default("0")
+# default_branch :string(255) default("master")
+# website :string(255)
+# lesson_url :string(255)
+# is_pinned :boolean default("0")
+# recommend_index :integer default("0")
+#
+# Indexes
+#
+# index_projects_on_forked_from_project_id (forked_from_project_id)
+# index_projects_on_identifier (identifier)
+# index_projects_on_invite_code (invite_code)
+# index_projects_on_is_public (is_public)
+# index_projects_on_lft (lft)
+# index_projects_on_license_id (license_id)
+# index_projects_on_name (name)
+# index_projects_on_platform (platform)
+# index_projects_on_project_category_id (project_category_id)
+# index_projects_on_project_language_id (project_language_id)
+# index_projects_on_project_type (project_type)
+# index_projects_on_recommend (recommend)
+# index_projects_on_rgt (rgt)
+# index_projects_on_status (status)
+# index_projects_on_updated_on (updated_on)
+#
+
@@ -98,10 +103,12 @@ class Project < ApplicationRecord
belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects
belongs_to :project_category, optional: true , :counter_cache => true
belongs_to :project_language, optional: true , :counter_cache => true
+ belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id
has_many :project_trends, dependent: :destroy
has_many :watchers, as: :watchable, dependent: :destroy
has_many :fork_users, dependent: :destroy
has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy
+ has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id
has_one :project_educoder, dependent: :destroy
has_one :project_score, dependent: :destroy
@@ -120,24 +127,81 @@ class Project < ApplicationRecord
has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy
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
+ after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members, :reset_cache_data
- before_save :set_invite_code
- after_destroy :reset_cache_data
- scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
+ before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned
+ before_destroy :decre_project_common
+ 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)}
scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)}
scope :recommend, -> { visible.project_statics_select.where(recommend: true) }
+ scope :pinned, -> {where(is_pinned: true)}
delegate :content, to: :project_detail, allow_nil: true
delegate :name, to: :license, prefix: true, allow_nil: true
- def reset_cache_data
- if changes[:user_id].present?
- first_owner = Owner.find_by_id(changes[:user_id].first)
- self.reset_user_cache_async_job(first_owner)
+ def self.all_visible(user_id=nil)
+ user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql
+ org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql
+ if user_id.present?
+ org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql
+ org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql
+ return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible
+ else
+ return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible
+ end
+ end
+
+ def reset_cache_data
+ CacheAsyncResetJob.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)
+ end
+ if changes[:project_language_id].present?
+ first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first)
+ last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last)
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id)
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id)
+ 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
+ end
+
+ def decre_project_common
+ CacheAsyncClearJob.perform_later('project_common_service', self.id)
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id)
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id)
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1})
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1})
+ end
+
+ def is_full_public
+ owner = self.owner
+ if owner.is_a?(Organization)
+ return self.is_public && owner&.visibility == "common"
+ else
+ return self.is_public
+ end
+ end
+
+ def reset_unmember_followed
+ if changes[:is_public].present? && changes[:is_public] == [true, false]
+ self.watchers.where.not(user_id: self.all_collaborators).destroy_all
end
- self.reset_platform_cache_async_job
- self.reset_user_cache_async_job(self.owner)
end
def set_invite_code
@@ -146,6 +210,16 @@ class Project < ApplicationRecord
end
end
+ def set_recommend_and_is_pinned
+ self.recommend = self.recommend_index.zero? ? false : true
+ # 私有项目不允许设置精选和推荐
+ unless self.is_public
+ self.recommend = false
+ self.recommend_index = 0
+ self.is_pinned = false
+ end
+ end
+
def self.search_project(search)
ransack(name_or_identifier_cont: search)
end
diff --git a/app/models/project_category.rb b/app/models/project_category.rb
index 3a9819816..4bba5423e 100644
--- a/app/models/project_category.rb
+++ b/app/models/project_category.rb
@@ -9,6 +9,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
+# pinned_index :integer default("0")
#
# Indexes
#
@@ -19,4 +20,15 @@ class ProjectCategory < ApplicationRecord
include Projectable
has_ancestry
+ def logo_url
+ image_url('logo')
+ end
+
+ private
+
+ def image_url(type)
+ return nil unless Util::FileManage.exists?(self, type)
+ Util::FileManage.source_disk_file_url(self, type)
+ end
+
end
diff --git a/app/models/project_trend.rb b/app/models/project_trend.rb
index 8c55c4f94..7642e1dfb 100644
--- a/app/models/project_trend.rb
+++ b/app/models/project_trend.rb
@@ -20,7 +20,8 @@
class ProjectTrend < ApplicationRecord
CLOSE = 'close'
CREATE = 'create'
-
+ MERGE = 'merge'
+
belongs_to :project
belongs_to :trend, polymorphic: true, optional: true
belongs_to :user
diff --git a/app/models/project_unit.rb b/app/models/project_unit.rb
index a07f62b4e..cc35a6b28 100644
--- a/app/models/project_unit.rb
+++ b/app/models/project_unit.rb
@@ -16,7 +16,7 @@
class ProjectUnit < ApplicationRecord
belongs_to :project
- enum unit_type: {code: 1, issues: 2, pulls: 3, devops: 4, versions: 5, resources: 6}
+ enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7}
validates :unit_type, uniqueness: { scope: :project_id}
@@ -32,9 +32,13 @@ class ProjectUnit < ApplicationRecord
types.delete("pulls") if project.sync_mirror?
# 默认code类型自动创建
types << "code"
+ before_units = project.project_units.pluck(:unit_type).sort
project.project_units.where.not(unit_type: types).each(&:destroy!)
types.each do |type|
project.project_units.find_or_create_by!(unit_type: type)
end
+ after_units = project.project_units.pluck(:unit_type).sort
+ return before_units, after_units
end
+
end
diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb
index 4226d561b..7338a1d72 100644
--- a/app/models/pull_request.rb
+++ b/app/models/pull_request.rb
@@ -37,24 +37,46 @@ class PullRequest < ApplicationRecord
has_many :pull_request_tags, foreign_key: :pull_request_id
has_many :project_trends, as: :trend, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy
+ has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_number, class_name: 'Gitea::Pull'
scope :merged_and_closed, ->{where.not(status: 0)}
scope :opening, -> {where(status: 0)}
- after_save :reset_cache_data
- after_destroy :reset_cache_data
+ after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
+ after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
- def reset_cache_data
- self.reset_platform_cache_async_job
- self.reset_user_cache_async_job(self.user)
+ def incre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {pullrequests: 1}, self.project_id)
+ end
+
+ def decre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {pullrequests: -1}, self.project_id)
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {pullrequest_count: 1}, self.user_id)
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {pullrequest_count: -1}, self.user_id)
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {pullrequest_count: 1})
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {pullrequest_count: -1})
end
def fork_project
Project.find_by(id: self.fork_project_id)
end
- def bind_gitea_pull_request!(gitea_pull_number)
- update_column(:gpid, gitea_pull_number)
+ def bind_gitea_pull_request!(gitea_pull_number, gitea_pull_id)
+ update_columns(
+ gitea_number: gitea_pull_number,
+ gitea_id: gitea_pull_id)
end
def merge!
@@ -67,19 +89,26 @@ class PullRequest < ApplicationRecord
# TODO: sync educoder platform repo's for update some statistics count
def self.update_some_count
- PullRequest.includes(:user, :project).select(:id, :user_id, :gpid, :project_id, :fork_project_id).each do |pr|
+ PullRequest.includes(:user, :project).select(:id, :user_id, :gitea_number, :project_id, :fork_project_id).each do |pr|
puts pr.id
- next if pr.gpid.blank?
+ next if pr.gitea_number.blank?
project = pr.project
next if project.blank?
user = project.owner
- next if pr.gpid === 6 || pr.gpid === 7
- files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gpid)
+ next if pr.gitea_number === 6 || pr.gitea_number === 7
+ files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gitea_number)
pr.update_column(:files_count, files_result['NumFiles']) unless files_result.blank?
- commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gpid)
+ commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gitea_number)
pr.update_column(:commits_count, commits_result.size) unless commits_result.blank?
end
end
+
+ def conflict_files
+ file_names = self&.gitea_pull&.conflicted_files
+ return [] if file_names.blank?
+
+ JSON.parse file_names
+ end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index cefdf6ea4..a012b449a 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -27,7 +27,6 @@
#
# Indexes
#
-# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id)
#
diff --git a/app/models/reversed_keyword.rb b/app/models/reversed_keyword.rb
new file mode 100644
index 000000000..10ad62fa0
--- /dev/null
+++ b/app/models/reversed_keyword.rb
@@ -0,0 +1,30 @@
+# == Schema Information
+#
+# Table name: reversed_keywords
+#
+# id :integer not null, primary key
+# identifier :string(255)
+# description :text(65535)
+# closed :boolean default("0")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+class ReversedKeyword < ApplicationRecord
+
+ scope :is_reversed, -> (identifier){where(identifier: identifier.downcase, closed: false) if identifier.present?}
+
+ validates :identifier, presence: true, uniqueness: true
+
+ before_validation :set_identifier
+
+ def self.check_exists?(identifier)
+ self.is_reversed(identifier).exists?
+ end
+
+ private
+
+ def set_identifier
+ self.identifier = self.identifier.downcase
+ end
+end
diff --git a/app/models/site.rb b/app/models/site.rb
index 58daddf14..af5e78169 100644
--- a/app/models/site.rb
+++ b/app/models/site.rb
@@ -17,17 +17,24 @@ class Site < ApplicationRecord
# common: 普通链接
enum site_type: { add: 0, personal: 1, common: 2 }
+ 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? }
+
def self.set_default_menu
set_add_menu!
set_personal_menu!
set_common_menu!
end
+ def self.has_notice_menu?
+ self.common.where(key: 'notice').present?
+ end
+
private
def self.set_add_menu!
adds= [
- {name: '新建镜像项目', key: 'add_mirror_project', url: '/projects/mirror/new'},
- {name: '新建托管项目', key: 'add_common', url: '/projects/deposit/new'},
+ {name: '新建项目', key: 'add_mirror_project', url: '/projects/mirror/new'},
+ {name: '导入项目', key: 'add_common', url: '/projects/deposit/new'},
{name: '新建组织', key: 'add_r', url: '/organize/new'}]
adds.each { |ele|
diff --git a/app/models/system_notification.rb b/app/models/system_notification.rb
new file mode 100644
index 000000000..d2b99ecf3
--- /dev/null
+++ b/app/models/system_notification.rb
@@ -0,0 +1,27 @@
+# == Schema Information
+#
+# Table name: system_notifications
+#
+# id :integer not null, primary key
+# subject :string(255)
+# sub_subject :string(255)
+# content :text(65535)
+# is_top :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+class SystemNotification < ApplicationRecord
+
+ default_scope { order(created_at: :desc)}
+
+ has_many :system_notification_histories
+ has_many :users, through: :system_notification_histories
+
+ scope :is_top, lambda { where(is_top: true) }
+
+ def read_member?(user_id)
+ self.system_notification_histories.where(user_id: user_id).present? ? true : false
+ end
+
+end
diff --git a/app/models/system_notification_history.rb b/app/models/system_notification_history.rb
new file mode 100644
index 000000000..b629babdf
--- /dev/null
+++ b/app/models/system_notification_history.rb
@@ -0,0 +1,23 @@
+# == Schema Information
+#
+# Table name: system_notification_histories
+#
+# id :integer not null, primary key
+# system_message_id :integer
+# user_id :integer
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_system_notification_histories_on_system_message_id (system_message_id)
+# index_system_notification_histories_on_user_id (user_id)
+#
+
+class SystemNotificationHistory < ApplicationRecord
+
+ belongs_to :system_notification
+ belongs_to :user
+
+ validates :system_notification_id, uniqueness: { scope: :user_id, message: '只能阅读一次'}
+end
diff --git a/app/models/team.rb b/app/models/team.rb
index c25963905..19d05c77a 100644
--- a/app/models/team.rb
+++ b/app/models/team.rb
@@ -31,7 +31,7 @@ class Team < ApplicationRecord
validates :name, uniqueness: {scope: :organization_id}
- enum authorize: {common: 0, read: 1, write: 2, admin: 3, owner: 4}
+ enum authorize: {read: 1, write: 2, admin: 3, owner: 4}
def self.build(organization_id, name, nickname, description, authorize, includes_all_project, can_create_org_project)
self.create!(organization_id: organization_id,
@@ -54,4 +54,15 @@ class Team < ApplicationRecord
team_users.where(user_id: user_id).present?
end
+ def authorize_name
+ case self.authorize
+ when 'read' then '报告者'
+ when 'write' then '开发者'
+ when 'admin' then '管理员'
+ when 'owner' then '拥有者'
+ else
+ ''
+ end
+ end
+
end
diff --git a/app/models/team_unit.rb b/app/models/team_unit.rb
index c757cc684..fdd1b975b 100644
--- a/app/models/team_unit.rb
+++ b/app/models/team_unit.rb
@@ -20,7 +20,7 @@ class TeamUnit < ApplicationRecord
belongs_to :organization
belongs_to :team
- enum unit_type: {code: 1, issues: 2, pulls: 3, releases: 4}
+ enum unit_type: {code: 1, issues: 2, pulls: 3, wiki: 4, releases: 5}
validates :unit_type, uniqueness: { scope: [:organization_id, :team_id]}
diff --git a/app/models/template_message_setting.rb b/app/models/template_message_setting.rb
new file mode 100644
index 000000000..a9c81500b
--- /dev/null
+++ b/app/models/template_message_setting.rb
@@ -0,0 +1,30 @@
+# == Schema Information
+#
+# Table name: template_message_settings
+#
+# id :integer not null, primary key
+# type :string(255)
+# name :string(255)
+# key :string(255)
+# openning :boolean
+# notification_disabled :boolean
+# email_disabled :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+class TemplateMessageSetting < ApplicationRecord
+
+ scope :openning, ->() {where(openning: true)}
+
+ def self.type_name
+ ""
+ end
+
+ def self.build_init_data
+ TemplateMessageSetting::CreateOrAssign.build_init_data
+ TemplateMessageSetting::ManageProject.build_init_data
+ TemplateMessageSetting::Normal.build_init_data
+ TemplateMessageSetting::WatchProject.build_init_data
+ end
+end
diff --git a/app/models/template_message_setting/create_or_assign.rb b/app/models/template_message_setting/create_or_assign.rb
new file mode 100644
index 000000000..2c9fa2076
--- /dev/null
+++ b/app/models/template_message_setting/create_or_assign.rb
@@ -0,0 +1,31 @@
+# == Schema Information
+#
+# Table name: template_message_settings
+#
+# id :integer not null, primary key
+# type :string(255)
+# name :string(255)
+# key :string(255)
+# openning :boolean
+# notification_disabled :boolean
+# email_disabled :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+#我创建的或负责的
+class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting
+
+ def self.type_name
+ "我创建的或负责的"
+ end
+
+ def self.order_index
+ 20
+ end
+
+ def self.build_init_data
+ self.find_or_create_by(name: "易修状态变更", key: "IssueChanged")
+ self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged")
+ end
+end
diff --git a/app/models/template_message_setting/manage_project.rb b/app/models/template_message_setting/manage_project.rb
new file mode 100644
index 000000000..2aa9e4883
--- /dev/null
+++ b/app/models/template_message_setting/manage_project.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: template_message_settings
+#
+# id :integer not null, primary key
+# type :string(255)
+# name :string(255)
+# key :string(255)
+# openning :boolean
+# notification_disabled :boolean
+# email_disabled :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+#我管理的
+class TemplateMessageSetting::ManageProject < TemplateMessageSetting
+
+ def self.type_name
+ "我管理的仓库"
+ end
+
+ def self.order_index
+ 30
+ end
+
+ def self.build_init_data
+ self.find_or_create_by(name: "有新的易修", key: "Issue")
+ self.find_or_create_by(name: "有新的合并请求", key: "PullRequest")
+ self.find_or_create_by(name: "有成员变动", key: "Member")
+ self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged")
+ end
+end
diff --git a/app/models/template_message_setting/normal.rb b/app/models/template_message_setting/normal.rb
new file mode 100644
index 000000000..9090196d5
--- /dev/null
+++ b/app/models/template_message_setting/normal.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: template_message_settings
+#
+# id :integer not null, primary key
+# type :string(255)
+# name :string(255)
+# key :string(255)
+# openning :boolean
+# notification_disabled :boolean
+# email_disabled :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+class TemplateMessageSetting::Normal < TemplateMessageSetting
+
+ def self.type_name
+ "我的状态"
+ end
+
+ def self.order_index
+ 10
+ end
+
+ def self.build_init_data
+ self.find_or_create_by(name: "账号有权限变更", key: "Permission")
+ self.find_or_create_by(name: "被拉入或移出组织", key: "Organization")
+ self.find_or_create_by(name: "被拉入或移出项目", key: "Project")
+ self.find_or_create_by(name: "有新的易修指派给我", key: "IssueAssigned")
+ self.find_or_create_by(name: "有新的合并请求指派给我", key: "PullRequestAssigned")
+ end
+end
diff --git a/app/models/template_message_setting/watch_project.rb b/app/models/template_message_setting/watch_project.rb
new file mode 100644
index 000000000..35dfef6db
--- /dev/null
+++ b/app/models/template_message_setting/watch_project.rb
@@ -0,0 +1,29 @@
+# == Schema Information
+#
+# Table name: template_message_settings
+#
+# id :integer not null, primary key
+# type :string(255)
+# name :string(255)
+# key :string(255)
+# openning :boolean
+# notification_disabled :boolean
+# email_disabled :boolean
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+#我关注的
+class TemplateMessageSetting::WatchProject < TemplateMessageSetting
+
+ def self.type_name
+ "我关注的仓库"
+ end
+
+ def self.order_index
+ 40
+ end
+
+ def self.build_init_data
+ end
+end
diff --git a/app/models/token.rb b/app/models/token.rb
index c71a860af..d1158c7e7 100644
--- a/app/models/token.rb
+++ b/app/models/token.rb
@@ -1,19 +1,19 @@
-# == Schema Information
-#
-# Table name: tokens
-#
-# id :integer not null, primary key
-# user_id :integer default("0"), not null
-# action :string(30) default(""), not null
-# value :string(40) default(""), not null
-# created_on :datetime not null
-#
-# Indexes
-#
-# index_tokens_on_user_id (user_id)
-# tokens_value (value) UNIQUE
-#
-
+# == Schema Information
+#
+# Table name: tokens
+#
+# id :integer not null, primary key
+# user_id :integer default("0"), not null
+# action :string(30) default(""), not null
+# value :string(40) default(""), not null
+# created_on :datetime not null
+#
+# Indexes
+#
+# index_tokens_on_user_id (user_id)
+# tokens_value (value) UNIQUE
+#
+
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -105,7 +105,7 @@ class Token < ActiveRecord::Base
end
def self.generate_token_value
- Educoder::Utils.random_hex(20)
+ Gitlink::Utils.random_hex(20)
end
def self.delete_user_all_tokens(user)
diff --git a/app/models/user.rb b/app/models/user.rb
index c943e5efa..3f37ab1ea 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
-# platform :string(255) default("0")
-# gitea_token :string(255)
-# gitea_uid :integer
# is_shixun_marker :boolean default("0")
+# admin_visitable :boolean default("0")
+# collaborator :boolean default("0")
+# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
-# sponsor_certification :integer default("0")
-# sponsor_num :integer default("0")
-# sponsored_num :integer default("0")
-# award_time :datetime
+# gitea_token :string(255)
+# platform :string(255)
#
# Indexes
#
@@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
-# index_users_on_login (login)
-# index_users_on_mail (mail)
+# index_users_on_login (login) UNIQUE
+# index_users_on_mail (mail) UNIQUE
+# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#
@@ -117,8 +116,6 @@ class User < Owner
enumerize :platform, in: [:forge, :educoder, :trustie, :military], default: :forge, scope: :shallow
belongs_to :laboratory, optional: true
- has_many :composes, dependent: :destroy
- has_many :compose_users, dependent: :destroy
has_one :user_extension, dependent: :destroy
has_many :open_users, dependent: :destroy
has_one :wechat_open_user, class_name: 'OpenUsers::Wechat'
@@ -170,7 +167,13 @@ class User < Owner
accepts_nested_attributes_for :is_pinned_projects
has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :pull_requests, dependent: :destroy
+ has_many :public_keys, class_name: "Gitea::PublicKey",primary_key: :gitea_uid, foreign_key: :owner_id, dependent: :destroy
+ has_one :user_template_message_setting, dependent: :destroy
+
+ has_many :system_notification_histories
+ has_many :system_notifications, through: :system_notification_histories
+
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
scope :like, lambda { |keywords|
@@ -186,7 +189,8 @@ class User < Owner
:show_email, :show_location, :show_department,
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
- before_save :update_hashed_password
+ before_save :update_hashed_password, :set_lastname
+ after_save :reset_cache_data
after_create do
SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie?
end
@@ -203,6 +207,10 @@ class User < Owner
validate :validate_sensitive_string
validate :validate_password_length
+ def reset_cache_data
+ Cache::V2::OwnerCommonService.new(self.id).reset
+ end
+
# 用户参与的所有项目
def full_member_projects
normal_projects = Project.members_projects(self.id).to_sql
@@ -424,6 +432,7 @@ class User < Owner
def activate!
update_attribute(:status, STATUS_ACTIVE)
+ prohibit_gitea_user_login!(false)
end
def register!
@@ -432,6 +441,12 @@ class User < Owner
def lock!
update_attribute(:status, STATUS_LOCKED)
+ prohibit_gitea_user_login!
+ end
+
+ def prohibit_gitea_user_login!(prohibit_login = true)
+ Gitea::User::UpdateInteractor.call(self.login,
+ {email: self.mail, prohibit_login: prohibit_login})
end
# 课程用户身份
@@ -675,7 +690,7 @@ class User < Owner
end
def self.generate_salt
- Educoder::Utils.random_hex(16)
+ Gitlink::Utils.random_hex(16)
end
# 全部已认证
@@ -757,6 +772,10 @@ class User < Owner
laboratory_id.present? && laboratory_id != 1
end
+ def profile_is_completed?
+ self.nickname.present? && self.gender.present? && self.mail.present? && self.custom_department.present?
+ end
+
protected
def validate_password_length
# 管理员的初始密码是5位
@@ -779,6 +798,10 @@ class User < Owner
self.laboratory = Laboratory.current if laboratory_id.blank?
end
+
+ def set_lastname
+ self.lastname = self.nickname if changes[:nickname].present?
+ end
end
diff --git a/app/models/user_action.rb b/app/models/user_action.rb
index 3ad8010ea..179359695 100644
--- a/app/models/user_action.rb
+++ b/app/models/user_action.rb
@@ -12,7 +12,9 @@
#
# Indexes
#
-# index_user_actions_on_ip (ip)
+# index_user_actions_on_ip (ip)
+# index_user_actions_on_user_id (user_id)
+# index_user_actions_on_user_id_and_action_type (user_id,action_type)
#
class UserAction < ApplicationRecord
diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb
index 49d7b35a1..ba519d6fb 100644
--- a/app/models/user_agent.rb
+++ b/app/models/user_agent.rb
@@ -10,10 +10,13 @@
# updated_at :datetime not null
# register_status :integer default("0")
# action_status :integer default("0")
+# is_delete :boolean default("0")
+# user_id :integer
#
# Indexes
#
-# index_user_agents_on_ip (ip) UNIQUE
+# index_user_agents_on_ip (ip)
+# index_user_agents_on_user_id (user_id)
#
class UserAgent < ApplicationRecord
diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb
index 0749d1f79..ee208af7e 100644
--- a/app/models/user_extension.rb
+++ b/app/models/user_extension.rb
@@ -22,6 +22,9 @@
# school_id :integer
# description :string(255) default("")
# department_id :integer
+# honor :text(65535)
+# edu_background :integer
+# edu_entry_year :integer
# province :string(255)
# city :string(255)
# custom_department :string(255)
diff --git a/app/models/user_template_message_setting.rb b/app/models/user_template_message_setting.rb
new file mode 100644
index 000000000..c581e626e
--- /dev/null
+++ b/app/models/user_template_message_setting.rb
@@ -0,0 +1,72 @@
+# == Schema Information
+#
+# Table name: user_template_message_settings
+#
+# id :integer not null, primary key
+# user_id :integer
+# notification_body :text(65535)
+# email_body :text(65535)
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_user_template_message_settings_on_user_id (user_id)
+#
+
+class UserTemplateMessageSetting < ApplicationRecord
+ serialize :notification_body, Hash
+ serialize :email_body, Hash
+
+ belongs_to :user
+
+ before_update :set_body_value
+
+ def self.build(user_id)
+ self.create!(user_id: user_id, notification_body: init_notification_body, email_body: init_email_body)
+ end
+
+ def self.init_notification_body
+ {
+ "Normal::Permission": true,
+ "Normal::Project": true,
+ "Normal::Organization": true,
+ "Normal::IssueAssigned": true,
+ "Normal::PullRequestAssigned": true,
+ "CreateOrAssign::IssueChanged": true,
+ "CreateOrAssign::PullRequestChanged": true,
+ "ManageProject::Issue": true,
+ "ManageProject::PullRequest": true,
+ "ManageProject::Member": true,
+ "ManageProject::SettingChanged": true,
+ }.stringify_keys!
+ end
+
+ def self.init_email_body
+ {
+ "Normal::Permission": true,
+ "Normal::Project": true,
+ "Normal::Organization": true,
+ "Normal::IssueAssigned": true,
+ "Normal::PullRequestAssigned": true,
+ "CreateOrAssign::IssueChanged": true,
+ "CreateOrAssign::PullRequestChanged": true,
+ "ManageProject::Issue": true,
+ "ManageProject::PullRequest": true,
+ "ManageProject::Member": true,
+ "ManageProject::SettingChanged": true,
+ }.stringify_keys!
+ end
+
+ private
+
+ def set_body_value
+ self.notification_body.each do |k, v|
+ self.notification_body[k] = ActiveModel::Type::Boolean.new.cast(v).nil? ? false : ActiveModel::Type::Boolean.new.cast(v)
+ end
+
+ self.email_body.each do |k, v|
+ self.email_body[k] = ActiveModel::Type::Boolean.new.cast(v).nil? ? false : ActiveModel::Type::Boolean.new.cast(v)
+ end
+ end
+end
diff --git a/app/models/version_release.rb b/app/models/version_release.rb
index 16b823a78..3c97420ea 100644
--- a/app/models/version_release.rb
+++ b/app/models/version_release.rb
@@ -17,6 +17,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# repository_id :integer
+# sha :string(255)
#
# Indexes
#
@@ -29,4 +30,9 @@ class VersionRelease < ApplicationRecord
has_many :project_trends, as: :trend, dependent: :destroy
scope :releases_size, ->{where(draft: false, prerelease: false).size}
has_many :attachments, as: :container, dependent: :destroy
+
+ def update_sha
+ git_release = Gitea::Versions::GetService.call(user.gitea_token, repository&.owner&.login, repository&.identifier, version_gid)
+ self.update(sha: git_release["sha"])
+ end
end
diff --git a/app/models/watcher.rb b/app/models/watcher.rb
index ccc8eefaa..5a2cd96fb 100644
--- a/app/models/watcher.rb
+++ b/app/models/watcher.rb
@@ -22,17 +22,40 @@ class Watcher < ApplicationRecord
scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)}
- after_save :reset_cache_data
- after_destroy :reset_cache_data
+ after_create :send_create_message_to_notice_system, :incre_project_common, :incre_user_statistic, :incre_platform_statistic
+ after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
- def reset_cache_data
- if self.watchable.is_a?(User)
- self.reset_user_cache_async_job(self.watchable)
- end
- if self.watchable.is_a?(Project)
- self.reset_user_cache_async_job(self.watchable&.owner)
- end
- self.reset_platform_cache_async_job
+
+ def incre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {watchers: 1}, self.watchable_id) if self.watchable_type == "Project"
+ end
+
+ def decre_project_common
+ CacheAsyncSetJob.perform_later("project_common_service", {watchers: -1}, self.watchable_id) if self.watchable_type == "Project"
+ end
+
+ def incre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {follow_count: 1}, self.watchable_id) if self.watchable_type == "User"
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_watcher_count: 1}, self.watchable&.user_id) if self.watchable_type == "Project"
+ end
+
+ def decre_user_statistic
+ CacheAsyncSetJob.perform_later("user_statistic_service", {follow_count: -1}, self.watchable_id) if self.watchable_type == "User"
+ CacheAsyncSetJob.perform_later("user_statistic_service", {project_watcher_count: -1}, self.watchable&.user_id) if self.watchable_type == "Project"
+ end
+
+ def incre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {follow_count: 1}) if self.watchable_type == "User"
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_watcher_count: 1}) if self.watchable_type == "Project"
+ end
+
+ def decre_platform_statistic
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {follow_count: -1}) if self.watchable_type == "User"
+ CacheAsyncSetJob.perform_later("platform_statistic_service", {project_watcher_count: -1}) if self.watchable_type == "Project"
+ end
+
+ def send_create_message_to_notice_system
+ SendTemplateMessageJob.perform_later('FollowTip', self.id) if self.watchable.is_a?(User) if Site.has_notice_menu?
end
end
diff --git a/app/queries/admins/course_list_query.rb b/app/queries/admins/course_list_query.rb
deleted file mode 100644
index 84868b7d0..000000000
--- a/app/queries/admins/course_list_query.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class Admins::CourseListQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :created_at, default_by: :created_at, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- course_lists = CourseList.all
-
- # 关键字模糊查询
- keyword = params[:keyword].to_s.strip
- if keyword.present?
- search_type = params[:search_type] || "0"
- case search_type
- when "0"
- course_lists = course_lists.joins(:user)
- .where('CONCAT(lastname, firstname) like :keyword OR users.nickname like :keyword', keyword: "%#{keyword}%")
- when "1"
- course_lists = course_lists.where('name like :keyword', keyword: "%#{keyword}%")
- end
- end
-
- custom_sort(course_lists, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/course_query.rb b/app/queries/admins/course_query.rb
deleted file mode 100644
index 6fbbc002e..000000000
--- a/app/queries/admins/course_query.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class Admins::CourseQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :created_at, default_by: :created_at, default_direction: :desc, default_table: 'courses'
-
- def initialize(params)
- @params = params
- end
-
- def call
- courses = Course.all
-
- courses = courses.where(id: params[:id]) if params[:id].present?
-
- # 状态过滤
- status =
- case params[:status].to_s.strip
- when 'processing' then 0
- when 'ended' then 1
- end
- courses = courses.where(is_end: status) if status
-
- # 单位
- if params[:school_id].present?
- courses = courses.where(school_id: params[:school_id])
- end
-
- # 首页展示
- if params[:homepage_show].present? && params[:homepage_show].to_s == 'true'
- courses = courses.where(homepage_show: true)
- end
-
- # 关键字
- keyword = params[:keyword].to_s.strip
- if keyword
- sql = 'CONCAT(lastname, firstname) LIKE :keyword OR users.nickname LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword'
- courses = courses.joins(:teacher, :course_list).where(sql, keyword: "%#{keyword}%")
- end
-
- custom_sort(courses, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/department_apply_query.rb b/app/queries/admins/department_apply_query.rb
deleted file mode 100644
index 500536ddb..000000000
--- a/app/queries/admins/department_apply_query.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class Admins::DepartmentApplyQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :created_at, default_by: :created_at, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- status = params[:status]
-
- applies = ApplyAddDepartment.where(status: status) if status.present?
-
- # 关键字模糊查询
- keyword = params[:keyword].to_s.strip
- if keyword.present?
- applies = applies.where('name LIKE :keyword', keyword: "%#{keyword}%")
- end
-
- custom_sort(applies, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/department_query.rb b/app/queries/admins/department_query.rb
deleted file mode 100644
index f0b8c5d24..000000000
--- a/app/queries/admins/department_query.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class Admins::DepartmentQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :created_at, default_by: :created_at, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- departments = Department.where(is_auth: true).without_deleted
-
- keyword = params[:keyword].to_s.strip
- if keyword.present?
- departments = departments.joins(:school)
- .where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: "%#{keyword}%")
- end
-
- if params[:with_member].to_s == 'true'
- subquery = DepartmentMember.where('department_id = departments.id').select('1 AS one').to_sql
- departments = departments.where("EXISTS(#{subquery})")
- end
-
- if params[:with_identifier].to_s == 'true'
- departments = departments.where.not(identifier: nil).where.not(identifier: '')
- end
-
- custom_sort(departments, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/edu_setting_query.rb b/app/queries/admins/edu_setting_query.rb
new file mode 100644
index 000000000..3e61ffd33
--- /dev/null
+++ b/app/queries/admins/edu_setting_query.rb
@@ -0,0 +1,28 @@
+class Admins::EduSettingQuery < ApplicationQuery
+ include CustomSortable
+
+ attr_reader :params
+
+ sort_columns :id, default_by: :id, default_direction: :desc
+
+ def initialize(params)
+ @params = params
+ end
+
+ def call
+ collection = EduSetting.all
+ collection = filter_settings(collection)
+
+ custom_sort collection, params[:sort_by], params[:sort_direction]
+ end
+
+ def filter_settings(collection)
+ by_search(collection)
+ end
+
+ def by_search(collection)
+ keyword = strip_param(:search)
+ collection.by_search(keyword)
+ end
+
+end
\ No newline at end of file
diff --git a/app/queries/admins/laboratory_shixun_query.rb b/app/queries/admins/laboratory_shixun_query.rb
deleted file mode 100644
index da7867194..000000000
--- a/app/queries/admins/laboratory_shixun_query.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-class Admins::LaboratoryShixunQuery < ApplicationQuery
- attr_reader :laboratory, :params
-
- def initialize(laboratory, params)
- @laboratory = laboratory
- @params = params
- end
-
- def call
- laboratory_shixuns = laboratory.laboratory_shixuns.joins(:shixun)
-
- keyword = params[:keyword].to_s.strip
- if keyword.present?
- like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword'
- laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%")
- end
-
- # 实训状态
- laboratory_shixuns = laboratory_shixuns.where(shixuns: { status: params[:status] }) if params[:status].present?
-
- # 技术平台
- if params[:tag_id].present?
- laboratory_shixuns = laboratory_shixuns.joins(shixun: :shixun_mirror_repositories)
- .where(shixun_mirror_repositories: { mirror_repository_id: params[:tag_id] })
- end
-
- # 首页展示、单位自建
- %i[homepage ownership].each do |column|
- if params[column].present? && params[column].to_s == 'true'
- laboratory_shixuns = laboratory_shixuns.where(column => true)
- end
- end
-
- laboratory_shixuns
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/school_query.rb b/app/queries/admins/school_query.rb
deleted file mode 100644
index 3206f0858..000000000
--- a/app/queries/admins/school_query.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class Admins::SchoolQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :users_count, :created_at, default_by: :created_at, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- schools = School.all
-
- keyword = strip_param(:keyword)
- Rails.logger.info("###########{keyword}")
- if keyword
- schools = schools.where('schools.name LIKE ?', "%#{keyword}%")
- end
- schools = schools.left_joins(:user_extensions).select('schools.*, IFNULL(count(user_extensions.user_id),0) users_count').group('schools.id')
- custom_sort schools, params[:sort_by], params[:sort_direction]
- end
-end
\ No newline at end of file
diff --git a/app/queries/admins/site_query.rb b/app/queries/admins/site_query.rb
new file mode 100644
index 000000000..1d15f0312
--- /dev/null
+++ b/app/queries/admins/site_query.rb
@@ -0,0 +1,35 @@
+class Admins::SiteQuery < ApplicationQuery
+ include CustomSortable
+
+ attr_reader :params
+
+ sort_columns :id, default_by: :id, default_direction: :desc
+
+ def initialize(params)
+ @params = params
+ end
+
+ def call
+ collection = Site.all
+ collection = filter_sites(collection)
+
+ custom_sort collection, params[:sort_by], params[:sort_direction]
+ end
+
+ def filter_sites(collection)
+ collection = by_search(collection)
+ collection = by_stie_type(collection)
+ collection
+ end
+
+ def by_search(collection)
+ keyword = strip_param(:search)
+ collection.by_search(keyword)
+ end
+
+ def by_stie_type(collection)
+ site_type = strip_param(:site_type)
+ collection.by_site_type(site_type)
+ end
+
+end
\ No newline at end of file
diff --git a/app/queries/admins/subject_query.rb b/app/queries/admins/subject_query.rb
deleted file mode 100644
index 3596c7715..000000000
--- a/app/queries/admins/subject_query.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-class Admins::SubjectQuery < ApplicationQuery
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :created_at, default_by: :created_at, default_direction: :desc, default_table: 'subjects'
-
- def initialize(params)
- @params = params
- end
-
- def call
- subjects = Subject.all
-
- subjects = subjects.where(id: params[:id]) if params[:id].present?
-
- # 状态过滤
- status =
- case params[:status].to_s.strip
- when "editing" then {status: 0}
- when "applying" then {status: 2, public: [0, 1]}
- when "pending" then {public: 1}
- when "published" then {public: 2}
- end
-
- subjects = subjects.where(status) if status
-
- # 创建者单位
- if params[:school_id].present?
- subjects = subjects.joins(user: :user_extension).where(user_extensions: { school_id: params[:school_id] })
- end
-
- # 首页展示、金课
- %i[homepage_show excellent].each do |column|
- if params[column].present? && params[column].to_s == 'true'
- subjects = subjects.where(column => true)
- end
- end
-
- # 关键字
- keyword = params[:keyword].to_s.strip
- if keyword
- sql = 'CONCAT(lastname, firstname) LIKE :keyword OR users.nickname LIKE :keyword OR subjects.name LIKE :keyword'
- subjects = subjects.joins(:user).where(sql, keyword: "%#{keyword}%")
- end
-
- custom_sort(subjects, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb
index 04f1d168b..b06791bd3 100644
--- a/app/queries/projects/list_query.rb
+++ b/app/queries/projects/list_query.rb
@@ -1,28 +1,55 @@
class Projects::ListQuery < ApplicationQuery
include CustomSortable
- attr_reader :params
+ attr_reader :params, :current_user_id
sort_columns :updated_on, :created_on, :forked_count, :praises_count, default_by: :updated_on, default_direction: :desc
- def initialize(params)
+ def initialize(params, current_user_id=nil)
@params = params
+ @current_user_id = current_user_id
end
def call
- q = Project.visible.by_name_or_identifier(params[:search])
-
- scope = q
- .with_project_type(params[:project_type])
- .with_project_category(params[:category_id])
- .with_project_language(params[:language_id])
+ collection = Project.all
+ collection = filter_projects(collection)
sort = params[:sort_by] || "updated_on"
sort_direction = params[:sort_direction] || "desc"
- custom_sort(scope, sort, sort_direction)
+ custom_sort(collection, sort, sort_direction)
# scope = scope.reorder("projects.#{sort} #{sort_direction}")
# scope
end
+
+ def filter_projects(collection)
+ collection = by_pinned(collection)
+ collection = by_search(collection)
+ collection = by_project_type(collection)
+ collection = by_project_category(collection)
+ collection = by_project_language(collection)
+ collection
+ end
+
+ def by_search(items)
+ items.visible.by_name_or_identifier(params[:search])
+ end
+
+ def by_project_type(items)
+ items.with_project_type(params[:project_type])
+ end
+
+ def by_project_category(items)
+ items.with_project_category(params[:category_id])
+ end
+
+ def by_project_language(items)
+ items.with_project_language(params[:language_id])
+ end
+
+ def by_pinned(items)
+ (params[:pinned].present? && params[:category_id].present?) ? items.pinned : items
+ end
+
end
diff --git a/app/queries/users/video_query.rb b/app/queries/users/video_query.rb
deleted file mode 100644
index cfaa314cc..000000000
--- a/app/queries/users/video_query.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-class Users::VideoQuery < ApplicationQuery
- include CustomSortable
-
- sort_columns :published_at, :title, default_by: :published_at, default_direction: :desc
-
- attr_reader :user, :params
-
- def initialize(user, params)
- @user = user
- @params = params
- end
-
- def call
- videos = user.videos
-
- videos =
- case params[:status]
- when 'published' then videos.published
- when 'processing' then videos.processing
- else videos.published
- end
-
- keyword = params[:keyword].to_s.strip
- videos = videos.where('title LIKE ?', "%#{keyword}%") if keyword.present?
-
- custom_sort(videos, params[:sort_by], params[:sort_direction])
- end
-end
\ No newline at end of file
diff --git a/app/queries/weapps/search_query.rb b/app/queries/weapps/search_query.rb
deleted file mode 100644
index 665480073..000000000
--- a/app/queries/weapps/search_query.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class Weapps::SearchQuery < ApplicationQuery
- include ElasticsearchAble
-
- attr_reader :params
-
- def initialize(params)
- @params = params
- end
-
- def call
- modal_name.search(keyword, search_options)
- end
-
- private
-
- def search_options
- hash = {
- fields: [:name],
- page: page,
- per_page: per_page
- }
- hash.merge(where: { status: 2 }) if modal_name == Shixun
-
- hash
- end
-
- def modal_name
- @_modal_name ||= begin
- case params[:type].to_s
- when 'subject' then Subject
- when 'shixun' then Shixun
- when 'course' then Course
- else Subject
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/queries/weapps/subject_query.rb b/app/queries/weapps/subject_query.rb
deleted file mode 100644
index 73e70160a..000000000
--- a/app/queries/weapps/subject_query.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class Weapps::SubjectQuery < ApplicationQuery
- include CustomSortable
- attr_reader :params
-
- def initialize(current_laboratory, params)
- @current_laboratory = current_laboratory
- @params = params
- end
-
- def call
- subjects = @current_laboratory.subjects.unhidden.publiced.show_moblied
-
- # 课程体系的过滤
- if params[:sub_discipline_id].present?
- subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {id: params[:sub_discipline_id]})
- elsif params[:discipline_id].present?
- subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {discipline_id: params[:discipline_id]})
- else
- subjects = subjects.joins(:sub_discipline_containers).where(sub_discipline_containers: {container_type: "Subject"})
- end
-
- subjects = subjects.left_joins(:shixuns).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show,
- subjects.shixuns_count, subjects.updated_at, IFNULL(sum(shixuns.myshixuns_count), 0) myshixuns_count')
- .group('subjects.id').order("subjects.homepage_show #{sort_type}, #{order_type} #{sort_type}")
- subjects
- end
-
- private
-
- def order_type
- Subject.column_names.include?(params[:order]) ? params[:order] : 'updated_at'
- end
-
- def sort_type
- %w(desc asc).include?(params[:sort]) ? params[:sort] : "desc"
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/add_department_member_service.rb b/app/services/admins/add_department_member_service.rb
deleted file mode 100644
index f8331cf4a..000000000
--- a/app/services/admins/add_department_member_service.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Admins::AddDepartmentMemberService < ApplicationService
-
- attr_reader :department, :params
-
- def initialize(department, params)
- @department = department
- @params = params
- end
-
- def call
- columns = %i[]
- DepartmentMember.bulk_insert(*columns) do |worker|
- Array.wrap(params[:user_ids]).compact.each do |user_id|
- next if department.department_members.exists?(user_id: user_id)
-
- worker.add(department_id: department.id, user_id: user_id)
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/check_shixun_mirrors_service.rb b/app/services/admins/check_shixun_mirrors_service.rb
deleted file mode 100644
index 4aa0af4cf..000000000
--- a/app/services/admins/check_shixun_mirrors_service.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-class Admins::CheckShixunMirrorsService < ApplicationService
- Error = Class.new(StandardError)
-
- def call
- bridge_images
-
- ActiveRecord::Base.transaction do
- check_sync_mirrors!
-
- check_mirrors!
- end
- end
-
- private
-
- def mirrors
- bridge_images['images']
- end
-
- def sync_mirrors
- bridge_images['imagesNotSync']
- end
-
- def check_mirrors!
- return if mirrors.blank?
- image_names = []
-
- mirrors.each do |data|
- mirror = JSON.parse(data)
-
- name_repository = MirrorRepository.find_by(name: mirror['imageName'])
- id_repository = MirrorRepository.find_by(mirrorID: mirror['imageID'])
-
- image_names << mirror['imageName']
-
- if name_repository.blank? && id_repository.present? # 镜像名称被修改
- id_repository.update_column(:status, 2)
- MirrorOperationRecord.create!(mirror_repository_id: id_repository.id, mirror_id: mirror['imageID'],
- mirror_name: mirror['imageName'], status: 2, user_id: -1)
- elsif name_repository.blank? # 镜像不存在、创建镜像
- new_repository = MirrorRepository.create!(mirrorID: mirror['imageID'], name: mirror['imageName'])
- MirrorOperationRecord.create!(mirror_repository_id: new_repository.id, mirror_id: mirror['imageID'],
- mirror_name: mirror['imageName'], status: 0, user_id: -1)
- elsif name_repository.mirrorID != mirror['imageID'] # 镜像ID被修改
- name_repository.update_column(:status, 2)
- MirrorOperationRecord.create!(mirror_repository_id: name_repository.id, mirror_id: mirror['imageID'],
- mirror_name: mirror['imageName'], status: 1, user_id: -1)
- end
- end
-
- # 判断中间层镜像是否被删除
- MirrorRepository.find_each do |mirror|
- next if mirror&.name.blank? || image_names.index(mirror.name)
-
- mirror.update_column(:status, 4)
- MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: mirror&.mirrorID,
- mirror_name: mirror.name, status: 3, user_id: -1)
- end
- end
-
- def check_sync_mirrors!
- return if sync_mirrors.blank?
-
- sync_mirrors.each do |data|
- mirror = JSON.parse(data)
-
- repository = MirrorRepository.find_by(name: mirror['imageName'])
- next if repository.blank? || repository.status != 1
-
- repository.update_column(:status, 5)
- MirrorOperationRecord.create!(mirror_repository_id: repository.id, mirror_id: mirror['imageID'],
- mirror_name: mirror['imageName'], status: 4, user_id: -1)
- end
- end
-
- def bridge_images
- @_bridge_images ||= begin
- url = "#{EduSetting.get('cloud_bridge')}/bridge/docker/images"
- res = Faraday.get(url)
- res = JSON.parse(res.body)
- raise Error, '拉取镜像信息异常' if res && res['code'] != 0
-
- res
- rescue => e
- Rails.logger.error("get response failed ! #{e.message}")
- raise Error, '实训云平台繁忙(繁忙等级:84)'
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/delete_unit_apply_service.rb b/app/services/admins/delete_unit_apply_service.rb
index a64c8d64d..af2e9668d 100644
--- a/app/services/admins/delete_unit_apply_service.rb
+++ b/app/services/admins/delete_unit_apply_service.rb
@@ -18,7 +18,7 @@ class Admins::DeleteUnitApplyService < ApplicationService
use_extensions = UserExtension&.where(school_id: @unit_apply.school_id)
user_ids = UserExtension&.where(school_id: @unit_apply.school_id)&.pluck(:user_id)
- User.where(id: user_ids).update_all(profile_completed: false)
+ User.where(id: user_ids)
use_extensions.update_all(school_id: nil,department_id: nil)
@unit_apply&.user&.user_extension&.update_attribute("department_id", nil)
diff --git a/app/services/admins/drag_cooperative_service.rb b/app/services/admins/drag_cooperative_service.rb
deleted file mode 100644
index 241b7eb11..000000000
--- a/app/services/admins/drag_cooperative_service.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class Admins::DragCooperativeService < ApplicationService
- Error = Class.new(StandardError)
-
- attr_reader :move, :after
-
- def initialize(move, after)
- @move = move
- @after = after # 移动后下一个位置的元素
- end
-
- def call
- return if move.position + 1 == after&.position # 未移动
- raise Error, '未知错误' if after && move.img_type != after.img_type
-
- coo_imgs = CooImg.where(img_type: move.img_type)
-
- ActiveRecord::Base.transaction do
- if after.blank? # 移动至末尾
- total = coo_imgs.count
-
- coo_imgs.where('position > ?', move.position).update_all('position = position - 1')
- move.update!(position: total)
- return
- end
-
- if move.position > after.position # 前移
- coo_imgs.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
- move.update!(position: after.position)
- else # 后移
- coo_imgs.where('position > ? AND position <= ?', move.position, after.position).update_all('position = position - 1')
- move.update!(position: after.position)
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/drag_portal_image_service.rb b/app/services/admins/drag_portal_image_service.rb
deleted file mode 100644
index 5555c08b2..000000000
--- a/app/services/admins/drag_portal_image_service.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class Admins::DragPortalImageService < ApplicationService
- Error = Class.new(StandardError)
-
- attr_reader :laboratory, :move, :after
-
- def initialize(laboratory, move, after)
- @laboratory = laboratory
- @move = move
- @after = after # 移动后下一个位置的元素
- end
-
- def call
- return if move.position + 1 == after&.position # 未移动
-
- images = laboratory.portal_images
-
- ActiveRecord::Base.transaction do
- if after.blank? || move.id == after.id # 移动至末尾
- total = images.count
-
- images.where('position > ?', move.position).update_all('position = position - 1')
- move.update!(position: total)
- return
- end
-
- if move.position > after.position # 前移
- images.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
- move.update!(position: after.position)
- else # 后移
- images.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
- move.update!(position: after.position - 1)
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/drag_weapp_advert_service.rb b/app/services/admins/drag_weapp_advert_service.rb
deleted file mode 100644
index 8bfb7c317..000000000
--- a/app/services/admins/drag_weapp_advert_service.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class Admins::DragWeappAdvertService < ApplicationService
- attr_reader :move, :after
-
- def initialize(move, after)
- @move = move
- @after = after # 移动后下一个位置的元素
- end
-
- def call
- return if move.position + 1 == after&.position # 未移动
-
- adverts = WeappSettings::Advert.all
-
- ActiveRecord::Base.transaction do
- if after.blank? || move.id == after.id # 移动至末尾
- total = adverts.count
-
- adverts.where('position > ?', move.position).update_all('position = position - 1')
- move.update!(position: total)
- return
- end
-
- if move.position > after.position # 前移
- adverts.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
- move.update!(position: after.position)
- else # 后移
- adverts.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
- move.update!(position: after.position - 1)
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/drag_weapp_carousel_service.rb b/app/services/admins/drag_weapp_carousel_service.rb
deleted file mode 100644
index f0b3832b2..000000000
--- a/app/services/admins/drag_weapp_carousel_service.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class Admins::DragWeappCarouselService < ApplicationService
- attr_reader :move, :after
-
- def initialize(move, after)
- @move = move
- @after = after # 移动后下一个位置的元素
- end
-
- def call
- return if move.position + 1 == after&.position # 未移动
-
- carousels = WeappSettings::Carousel.all
-
- ActiveRecord::Base.transaction do
- if after.blank? || move.id == after.id # 移动至末尾
- total = carousels.count
-
- carousels.where('position > ?', move.position).update_all('position = position - 1')
- move.update!(position: total)
- return
- end
-
- if move.position > after.position # 前移
- carousels.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
- move.update!(position: after.position)
- else # 后移
- carousels.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
- move.update!(position: after.position - 1)
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/import_course_member_service.rb b/app/services/admins/import_course_member_service.rb
deleted file mode 100644
index 3ea559766..000000000
--- a/app/services/admins/import_course_member_service.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-class Admins::ImportCourseMemberService < ApplicationService
- Error = Class.new(StandardError)
-
- attr_reader :file, :result
-
- def initialize(file)
- @file = file
- @result = { success: 0, fail: [] }
- end
-
- def call
- raise Error, '文件不存在' if file.blank?
-
- excel = Admins::ImportCourseMemberExcel.new(file)
- excel.read_each(&method(:create_course_member))
-
- result
- rescue ApplicationImport::Error => ex
- raise Error, ex.message
- end
-
- private
-
- def create_course_member(data)
- raise '课堂角色必须为 2、3、4' unless [2, 3, 4].include?(data.role.to_i)
-
- user = User.joins(:user_extension).where(user_extensions: { student_id: data.student_id, school_id: data.school_id }).first
- raise '该学号的用户不存在' if user.blank?
- course = Course.find_by(id: data.course_id)
- raise '该课堂不存在' if course.blank?
-
- course_group = nil
- if data.course_group_name.present?
- course_group = course.course_groups.find_or_create_by!(name: data.course_group_name)
- end
-
- member = course.course_members.find_by(user_id: user.id, role: data.role.to_i)
- # 如果已是课堂成员且是学生身份and不在指定的分班则移动到该分班
- if member.present? && member.role == 'STUDENT' && course_group && member.course_group_id != course_group&.id.to_i
- member.update!(course_group_id: course_group&.id.to_i)
- elsif member.blank?
- course.course_members.create!(user_id: user.id, role: data.role.to_i, course_group_id: course_group&.id.to_i)
- extra =
- case data.role.to_i
- when 2 then 9
- when 3 then 7
- else 10
- end
-
- Tiding.create!(user_id: user.id, trigger_user_id: course.tea_id, container_id: course.id,
- container_type: 'TeacherJoinCourse', belong_container_id: course.id,
- belong_container_type: 'Course', tiding_type: 'System', extra: extra)
- end
-
- result[:success] += 1
- rescue Exception => ex
- fail_data = data.as_json
- fail_data[:data] = fail_data.values.join(',')
- fail_data[:message] = ex.message
-
- result[:fail] << fail_data
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/import_user_service.rb b/app/services/admins/import_user_service.rb
index 5d4c2e10f..2fac412e1 100644
--- a/app/services/admins/import_user_service.rb
+++ b/app/services/admins/import_user_service.rb
@@ -57,7 +57,7 @@ class Admins::ImportUserService < ApplicationService
password: '12345678',
phone: data.phone,
mail: "#{prefix}#{data.student_id}@qq.com",
- profile_completed: true
+ # profile_completed: true
}
ActiveRecord::Base.transaction do
user = User.create!(attr)
diff --git a/app/services/admins/school_daily_statistic_service.rb b/app/services/admins/school_daily_statistic_service.rb
deleted file mode 100644
index 64bb97864..000000000
--- a/app/services/admins/school_daily_statistic_service.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-class Admins::SchoolDailyStatisticService < ApplicationService
- include CustomSortable
-
- attr_reader :params
-
- sort_columns :student_count, :teacher_count, :homework_count, :other_homework_count,
- :course_count, :active_course_count, :nearly_course_time, :shixun_count, :shixun_evaluate_count,
- default_by: :teacher_count, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- schools = School.group('schools.id')
-
- keyword = params[:keyword].try(:to_s).try(:strip)
- if keyword.present?
- schools = schools.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
- end
-
- count = schools.count.count
-
- # 根据排序字段进行查询
- schools = query_by_sort_column(schools, params[:sort_by])
- schools = custom_sort(schools, params[:sort_by], params[:sort_direction])
-
- schools = schools.limit(page_size).offset(offset)
- # 查询并组装其它数据
- schools = package_other_data(schools)
-
- [count, schools]
- end
-
- def package_other_data(schools)
- ids = schools.map(&:id)
-
- student_map = UserExtension.where(school_id: ids, identity: :student).group(:school_id).count
- teacher_map = UserExtension.where(school_id: ids, identity: :teacher).group(:school_id).count
-
- homeworks = HomeworkCommon.joins(:course)
- shixun_homework_map = homeworks.where(homework_type: 4, courses: { school_id: ids }).group('school_id').count
- other_homework_map = homeworks.where(homework_type: [1, 3], courses: { school_id: ids }).group('school_id').count
-
- courses = Course.where(is_delete: 0, school_id: ids).group('school_id')
- course_map = courses.count
- nearly_course_time_map = courses.joins(:course_acts).maximum('course_activities.updated_at')
- active_course_map = courses.where(is_end: false).count
-
- shixun_map = Shixun.joins(user: :user_extension).where(user_extensions: { identity: :teacher, school_id: ids })
- .where(fork_from: nil).group('school_id').count
-
- reports = SchoolReport.where(school_id: ids)
- evaluate_count_map = reports.each_with_object({}) { |report, obj| obj[report.school_id] = report.shixun_evaluate_count }
-
- schools.map do |school|
- {
- id: school.id,
- name: school.name,
- teacher_count: teacher_map[school.id],
- student_count: student_map[school.id],
- homework_count: shixun_homework_map[school.id],
- other_homework_count: other_homework_map[school.id],
- course_count: course_map[school.id],
- nearly_course_time: nearly_course_time_map[school.id],
- active_course_count: active_course_map[school.id],
- shixun_count: shixun_map.fetch(school.id, 0),
- shixun_evaluate_count: evaluate_count_map.fetch(school.id, 0)
- }
- end
- end
-
- private
- def query_by_sort_column(schools, sort_by_column)
- base_query_column = 'schools.id, schools.name'
-
- case sort_by_column.to_s
- when 'teacher_count' then
- schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
- .select("#{base_query_column}, COUNT(*) teacher_count")
- when 'student_count' then
- schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 1')
- .select("#{base_query_column}, COUNT(*) student_count")
- when 'homework_count' then
- schools.joins('LEFT JOIN courses ON courses.school_id = schools.id')
- .joins('LEFT JOIN homework_commons hc ON hc.course_id = courses.id AND hc.homework_type = 4')
- .select("#{base_query_column}, COUNT(*) homework_count")
- when 'other_homework_count' then
- schools.joins('LEFT JOIN courses ON courses.school_id = schools.id')
- .joins('LEFT JOIN homework_commons hc ON hc.course_id = courses.id AND hc.homework_type IN (1, 3)')
- .select("#{base_query_column}, COUNT(*) other_homework_count")
- when 'course_count' then
- schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0')
- .select("#{base_query_column}, COUNT(*) course_count")
- when 'shixun_count' then
- schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
- .joins('LEFT JOIN users ON users.id = ue.user_id')
- .joins('LEFT JOIN shixuns sx ON sx.user_id = users.id AND sx.fork_from IS NULL')
- .select("#{base_query_column}, COUNT(*) shixun_count")
- when 'shixun_evaluate_count' then
- schools.joins('LEFT JOIN school_reports ON school_reports.school_id = schools.id')
- .select("#{base_query_column}, shixun_evaluate_count")
- when 'nearly_course_time' then
- schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0')
- .joins('LEFT JOIN course_activities acs ON acs.course_id = cs.id')
- .select("#{base_query_column}, MAX(acs.updated_at) nearly_course_time")
- when 'active_course_count' then
- schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0 AND cs.is_end = false')
- .select("#{base_query_column}, COUNT(*) active_course_count")
- else
- schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
- .select("#{base_query_column}, COUNT(*) teacher_count")
- end
- end
-
- def page_size
- params[:per_page] || 20
- end
-
- def offset
- (params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * page_size
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/shixun_auths/agree_apply_service.rb b/app/services/admins/shixun_auths/agree_apply_service.rb
deleted file mode 100644
index b8875cf09..000000000
--- a/app/services/admins/shixun_auths/agree_apply_service.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-class Admins::ShixunAuths::AgreeApplyService < ApplicationService
- attr_reader :apply, :user, :shixun
-
- def initialize(apply, user)
- @apply = apply
- @user = user
- @shixun = Shixun.find(apply.container_id)
- end
-
- def call
- ActiveRecord::Base.transaction do
- apply.update!(status: 1, dealer_id: user.id)
- shixun.update!(public: 2, publish_time: Time.now)
-
- # 奖励金币、经验
- reward_grade_and_experience!
-
- deal_tiding!
- end
- end
-
- private
-
- def reward_grade_and_experience!
- score = shixun.all_score
- shixun_creator = shixun.user
-
- RewardGradeService.call(shixun_creator, container_id: shixun.id, container_type: 'shixunPublish', score: score)
-
- Experience.create!(user_id: shixun_creator.id, container_id: shixun.id, container_type: 'shixunPublish', score: score)
- shixun_creator.update_column(:experience, shixun_creator.experience.to_i + score)
- end
-
- def deal_tiding!
- apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
-
- Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
- container_id: apply.id, container_type: 'ApplyAction',
- parent_container_id: apply.container_id, parent_container_type: apply.container_type,
- belong_container_id: apply.container_id, belong_container_type: 'Shixun',
- status: 1, tiding_type: 'System')
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/shixun_auths/refuse_apply_service.rb b/app/services/admins/shixun_auths/refuse_apply_service.rb
deleted file mode 100644
index 76d420e53..000000000
--- a/app/services/admins/shixun_auths/refuse_apply_service.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class Admins::ShixunAuths::RefuseApplyService < ApplicationService
- attr_reader :apply, :user, :shixun, :params
-
- def initialize(apply, user, params)
- @apply = apply
- @user = user
- @shixun = Shixun.find(apply.container_id)
- @params = params
- end
-
- def call
- ActiveRecord::Base.transaction do
- shixun.update!(public: 0)
- apply.update!(status: 2, reason: reason, dealer_id: user.id)
-
- deal_tiding!
- end
- end
-
- private
-
- def reason
- params[:reason].to_s.strip
- end
-
- def deal_tiding!
- apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
-
- Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
- container_id: apply.id, container_type: 'ApplyAction',
- parent_container_id: apply.container_id, parent_container_type: apply.container_type,
- belong_container_id: apply.container_id, belong_container_type: 'Shixun',
- status: 2, tiding_type: 'System')
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/statistic_school_contrast_data_service.rb b/app/services/admins/statistic_school_contrast_data_service.rb
deleted file mode 100644
index 0496b1371..000000000
--- a/app/services/admins/statistic_school_contrast_data_service.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-class Admins::StatisticSchoolContrastDataService < ApplicationService
- ParameterError = Class.new(StandardError)
-
- PAGE_SIZE = 20
- CONTRAST_COLUMN_LIST = %w(
- teacher_increase_count student_increase_count course_increase_count
- shixun_increase_count active_user_count shixun_homework_count shixun_evaluate_count
- ).freeze
-
- attr_reader :params, :sort_direction, :contrast_column
-
- def initialize(params)
- @params = params
- @sort_direction = params[:sort_direction].to_s
- @contrast_column = params[:contrast_column].to_s
- end
-
- def call
- validate_parameter!
- reports = School.joins(:school_daily_reports).select(select_columns)
-
- keyword = params[:keyword].try(:to_s).try(:strip)
- if keyword.present?
- reports = reports.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
- end
-
- count = reports.count('distinct(schools.id)')
-
- sql = query_report_sql(reports.group('schools.id').to_sql)
- reports = SchoolDailyReport.find_by_sql(sql)
-
- [count, reports]
- end
-
- private
- def validate_parameter!
- if %i[begin_date end_date other_begin_date other_end_date].any? { |key| params[key].blank? }
- raise ParameterError
- end
-
- unless %w(desc asc).include?(sort_direction)
- raise ParameterError
- end
-
- unless CONTRAST_COLUMN_LIST.include?(contrast_column)
- raise ParameterError
- end
- end
-
- def format_date(date)
- Time.zone.parse(date).strftime("%Y-%m-%d")
- end
-
- def offset
- (params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * PAGE_SIZE
- end
-
- def select_columns
- if contrast_column != 'active_user_count'
- "schools.id school_id, schools.name school_name,"\
- "(SUM(IF(date BETWEEN '#{format_date(params[:begin_date])}' AND '#{format_date(params[:end_date])}', #{contrast_column}, 0))) total,"\
- "(SUM(IF(date BETWEEN '#{format_date(params[:other_begin_date])}' AND '#{format_date(params[:other_end_date])}', #{contrast_column}, 0))) other_total"
- else
- # 活跃用户对比时处理方法不同
- relations = SchoolDailyActiveUser.select('COUNT(distinct user_id)').joins(:school_daily_report)
- .where('school_id = schools.id')
- total_subquery = relations.where("date BETWEEN '#{format_date(params[:begin_date])}' AND '#{format_date(params[:end_date])}'").to_sql
- other_total_subquery = relations.where("date BETWEEN '#{format_date(params[:other_begin_date])}' AND '#{format_date(params[:other_end_date])}'").to_sql
-
- "schools.id school_id, schools.name school_name, (#{total_subquery}) AS total, (#{other_total_subquery}) AS other_total"
- end
- end
-
- def query_report_sql(from_sql)
- order_by = "(total = 0 AND other_total != 0) #{sort_direction}, (percentage != 0) #{sort_direction}, percentage #{sort_direction}"
-
- "SELECT reports.*, (other_total - total) increase, (IF(other_total - total = 0, 0.0, round((other_total - total) / IF(total = 0, 1, total), 5))) percentage "\
- "FROM (#{from_sql}) reports ORDER BY #{order_by} LIMIT #{PAGE_SIZE} OFFSET #{offset}"
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/statistic_school_data_grow_service.rb b/app/services/admins/statistic_school_data_grow_service.rb
deleted file mode 100644
index 8df106666..000000000
--- a/app/services/admins/statistic_school_data_grow_service.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-class Admins::StatisticSchoolDataGrowService < ApplicationService
- include CustomSortable
-
- PAGE_SIZE = 20
-
- attr_reader :params
-
- sort_columns :teacher_increase_count, :student_increase_count,
- :course_increase_count, :shixun_increase_count, :uniq_active_user_count,
- :shixun_homework_count, :shixun_evaluate_count,
- default_by: :teacher_increase_count, default_direction: :desc
-
- def initialize(params)
- @params = params
- end
-
- def call
- reports = School.where(nil)
-
- reports = search_filter(reports)
-
- count = reports.count
-
- subquery = SchoolDailyActiveUser.select('COUNT(distinct(user_id))').joins(:school_daily_report)
- .where(date_condition_sql).where("school_id is not null and school_id = schools.id").to_sql
- reports = reports.joins("LEFT JOIN school_daily_reports sdr ON sdr.school_id = schools.id AND #{date_condition_sql}")
- reports = reports.select(
- 'schools.id school_id, schools.name school_name,'\
- 'SUM(teacher_increase_count) teacher_increase_count,'\
- 'SUM(student_increase_count) student_increase_count,'\
- 'SUM(course_increase_count) course_increase_count,'\
- 'SUM(shixun_increase_count) shixun_increase_count,'\
- 'SUM(shixun_homework_count) shixun_homework_count,'\
- 'SUM(shixun_evaluate_count) shixun_evaluate_count,'\
- "(#{subquery}) uniq_active_user_count,"\
- 'SUM(active_user_count) active_user_count').group('schools.id')
-
- reports = custom_sort(reports, params[:sort_by], params[:sort_direction])
- reports = reports.order('school_id asc').limit(PAGE_SIZE).offset(offset)
-
- [count, reports]
- end
-
- def grow_summary
- @_grow_summary ||= begin
- reports = School.joins("LEFT JOIN school_daily_reports sdr ON sdr.school_id = schools.id")
- .where(date_condition_sql)
-
- subquery = SchoolDailyActiveUser.select('COUNT(distinct user_id)')
- .joins('LEFT JOIN school_daily_reports sdr ON sdr.id = school_daily_active_users.school_daily_report_id')
- .where(date_condition_sql).to_sql
- reports = search_filter(reports)
- reports.select(
- 'SUM(teacher_increase_count) teacher_increase_count,'\
- 'SUM(student_increase_count) student_increase_count,'\
- 'SUM(course_increase_count) course_increase_count,'\
- 'SUM(shixun_increase_count) shixun_increase_count,'\
- 'SUM(shixun_homework_count) shixun_homework_count,'\
- 'SUM(shixun_evaluate_count) shixun_evaluate_count,'\
- "(#{subquery}) uniq_active_user_count,"\
- 'SUM(active_user_count) active_user_count'
- ).first
- end
- end
-
- private
-
- def search_filter(relations)
- keyword = params[:keyword].try(:to_s).try(:strip)
- if keyword.present?
- relations = relations.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
- end
-
- relations
- end
-
- def date_condition_sql
- date = query_date
- if date.is_a?(Range)
- "date BETWEEN '#{date.min.strftime('%Y-%m-%d')}' AND '#{date.max.strftime('%Y-%m-%d')}'"
- else
- "date = '#{date.strftime('%Y-%m-%d')}'"
- end
- end
-
- def query_date
- if params[:grow_begin_date].present?
- begin_time = Time.zone.parse(params[:grow_begin_date])
- end_date = if params[:grow_end_date].present?
- Time.zone.parse(params[:grow_end_date])
- end
-
- end_date.blank? || end_date == begin_time ? begin_time : begin_time..end_date
- else
- yesterday
- end
- end
-
- def yesterday
- # 每日凌晨5点为节点, 25日凌晨4点、3点、2点等等,未到更新数据时间点,看到的数据是:23日-24日的统计数据
- (Time.zone.now - 5.hours).beginning_of_day - 1.days
- end
-
- def offset
- (params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * PAGE_SIZE
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/subject_auths/agree_apply_service.rb b/app/services/admins/subject_auths/agree_apply_service.rb
deleted file mode 100644
index ec5fec4bb..000000000
--- a/app/services/admins/subject_auths/agree_apply_service.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class Admins::SubjectAuths::AgreeApplyService < ApplicationService
- attr_reader :apply, :user, :subject
-
- def initialize(apply, user)
- @apply = apply
- @user = user
- @subject = Subject.find(apply.container_id)
- end
-
- def call
- ActiveRecord::Base.transaction do
- apply.update!(status: 1, dealer_id: user.id)
- subject.update!(public: 2, publish_time: Time.now)
-
- deal_tiding!
- end
- end
-
- private
-
- def deal_tiding!
- apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
-
- Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
- container_id: apply.id, container_type: 'ApplyAction',
- parent_container_id: apply.container_id, parent_container_type: apply.container_type,
- belong_container_id: apply.container_id, belong_container_type: 'Subject',
- status: 1, tiding_type: 'System')
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/subject_auths/refuse_apply_service.rb b/app/services/admins/subject_auths/refuse_apply_service.rb
deleted file mode 100644
index 45f2d44d3..000000000
--- a/app/services/admins/subject_auths/refuse_apply_service.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class Admins::SubjectAuths::RefuseApplyService < ApplicationService
- attr_reader :apply, :user, :subject, :params
-
- def initialize(apply, user, params)
- @apply = apply
- @user = user
- @subject = Subject.find(apply.container_id)
- @params = params
- end
-
- def call
- ActiveRecord::Base.transaction do
- subject.update!(public: 0)
- apply.update!(status: 2, reason: reason, dealer_id: user.id)
-
- deal_tiding!
- end
- end
-
- private
-
- def reason
- params[:reason].to_s.strip
- end
-
- def deal_tiding!
- apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
-
- Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
- container_id: apply.id, container_type: 'ApplyAction',
- parent_container_id: apply.container_id, parent_container_type: apply.container_type,
- belong_container_id: apply.container_id, belong_container_type: 'Subject',
- status: 2, tiding_type: 'System')
- end
-end
\ No newline at end of file
diff --git a/app/services/admins/update_user_service.rb b/app/services/admins/update_user_service.rb
index 6b1c0c857..34f704cbe 100644
--- a/app/services/admins/update_user_service.rb
+++ b/app/services/admins/update_user_service.rb
@@ -15,19 +15,13 @@ class Admins::UpdateUserService < ApplicationService
user.firstname = ''
user.password = params[:password] if params[:password].present?
- if params[:identity].to_s == 'student'
- params[:technical_title] = nil
- else
- params[:student_id] = nil
- end
user.user_extension.assign_attributes(user_extension_attributes)
+ old_login = user.login
ActiveRecord::Base.transaction do
user.save!
user.user_extension.save!
- user.update!(is_shixun_marker: true) if user.is_certification_teacher
-
- update_gitlab_password if params[:password].present?
+ update_gitea_user(old_login)
end
user
@@ -36,7 +30,7 @@ class Admins::UpdateUserService < ApplicationService
private
def user_attributes
- params.slice(*%i[lastname nickname mail phone admin business is_test
+ params.slice(*%i[lastname nickname mail phone admin business is_test login
professional_certification authentication is_shixun_marker])
end
@@ -44,10 +38,29 @@ class Admins::UpdateUserService < ApplicationService
params.slice(*%i[gender identity technical_title student_id location location_city school_id department_id])
end
- def update_gitlab_password
- return if user.gid.blank?
- # 同步修改gitlab密码
- Gitlab.client.edit_user(user.gid, password: params[:password])
+ def gitea_user_params
+ hash = {
+ password: params[:password].to_s.presence,
+ email: user.mail,
+ login_name: params[:login].to_s.presence,
+ admin: boolean_admin
+ }.compact
+
+ hash.delete_if {|_,v| v.to_s.strip == ''}
+ end
+
+ def boolean_admin
+ admin = params[:admin].to_s.presence
+ case admin
+ when "0" then false
+ when "1" then true
+ end
+ end
+
+ def update_gitea_user(old_login)
+ return if user.gitea_uid.blank?
+
+ Gitea::User::UpdateInteractor.call(old_login, gitea_user_params)
rescue Exception => ex
Util.logger_error(ex)
raise Error, '保存失败'
diff --git a/app/services/atme_service.rb b/app/services/atme_service.rb
new file mode 100644
index 000000000..623b32c09
--- /dev/null
+++ b/app/services/atme_service.rb
@@ -0,0 +1,37 @@
+class AtmeService < ApplicationService
+ Error = Class.new(StandardError)
+
+ attr_reader :user, :receivers, :atmeable
+
+ def initialize(user, receivers, atmeable)
+ @user = user
+ @receivers = receivers
+ @atmeable = atmeable
+ end
+
+ def call
+ Rails.logger.info "[ATME] service args: [user]=>#{user}, [receivers]=>#{receivers}, [atmeable]=>#{atmeable}"
+ return if atmeable.nil?
+ Rails.logger.info "[ATME] atmeable class name is: #{ atmeable.class.name}"
+ case atmeable.class.name
+ when 'Issue'
+ message_source = 'IssueAtme'
+ when 'PullRequest'
+ message_source = 'PullRequestAtme'
+ when 'Journal'
+ journal = Journal.find_by_id(atmeable.id)
+ if journal.present?
+ if journal&.issue&.pull_request.present?
+ @atmeable = journal&.issue&.pull_request
+ message_source = 'PullRequestAtme'
+ else
+ @atmeable = journal&.issue
+ message_source = 'IssueAtme'
+ end
+ end
+ else
+ return
+ end
+ SendTemplateMessageJob.perform_now(message_source, receivers, user.id, @atmeable.id) if Site.has_notice_menu?
+ end
+end
diff --git a/app/services/cache/platform_project_languages_count_service.rb b/app/services/cache/platform_project_languages_count_service.rb
index 2b4f0fae4..0c6ffab19 100644
--- a/app/services/cache/platform_project_languages_count_service.rb
+++ b/app/services/cache/platform_project_languages_count_service.rb
@@ -46,11 +46,11 @@ class Cache::PlatformProjectLanguagesCountService < ApplicationService
def reset_platform_project_language_count_by_key
return if key.nil?
- $redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count)
+ $redis_cache.hset(platform_project_language_count_key, key, ProjectLanguage.where(name: key).projects_count)
end
def reset_platform_project_language_count
- Project.joins(:project_language).group("project_languages.name").count.each do |k, v|
+ ProjectLanguage.where.not(projects_count: 0).group("project_languages.name").sum(:projects_count).each do |k, v|
$redis_cache.hset(platform_project_language_count_key, k, v)
end
end
diff --git a/app/services/cache/v2/owner_common_service.rb b/app/services/cache/v2/owner_common_service.rb
new file mode 100644
index 000000000..c97e34d48
--- /dev/null
+++ b/app/services/cache/v2/owner_common_service.rb
@@ -0,0 +1,135 @@
+class Cache::V2::OwnerCommonService < ApplicationService
+ include AvatarHelper
+ attr_reader :owner_id, :name
+ attr_accessor :owner, :login, :email
+
+ def initialize(owner_id, params={})
+ @owner_id = owner_id
+ @email = params[:email]
+ @name = params[:name]
+ @avatar_url = params[:avatar_url]
+ end
+
+ def read
+ owner_common
+ end
+
+ def call
+ set_owner_common
+ end
+
+ def reset
+ reset_owner_common
+ end
+
+ def clear
+ clear_owner_common
+ end
+
+ private
+ def load_owner
+ @owner = Owner.find_by_id @owner_id
+ @login = @owner&.login
+ @email ||= @owner&.mail
+ end
+
+ def owner_common_key
+ "v2-owner-common:#{@login}-#{@email.to_s}"
+ end
+
+ def owner_common_key_by_id
+ "v2-owner-common:#{@owner&.id}"
+ end
+
+ def owner_common
+ result = $redis_cache.hgetall(owner_common_key_by_id)
+ result.blank? ? reset_owner_common : result
+ end
+
+ def set_owner_common
+ if $redis_cache.hgetall(owner_common_key_by_id).blank?
+ reset_owner_common
+ return
+ else
+ load_owner
+ return if @owner.nil?
+ if @name.present?
+ if $redis_cache.hget(owner_common_key, "name").nil?
+ reset_owner_name
+ else
+ $redis_cache.hset(owner_common_key, "name", @name)
+ $redis_cache.hset(owner_common_key_by_id, "name", @name)
+ end
+ end
+ if @email.present?
+ if $redis_cache.hget(owner_common_key, "email").nil?
+ reset_owner_email
+ else
+ # 更改邮箱这里把旧数据删除
+ $redis_cache.del("v2-owner-common:#{@login}-*")
+ $redis_cache.hset(owner_common_key, "email", @email)
+ $redis_cache.hset(owner_common_key_by_id, "email", @email)
+ end
+ end
+ if @avatar_url.present?
+ if $redis_cache.hget(owner_common_key, "avatar_url").nil?
+ reset_owner_avatar_url
+ else
+ $redis_cache.hset(owner_common_key, "avatar_url", @avatar_url)
+ $redis_cache.hset(owner_common_key_by_id, "avatar_url", @avatar_url)
+ end
+
+ end
+ end
+
+ $redis_cache.hgetall(owner_common_key)
+ end
+ def reset_owner_id
+ $redis_cache.hset(owner_common_key, "id", owner&.id)
+ $redis_cache.hset(owner_common_key_by_id, "id", owner&.id)
+ end
+
+ def reset_owner_type
+ $redis_cache.hset(owner_common_key, "type", owner&.type)
+ $redis_cache.hset(owner_common_key_by_id, "type", owner&.type)
+ end
+
+ def reset_owner_login
+ $redis_cache.hset(owner_common_key, "login", owner&.login)
+ $redis_cache.hset(owner_common_key_by_id, "login", owner&.login)
+ end
+
+ def reset_owner_email
+ $redis_cache.hset(owner_common_key, "email", owner&.mail)
+ $redis_cache.hset(owner_common_key_by_id, "email", owner&.mail)
+ end
+
+ def reset_owner_name
+ $redis_cache.hset(owner_common_key, "name", owner&.real_name)
+ $redis_cache.hset(owner_common_key_by_id, "name", owner&.real_name)
+ end
+
+ def reset_owner_avatar_url
+ $redis_cache.hset(owner_common_key, "avatar_url", url_to_avatar(owner))
+ $redis_cache.hset(owner_common_key_by_id, "avatar_url", url_to_avatar(owner))
+ end
+
+ def reset_owner_common
+ clear_owner_common
+ reset_owner_id
+ reset_owner_type
+ reset_owner_login
+ reset_owner_email
+ reset_owner_name
+ reset_owner_avatar_url
+
+ $redis_cache.hgetall(owner_common_key)
+ end
+
+ def clear_owner_common
+ load_owner
+ return if @owner.nil?
+ $redis_cache.del(owner_common_key)
+ $redis_cache.del(owner_common_key_by_id)
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/platform_statistic_service.rb b/app/services/cache/v2/platform_statistic_service.rb
new file mode 100644
index 000000000..5bf4f4a74
--- /dev/null
+++ b/app/services/cache/v2/platform_statistic_service.rb
@@ -0,0 +1,184 @@
+class Cache::V2::PlatformStatisticService < ApplicationService
+ attr_reader :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
+
+ def initialize(params={})
+ @follow_count = params[:follow_count]
+ @fork_count = params[:fork_count]
+ @issue_count = params[:issue_count]
+ @project_count = params[:project_count]
+ @project_language_count_key = params[:project_language_count_key]
+ @project_language_count = params[:project_language_count]
+ @project_praise_count = params[:project_praise_count]
+ @project_watcher_count = params[:project_watcher_count]
+ @pullrequest_count = params[:pullrequest_count]
+ end
+
+ def read
+ platform_statistic
+ end
+
+ def call
+ set_platform_statistic
+ end
+
+ def reset
+ reset_platform_statistic
+ end
+
+ private
+
+ def platform_statistic_key
+ "v2-platform-statistic"
+ end
+
+ def follow_count_key
+ "follow-count"
+ end
+
+ def fork_count_key
+ "fork-count"
+ end
+
+ def issue_count_key
+ "issue-count"
+ end
+
+ def project_count_key
+ "project-count"
+ end
+
+ def project_language_key
+ "project-language"
+ end
+
+ def project_praise_count_key
+ "project-praise-count"
+ end
+
+ def project_watcher_count_key
+ "project-watcher-count"
+ end
+
+ def pullrequest_count_key
+ "pullrequest-count"
+ end
+
+ def platform_statistic
+ result = $redis_cache.hgetall(platform_statistic_key)
+
+ result.blank? ? reset_platform_statistic : result
+ end
+
+ def set_platform_statistic
+ if $redis_cache.hgetall(platform_statistic_key).blank?
+ reset_platform_statistic
+ return
+ end
+ if @follow_count.present?
+ if $redis_cache.hget(platform_statistic_key, follow_count_key).nil?
+ reset_platform_follow_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, follow_count_key, @follow_count)
+ end
+ end
+ if @fork_count.present?
+ if $redis_cache.hget(platform_statistic_key, fork_count_key).nil?
+ reset_platform_fork_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, fork_count_key, @fork_count)
+ end
+ end
+ if @issue_count.present?
+ if $redis_cache.hget(platform_statistic_key, issue_count_key).nil?
+ reset_platform_issue_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, issue_count_key, @issue_count)
+ end
+ end
+ if @project_count.present?
+ if $redis_cache.hget(platform_statistic_key, project_count_key).nil?
+ reset_platform_project_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, project_count_key, @project_count)
+ end
+ end
+ if @project_language_count_key.present? && project_language_count.present?
+ if $redis_cache.hget(platform_statistic_key, project_language_key).nil?
+ reset_platform_project_language
+ else
+ result = JSON.parse($redis_cache.hget(platform_statistic_key, project_language_key))
+ result[@project_language_count_key] ||= 0
+ result[@project_language_count_key] += project_language_count.to_i
+ $redis_cache.hset(platform_statistic_key, project_language_key, result.to_json)
+ end
+ end
+ if @project_praise_count.present?
+ if $redis_cache.hget(platform_statistic_key, project_praise_count_key).nil?
+ reset_platform_project_praise_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, project_praise_count_key, @project_praise_count)
+ end
+ end
+ if @project_watcher_count.present?
+ if $redis_cache.hget(platform_statistic_key, project_watcher_count_key).nil?
+ reset_platform_project_watcher_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, project_watcher_count_key, @project_watcher_count)
+ end
+ end
+ if @pullrequest_count.present?
+ if $redis_cache.hget(platform_statistic_key, pullrequest_count_key).nil?
+ reset_platform_pullrequest_count
+ else
+ $redis_cache.hincrby(platform_statistic_key, pullrequest_count_key, @pullrequest_count)
+ end
+ end
+ $redis_cache.hgetall(platform_statistic_key)
+ end
+
+ def reset_platform_follow_count
+ $redis_cache.hset(platform_statistic_key, follow_count_key, Watcher.where(watchable_type: 'User').count)
+ end
+
+ def reset_platform_fork_count
+ $redis_cache.hset(platform_statistic_key, fork_count_key, ForkUser.count)
+ end
+
+ def reset_platform_issue_count
+ $redis_cache.hset(platform_statistic_key, issue_count_key, Issue.count)
+ end
+
+ def reset_platform_project_count
+ $redis_cache.hset(platform_statistic_key, project_count_key, Project.count)
+ end
+
+ def reset_platform_project_language
+ $redis_cache.hset(platform_statistic_key, project_language_key, ProjectLanguage.where.not(projects_count: 0).group("project_languages.name").sum(:projects_count).to_json)
+ end
+
+ def reset_platform_project_praise_count
+ $redis_cache.hset(platform_statistic_key, project_praise_count_key, PraiseTread.where(praise_tread_object_type: "Project").count)
+ end
+
+ def reset_platform_project_watcher_count
+ $redis_cache.hset(platform_statistic_key, project_watcher_count_key, Watcher.where(watchable_type: 'Project').count)
+ end
+
+ def reset_platform_pullrequest_count
+ $redis_cache.hset(platform_statistic_key, pullrequest_count_key, PullRequest.count)
+ end
+
+ def reset_platform_statistic
+ $redis_cache.del(platform_statistic_key)
+ reset_platform_follow_count
+ reset_platform_fork_count
+ reset_platform_issue_count
+ reset_platform_project_count
+ reset_platform_project_language
+ reset_platform_project_praise_count
+ reset_platform_project_watcher_count
+ reset_platform_pullrequest_count
+
+ $redis_cache.hgetall(platform_statistic_key)
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/project_common_service.rb b/app/services/cache/v2/project_common_service.rb
new file mode 100644
index 000000000..760c6d05b
--- /dev/null
+++ b/app/services/cache/v2/project_common_service.rb
@@ -0,0 +1,219 @@
+class Cache::V2::ProjectCommonService < ApplicationService
+ attr_reader :project_id, :owner_id, :name, :identifier, :description, :visits, :watchers, :praises, :forks, :issues, :pullrequests
+ attr_accessor :project
+
+ def initialize(project_id, params={})
+ @project_id = project_id
+ @owner_id = params[:owner_id]
+ @name = params[:name]
+ @identifier = params[:identifier]
+ @description = params[:description]
+ @visits = params[:visits]
+ @watchers = params[:watchers]
+ @praises = params[:praises]
+ @forks = params[:forks]
+ @issues = params[:issues]
+ @pullrequests = params[:pullrequests]
+ end
+
+ def read
+ project_common
+ end
+
+ def call
+ set_project_common
+ end
+
+ def reset
+ reset_project_common
+ end
+
+ def clear
+ clear_project_common
+ end
+
+ private
+ def load_project
+ @project = Project.find_by_id(project_id)
+ end
+
+ def project_common_key
+ "v2-project-common:#{@project_id}"
+ end
+
+ def owner_id_key
+ "owner_id"
+ end
+
+ def name_key
+ "name"
+ end
+
+ def identifier_key
+ "identifier"
+ end
+
+ def description_key
+ "description"
+ end
+
+ def visits_key
+ "visits"
+ end
+
+ def watchers_key
+ "watchers"
+ end
+
+ def praises_key
+ "praises"
+ end
+
+ def forks_key
+ "forks"
+ end
+
+ def issues_key
+ "issues"
+ end
+
+ def pullrequests_key
+ "pullrequests"
+ end
+
+ def project_common
+ result = $redis_cache.hgetall(project_common_key)
+ result.blank? ? reset_project_common : result
+ end
+
+ def set_project_common
+ if $redis_cache.hgetall(project_common_key).blank?
+ reset_project_common
+ return
+ else
+ load_project
+ return unless @project.is_full_public
+ if @owner_id.present?
+ if $redis_cache.hget(project_common_key, owner_id_key).nil?
+ reset_project_owner_id
+ else
+ $redis_cache.hset(project_common_key, owner_id_key, @owner_id)
+ end
+ end
+ if @name.present?
+ if $redis_cache.hget(project_common_key, name_key).nil?
+ reset_project_name
+ else
+ $redis_cache.hset(project_common_key, name_key, @name)
+ end
+ end
+ if @identifier.present?
+ if $redis_cache.hget(project_common_key, identifier_key).nil?
+ reset_project_identifier
+ else
+ $redis_cache.hset(project_common_key, identifier_key, @identifier)
+ end
+ end
+ if @description.present?
+ if $redis_cache.hget(project_common_key, description_key).nil?
+ reset_project_description
+ else
+ $redis_cache.hset(project_common_key, description_key, @description)
+ end
+ end
+ if @visits.present?
+ $redis_cache.hincrby(project_common_key, visits_key, @visits.to_s)
+ Cache::V2::ProjectRankService.call(@project_id, {visits: @visits})
+ Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {visits: @visits})
+ end
+ if @watchers.present?
+ $redis_cache.hincrby(project_common_key, watchers_key, @watchers)
+ end
+ if @praises.present?
+ $redis_cache.hincrby(project_common_key, praises_key, @praises)
+ Cache::V2::ProjectRankService.call(@project_id, {praises: @praises})
+ Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {praises: @praises})
+ end
+ if @forks.present?
+ $redis_cache.hincrby(project_common_key, forks_key, @forks)
+ Cache::V2::ProjectRankService.call(@project_id, {forks: @forks})
+ Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {forks: @forks})
+ end
+ if @issues.present?
+ $redis_cache.hincrby(project_common_key, issues_key, @issues)
+ Cache::V2::ProjectRankService.call(@project_id, {issues: @issues})
+ Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {issues: @issues})
+ end
+ if @pullrequests.present?
+ $redis_cache.hincrby(project_common_key, pullrequests_key, @pullrequests)
+ Cache::V2::ProjectRankService.call(@project_id, {pullrequests: @pullrequests})
+ Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {pullrequests: @pullrequests})
+ end
+ end
+
+ $redis_cache.hgetall(project_common_key)
+ end
+
+ def reset_project_owner_id
+ $redis_cache.hset(project_common_key, owner_id_key, @project&.user_id)
+ end
+
+ def reset_project_name
+ $redis_cache.hset(project_common_key, name_key, @project&.name)
+ end
+
+ def reset_project_identifier
+ $redis_cache.hset(project_common_key, identifier_key, @project&.identifier)
+ end
+
+ def reset_project_description
+ $redis_cache.hset(project_common_key, description_key, @project&.description)
+ end
+
+ def reset_project_visits
+ $redis_cache.hset(project_common_key, visits_key, @project&.visits || 0)
+ end
+
+ def reset_project_watchers
+ $redis_cache.hset(project_common_key, watchers_key, Watcher.where(watchable_type: 'Project', watchable_id: @project_id).count)
+ end
+
+ def reset_project_praises
+ $redis_cache.hset(project_common_key, praises_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: @project_id).count)
+ end
+
+ def reset_project_forks
+ $redis_cache.hset(project_common_key, forks_key, ForkUser.where(project_id: @project_id).count)
+ end
+
+ def reset_project_issues
+ $redis_cache.hset(project_common_key, issues_key, Issue.issue_issue.where(project_id: @project_id).count)
+ end
+
+ def reset_project_pullrequests
+ $redis_cache.hset(project_common_key, pullrequests_key, PullRequest.where(project_id: @project_id).count)
+ end
+
+ def reset_project_common
+ load_project
+ return unless @project.is_full_public
+ $redis_cache.del(project_common_key)
+ reset_project_owner_id
+ reset_project_name
+ reset_project_identifier
+ reset_project_description
+ reset_project_visits
+ reset_project_watchers
+ reset_project_praises
+ reset_project_forks
+ reset_project_issues
+ reset_project_pullrequests
+
+ $redis_cache.hgetall(project_common_key)
+ end
+
+ def clear_project_common
+ $redis_cache.del(project_common_key)
+ Cache::V2::ProjectRankService.new(@project_id).clear
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/project_date_rank_service.rb b/app/services/cache/v2/project_date_rank_service.rb
new file mode 100644
index 000000000..092aff796
--- /dev/null
+++ b/app/services/cache/v2/project_date_rank_service.rb
@@ -0,0 +1,51 @@
+class Cache::V2::ProjectDateRankService < ApplicationService
+ attr_reader :project_id, :rank_date, :visits, :praises, :forks, :issues, :pullrequests
+ attr_accessor :project_common
+
+ def initialize(project_id, rank_date=Date.today, params={})
+ @project_id = project_id
+ @rank_date = rank_date
+ @visits = params[:visits]
+ @praises = params[:praises]
+ @forks = params[:forks]
+ @issues = params[:issues]
+ @pullrequests = params[:pullrequests]
+ end
+
+ def read
+ project_rank
+ end
+
+ def call
+ set_project_rank
+ end
+
+ private
+ def project_rank_key
+ "v2-project-rank-#{@rank_date.to_s}"
+ end
+
+ def project_rank
+ $redis_cache.zscore(project_rank_key, @project_id)
+ end
+
+ def set_project_rank
+ if @visits.present?
+ $redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id)
+ end
+ if @praises.present?
+ $redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id)
+ end
+ if @forks.present?
+ $redis_cache.zincrby(project_rank_key, @forks.to_i * 5, @project_id)
+ end
+ if @issues.present?
+ $redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id)
+ end
+ if @pullrequests.present?
+ $redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id)
+ end
+
+ $redis_cache.zscore(project_rank_key, @project_id)
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/project_rank_service.rb b/app/services/cache/v2/project_rank_service.rb
new file mode 100644
index 000000000..7e5d323bf
--- /dev/null
+++ b/app/services/cache/v2/project_rank_service.rb
@@ -0,0 +1,87 @@
+class Cache::V2::ProjectRankService < ApplicationService
+ attr_reader :project_id, :visits, :praises, :forks, :issues, :pullrequests
+ attr_accessor :project_common
+
+ def initialize(project_id, params={})
+ @project_id = project_id
+ @visits = params[:visits]
+ @praises = params[:praises]
+ @forks = params[:forks]
+ @issues = params[:issues]
+ @pullrequests = params[:pullrequests]
+ end
+
+ def read
+ project_rank
+ end
+
+ def call
+ set_project_rank
+ end
+
+ def reset
+ reset_project_rank
+ end
+
+ def clear
+ clear_project_rank
+ end
+
+ private
+ def load_project_common
+ @project_common = Cache::V2::ProjectCommonService.new(@project_id).read
+ end
+
+ def project_rank_key
+ "v2-project-rank"
+ end
+
+ def project_rank
+ result = $redis_cache.zscore(project_rank_key, @project_id)
+ result.blank? ? reset_project_rank : result
+ end
+
+ def set_project_rank
+ load_project_common
+ if $redis_cache.zscore(project_rank_key, @project_id).blank?
+ reset_project_rank
+ return
+ else
+ if @visits.present?
+ $redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id)
+ end
+ if @praises.present?
+ $redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id)
+ end
+ if @forks.present?
+ $redis_cache.zincrby(project_rank_key, @forks.to_i * 5, @project_id)
+ end
+ if @issues.present?
+ $redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id)
+ end
+ if @pullrequests.present?
+ $redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id)
+ end
+ reset_user_project_rank
+ end
+
+ $redis_cache.zscore(project_rank_key, @project_id)
+ end
+
+ def reset_project_rank
+ load_project_common
+ score = @project_common["visits"].to_i * 1 + @project_common["praises"].to_i * 5 + @project_common["forks"].to_i * 5 + @project_common["issues"].to_i * 10 + @project_common["pullrequests"].to_i * 10
+ $redis_cache.zadd(project_rank_key, score, @project_id)
+ reset_user_project_rank
+
+ $redis_cache.zscore(project_rank_key, @project_id)
+ end
+
+ def reset_user_project_rank
+ $redis_cache.zadd("v2-user-project-rank:#{@project_common["owner_id"]}", $redis_cache.zscore(project_rank_key, @project_id), @project_id)
+ end
+
+ def clear_project_rank
+ $redis_cache.sadd('v2-project-rank-deleted', @project_id)
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/user_date_rank_service.rb b/app/services/cache/v2/user_date_rank_service.rb
new file mode 100644
index 000000000..00073a8e8
--- /dev/null
+++ b/app/services/cache/v2/user_date_rank_service.rb
@@ -0,0 +1,119 @@
+class Cache::V2::UserDateRankService < ApplicationService
+ attr_reader :user_id, :rank_date, :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
+
+ def initialize(user_id, rank_date=Date.today, params={})
+ @user_id = user_id
+ @rank_date = rank_date
+ @follow_count = params[:follow_count]
+ @fork_count = params[:fork_count]
+ @issue_count = params[:issue_count]
+ @project_count = params[:project_count]
+ @project_language_count_key = params[:project_language_count_key]
+ @project_language_count = params[:project_language_count]
+ @project_praise_count = params[:project_praise_count]
+ @project_watcher_count = params[:project_watcher_count]
+ @pullrequest_count = params[:pullrequest_count]
+ end
+
+ def read_rank
+ user_rank
+ end
+
+ def read_statistic
+ user_statistic
+ end
+
+ def call
+ set_user_rank
+ end
+
+ private
+ def user_rank_key
+ "v2-user-rank-#{@rank_date.to_s}"
+ end
+
+ def user_date_statistic_key
+ "v2-user-statistic:#{@user_id}-#{@rank_date.to_s}"
+ end
+
+ def user_rank
+ $redis_cache.zscore(user_rank_key, @user_id)
+ end
+
+ def user_statistic
+ $redis_cache.hgetall(user_date_statistic_key)
+ end
+
+ def set_user_statistic
+ if @follow_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "follow-count", @follow_count.to_i)
+ end
+ if @fork_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "fork-count", @fork_count.to_i)
+ end
+ if @issue_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "issue-count", @issue_count.to_i)
+ end
+ if @project_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "project-count", @project_count.to_i)
+ end
+ if project_language_count_key.present? && project_language_count.present?
+ if $redis_cache.hget(user_date_statistic_key, "project-language").nil?
+ result = {}
+ result[@project_language_count_key] = project_language_count.to_i
+ result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
+ $redis_cache.hset(user_date_statistic_key, "project-language", result.to_json)
+ else
+ result = JSON.parse($redis_cache.hget(user_date_statistic_key, "project-language"))
+ result[@project_language_count_key] ||= 0
+ result[@project_language_count_key] += project_language_count.to_i
+ result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
+ $redis_cache.hset(user_date_statistic_key, "project-language", result.to_json)
+ end
+ end
+ if @project_praise_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "project-praise-count", @project_praise_count.to_i)
+ end
+ if @project_watcher_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "project-watcher-count", @project_watcher_count.to_i)
+ end
+ if @pullrequest_count.present?
+ $redis_cache.hincrby(user_date_statistic_key, "pullrequest-count", @pullrequest_count.to_i)
+ end
+
+ $redis_cache.hgetall(user_date_statistic_key)
+ end
+
+ def set_user_rank
+ set_user_statistic
+ follow_count = $redis_cache.hget(user_date_statistic_key, "follow-count") || 0
+ pullrequest_count = $redis_cache.hget(user_date_statistic_key, "pullrequest-count") || 0
+ issues_count = $redis_cache.hget(user_date_statistic_key, "issue-count") || 0
+ project_count = $redis_cache.hget(user_date_statistic_key, "project-count") || 0
+ fork_count = $redis_cache.hget(user_date_statistic_key, "fork-count") || 0
+ project_watchers_count = $redis_cache.hget(user_date_statistic_key, "project-watcher-count") || 0
+ project_praises_count = $redis_cache.hget(user_date_statistic_key, "project-praise-count") || 0
+ project_language = $redis_cache.hget(user_date_statistic_key, "project-language")
+ project_languages_count = project_language.nil? || project_language == "{}" ? 0 : JSON.parse(project_language).length
+ # 影响力
+ influence = (60.0 + follow_count.to_i / (follow_count.to_i + 20.0) * 40.0).to_i
+
+ # 贡献度
+ contribution = (60.0 + pullrequest_count.to_i / (pullrequest_count.to_i + 20.0) * 40.0).to_i
+
+ # 活跃度
+ activity = (60.0 + issues_count.to_i / (issues_count.to_i + 80.0) * 40.0).to_i
+
+ # 项目经验
+ experience = 10 * project_count.to_i + 5 * fork_count.to_i + project_watchers_count.to_i + project_praises_count.to_i
+ experience = (60.0 + experience / (experience + 100.0) * 40.0).to_i
+ # 语言能力
+ language = (60.0 + project_languages_count.to_i / (project_languages_count.to_i + 5.0) * 40.0).to_i
+
+ score = influence+ contribution + activity + experience + language
+ $redis_cache.zrem(user_rank_key, @user_id)
+ $redis_cache.zadd(user_rank_key, score-300, @user_id) if score > 300
+
+ $redis_cache.zscore(user_rank_key, @user_id)
+ end
+end
\ No newline at end of file
diff --git a/app/services/cache/v2/user_statistic_service.rb b/app/services/cache/v2/user_statistic_service.rb
new file mode 100644
index 000000000..b82797d84
--- /dev/null
+++ b/app/services/cache/v2/user_statistic_service.rb
@@ -0,0 +1,202 @@
+class Cache::V2::UserStatisticService < ApplicationService
+ attr_reader :user_id, :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
+
+ def initialize(user_id, params={})
+ @user_id = user_id
+ @follow_count = params[:follow_count]
+ @fork_count = params[:fork_count]
+ @issue_count = params[:issue_count]
+ @project_count = params[:project_count]
+ @project_language_count_key = params[:project_language_count_key]
+ @project_language_count = params[:project_language_count]
+ @project_praise_count = params[:project_praise_count]
+ @project_watcher_count = params[:project_watcher_count]
+ @pullrequest_count = params[:pullrequest_count]
+ Cache::V2::OwnerCommonService.new(user_id).read
+ end
+
+ def read
+ user_statistic
+ end
+
+ def call
+ set_user_statistic
+ end
+
+ def reset
+ reset_user_statistic
+ end
+
+ private
+
+ def user_statistic_key
+ "v2-user-statistic:#{@user_id}"
+ end
+
+ def follow_count_key
+ "follow-count"
+ end
+
+ def fork_count_key
+ "fork-count"
+ end
+
+ def issue_count_key
+ "issue-count"
+ end
+
+ def project_count_key
+ "project-count"
+ end
+
+ def project_language_key
+ "project-language"
+ end
+
+ def project_praise_count_key
+ "project-praise-count"
+ end
+
+ def project_watcher_count_key
+ "project-watcher-count"
+ end
+
+ def pullrequest_count_key
+ "pullrequest-count"
+ end
+
+ def user_statistic
+ result = $redis_cache.hgetall(user_statistic_key)
+ result.blank? ? reset_user_statistic : result
+ end
+
+ def set_user_statistic
+ if $redis_cache.hgetall(user_statistic_key).blank?
+ reset_user_statistic
+ return
+ end
+ if @follow_count.present?
+ if $redis_cache.hget(user_statistic_key, follow_count_key).nil?
+ reset_user_follow_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {follow_count: @follow_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, follow_count_key, @follow_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {follow_count: @follow_count})
+ end
+ end
+ if @fork_count.present?
+ if $redis_cache.hget(user_statistic_key, fork_count_key).nil?
+ reset_user_fork_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {fork_count: @fork_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, fork_count_key, @fork_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {fork_count: @fork_count})
+ end
+ end
+ if @issue_count.present?
+ if $redis_cache.hget(user_statistic_key, issue_count_key).nil?
+ reset_user_issue_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {issue_count: @issue_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, issue_count_key, @issue_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {issue_count: @issue_count})
+ end
+ end
+ if @project_count.present?
+ if $redis_cache.hget(user_statistic_key, project_count_key).nil?
+ reset_user_project_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_count: @project_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, project_count_key, @project_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_count: @project_count})
+ end
+ end
+ if @project_language_count_key.present? && project_language_count.present?
+ if $redis_cache.hget(user_statistic_key, project_language_key).nil?
+ reset_user_project_language
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_language_count_key: @project_language_count_key, project_language_count: @project_language_count})
+ else
+ result = JSON.parse($redis_cache.hget(user_statistic_key, project_language_key))
+ result[@project_language_count_key] ||= 0
+ result[@project_language_count_key] += project_language_count.to_i
+ result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
+ $redis_cache.hset(user_statistic_key, project_language_key, result.to_json)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_language_count_key: @project_language_count_key, project_language_count: @project_language_count})
+ end
+ end
+ if @project_praise_count.present?
+ if $redis_cache.hget(user_statistic_key, project_praise_count_key).nil?
+ reset_user_project_praise_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_praise_count: @project_praise_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, project_praise_count_key, @project_praise_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_praise_count: @project_praise_count})
+ end
+ end
+ if @project_watcher_count.present?
+ if $redis_cache.hget(user_statistic_key, project_watcher_count_key).nil?
+ reset_user_project_watcher_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_watcher_count: @project_watcher_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, project_watcher_count_key, @project_watcher_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_watcher_count: @project_watcher_count})
+ end
+ end
+ if @pullrequest_count.present?
+ if $redis_cache.hget(user_statistic_key, pullrequest_count_key).nil?
+ reset_user_pullrequest_count
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {pullrequest_count: @pullrequest_count})
+ else
+ $redis_cache.hincrby(user_statistic_key, pullrequest_count_key, @pullrequest_count)
+ Cache::V2::UserDateRankService.call(@user_id, Date.today, {pullrequest_count: @pullrequest_count})
+ end
+ end
+ $redis_cache.hgetall(user_statistic_key)
+ end
+
+ def reset_user_follow_count
+ $redis_cache.hset(user_statistic_key, follow_count_key, Watcher.where(watchable_type: 'User', watchable_id: @user_id).count)
+ end
+
+ def reset_user_fork_count
+ $redis_cache.hset(user_statistic_key, fork_count_key, ForkUser.joins(:project).where(projects: {user_id: @user_id}).count)
+ end
+
+ def reset_user_issue_count
+ $redis_cache.hset(user_statistic_key, issue_count_key, Issue.where(author_id: @user_id).count)
+ end
+
+ def reset_user_project_count
+ $redis_cache.hset(user_statistic_key, project_count_key, Project.where(user_id: @user_id).count)
+ end
+
+ def reset_user_project_language
+ $redis_cache.hset(user_statistic_key, project_language_key, Project.where(user_id: @user_id).joins(:project_language).group("project_languages.name").count.to_json)
+ end
+
+ def reset_user_project_praise_count
+ $redis_cache.hset(user_statistic_key, project_praise_count_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: Project.where(user_id: @user_id)).count)
+ end
+
+ def reset_user_project_watcher_count
+ $redis_cache.hset(user_statistic_key, project_watcher_count_key, Watcher.where(watchable_type: 'Project', watchable_id: Project.where(user_id: @user_id)).count)
+ end
+
+ def reset_user_pullrequest_count
+ $redis_cache.hset(user_statistic_key, pullrequest_count_key, PullRequest.where(user_id: @user_id).count)
+ end
+
+ def reset_user_statistic
+ $redis_cache.del(user_statistic_key)
+ reset_user_follow_count
+ reset_user_fork_count
+ reset_user_issue_count
+ reset_user_project_count
+ reset_user_project_language
+ reset_user_project_praise_count
+ reset_user_project_watcher_count
+ reset_user_pullrequest_count
+
+ $redis_cache.hgetall(user_statistic_key)
+ end
+end
\ No newline at end of file
diff --git a/app/services/courses_service.rb b/app/services/courses_service.rb
deleted file mode 100644
index 8229c7c32..000000000
--- a/app/services/courses_service.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class CoursesService
-end
\ No newline at end of file
diff --git a/app/services/create_add_department_apply_service.rb b/app/services/create_add_department_apply_service.rb
deleted file mode 100644
index e172b001a..000000000
--- a/app/services/create_add_department_apply_service.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class CreateAddDepartmentApplyService < ApplicationService
- Error = Class.new(StandardError)
-
- attr_reader :user, :params
-
- def initialize(user, params)
- @user = user
- @params = params
- end
-
- def call
- name = params[:name].to_s.strip
- raise Error, '名称不能为空' if name.blank?
-
- school = School.find_by(id: params[:school_id])
- raise Error, '学校/单位不存在' if school.blank?
- raise Error, '部门已存在' if school.departments.exists?(name: name)
-
- department = Department.new
- department.name = name
- department.school = school
-
- ActiveRecord::Base.transaction do
- department.save!
-
- attrs = {
- user_id: user.id, department: department, school: school,
- name: department.name, remarks: params[:remarks], status: 0,
- }
- apply = ApplyAddDepartment.create!(attrs)
-
- unless user.professional_certification?
- user.user_extension.update!(department_id: department.id)
- end
-
- # 向管理员发送通知
- message = AppliedMessage.new(user_id: 1, status: 0, applied_user_id: user.id, viewed: 0,
- applied_id: apply.id, applied_type: 'ApplyAddDepartment', name: department.name)
- message.save(validate: false)
- end
-
- department
- end
-end
diff --git a/app/services/create_add_school_apply_service.rb b/app/services/create_add_school_apply_service.rb
deleted file mode 100644
index 96619c681..000000000
--- a/app/services/create_add_school_apply_service.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class CreateAddSchoolApplyService < ApplicationService
- Error = Class.new(StandardError)
-
- attr_reader :user, :params
-
- def initialize(user, params)
- @user = user
- @params = params
- end
-
- def call
- AddSchoolApplyForm.new(params).validate!
-
- name = params[:name].to_s.strip
- raise Error, '学校/单位已经存在' if name.present? && School.exists?(name: name)
-
- school = School.new
- school.name = name
- school.province = params[:province].to_s.strip
- school.city = params[:city].to_s.strip
- school.address = params[:address].to_s.strip
-
- ActiveRecord::Base.transaction do
- school.save!
-
- school_attrs = school.as_json(only: %i[name province city address])
- ApplyAddSchool.create!(school_attrs.merge(school: school, user_id: user.id, remarks: params[:remarks]))
-
- # 向管理员发送通知
- message = AppliedMessage.new(user_id: 1, status: 0, applied_user_id: user.id, viewed: 0,
- applied_id: school.id, applied_type: 'ApplyAddSchools', name: school.name)
- message.save(validate: false)
- end
-
- school
- end
-end
diff --git a/app/services/duplicate_course_service.rb b/app/services/duplicate_course_service.rb
deleted file mode 100644
index fa57a8901..000000000
--- a/app/services/duplicate_course_service.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-class DuplicateCourseService < ApplicationService
- attr_reader :origin_course, :user, :course
-
- def initialize(origin_course, user)
- @user = user
- @origin_course = origin_course
- end
-
- def call
- ActiveRecord::Base.transaction do
- @course = copy_course!
-
- copy_course_modules!
-
- join_course!
-
- copy_homework_commons!
-
- copy_exercises!
-
- copy_polls!
-
- copy_attachments!
-
- course
- end
- end
-
- private
-
- def copy_course!
- create_attrs = origin_course.as_json(only: %i[name class_period credit course_list_id])
- create_attrs.merge!(tea_id: user.id, school_id: user.school_id, is_public: 0, is_copy: 1)
-
- Course.create!(create_attrs)
- end
-
- def copy_course_modules!
- @second_category_list = {}
- origin_course.course_modules.each do |course_module|
- attrs = course_module.as_json(only: %i[module_type position hidden module_name])
- new_course_module = CourseModule.create!(attrs.merge(course_id: course.id))
- # 复制子目录
- course_module.course_second_categories.each do |second_category|
- category_attr = second_category.as_json(only: %i[category_type name position])
- new_second_category =
- CourseSecondCategory.create!(category_attr.merge(course_id: course.id, course_module_id: new_course_module.id))
- @second_category_list[second_category.id] = new_second_category.id
- end
- end
- end
-
- def join_course!
- CourseMember.create!(course_id: course.id, user_id: user.id, role: 1)
- end
-
- def copy_homework_commons!
- origin_course.homework_commons.where(homework_type: %i[normal group practice]).find_each do |origin_homework|
- homework_attrs = origin_homework.as_json(only: %i[name description homework_type homework_bank_id reference_answer])
-
- course_second_category_id = @second_category_list[origin_homework.course_second_category_id]
-
- homework = HomeworkCommon.create!(homework_attrs.merge(user_id: user.id, course_id: course.id,
- course_second_category_id:course_second_category_id))
-
- origin_homework.attachments.find_each do |origin_attachment|
- attachment = origin_attachment.copy
- attrs = { container: homework, author_id: origin_homework.user_id, copy_from: origin_attachment.id }
- attachment.assign_attributes(attrs)
- attachment.save!
-
- origin_attachment.increment!(:quotes)
- end
-
- homework.create_homework_detail_manual!
-
- if homework.group_homework_type?
- attrs = origin_homework.homework_detail_group.as_json(only: %i[min_num max_num base_on_project])
- homework.create_homework_detail_group!(attrs)
- elsif homework.practice_homework_type?
- HomeworkCommonsShixun.create!(homework_common_id: homework.id, shixun_id: origin_homework.homework_commons_shixun.shixun_id)
- HomeworksService.new.create_shixun_homework_cha_setting(homework, origin_homework.shixuns.first)
- end
-
-
- origin_homework.increment!(:quotes)
- origin_homework.homework_bank.increment!(:quotes) if origin_homework.homework_bank
- end
- end
-
- def copy_exercises!
- origin_course.exercises.find_each do |origin_exercise|
- attrs = origin_exercise.as_json(only: %i[exercise_name exercise_description exercise_bank_id])
- exercise = course.exercises.create!(attrs.merge(user_id: user.id))
-
- origin_exercise.exercise_questions.find_each do |origin_question|
- question_attrs = origin_question.as_json(only: %i[question_title question_type question_number question_score shixun_name shixun_id is_ordered level])
- # question_attrs[:question_type] ||= 1
- question = exercise.exercise_questions.create!(question_attrs)
-
- exercise_choice_map = {}
- origin_question.exercise_choices.each_with_index do |origin_choice, index|
- choice_attrs = { choice_position: index + 1, choice_text: origin_choice.choice_text }
- choice = question.exercise_choices.create!(choice_attrs)
-
- # exercise_choice_map[origin_choice.id] = choice.id 标准答案中存的是choice_position, 直接取原题的exercise_choice_id就行
- end
-
- origin_question.exercise_standard_answers.find_each do |origin_answer|
- question.exercise_standard_answers.create!(
- exercise_choice_id: origin_answer.exercise_choice_id,
- answer_text: origin_answer.answer_text
- )
- end
-
- origin_question.exercise_shixun_challenges.each_with_index do |sc, index|
- question.exercise_shixun_challenges.create!({position: index+1, challenge_id: sc.challenge_id,
- shixun_id: sc.shixun_id, question_score: sc.question_score})
- end
- end
-
- origin_exercise.exercise_bank.increment!(:quotes) if exercise.exercise_bank
- end
- end
-
- def copy_polls!
- origin_course.polls.includes(poll_questions: :poll_answers).find_each do |origin_poll|
- poll_attrs = origin_poll.as_json(only: %i[polls_name polls_description exercise_bank_id])
- poll = course.polls.create!(poll_attrs.merge(user_id: user.id))
-
- origin_poll.poll_questions.each do |origin_question|
- attr_names = %i[question_title question_type is_necessary question_number max_choices min_choices]
- question_attrs = origin_question.as_json(only: attr_names)
- question_attrs[:question_type] ||= 1
-
- question = poll.poll_questions.create!(question_attrs)
-
- origin_question.poll_answers.each_with_index do |origin_answer, index|
- question.poll_answers.create!(answer_position: index + 1, answer_text: origin_answer.answer_text)
- end
- end
-
- origin_poll.exercise_bank.increment!(:quotes) if origin_poll.exercise_bank
- end
- end
-
- def copy_attachments!
- origin_course.attachments.each do |origin_attachment|
- attachment = origin_attachment.copy
- # attachment.tag_list.add(origin_attachment.tag_list) # tag关联
- attachment.container = course
- attachment.created_on = Time.now
- attachment.publish_time = nil
- attachment.author_id = User.current.id
- attachment.copy_from = origin_attachment.copy_from || origin_attachment.id
- attachment.is_publish = 0
- attachment.attachtype ||= 4
- attachment.course_second_category_id = @second_category_list[origin_attachment.course_second_category_id]
-
- attachment.save!
- origin_course.update_quotes(attachment)
- end
- end
-end
\ No newline at end of file
diff --git a/app/services/gitea/accelerator/migrate_service.rb b/app/services/gitea/accelerator/migrate_service.rb
index 26541b48e..86b8b3db1 100644
--- a/app/services/gitea/accelerator/migrate_service.rb
+++ b/app/services/gitea/accelerator/migrate_service.rb
@@ -44,7 +44,7 @@ class Gitea::Accelerator::MigrateService < Gitea::Accelerator::BaseService
clone_addr: params[:clone_addr],
repo_name: params[:repository_name],
auth_username: params[:auth_username],
- auth_password: params[:auth_password],
+ auth_password: Base64.decode64(params[:auth_password]),
mirror: ActiveModel::Type::Boolean.new.cast(params[:is_mirror])
}
end
diff --git a/app/services/gitea/client_service.rb b/app/services/gitea/client_service.rb
index 0ef041997..90843cc98 100644
--- a/app/services/gitea/client_service.rb
+++ b/app/services/gitea/client_service.rb
@@ -82,6 +82,8 @@ class Gitea::ClientService < ApplicationService
req.headers['Content-Type'] = 'application/json'
req.response :logger # 显示日志
req.adapter Faraday.default_adapter
+ req.options.timeout = 100 # open/read timeout in seconds
+ req.options.open_timeout = 10 # connection open timeout in seconds
if token.blank?
req.basic_auth(username, secret)
else
@@ -108,6 +110,7 @@ class Gitea::ClientService < ApplicationService
def full_url(api_rest, action='post')
url = [api_url, api_rest].join('').freeze
url = action === 'get' ? url : URI.escape(url)
+ url = URI.escape(url) unless url.ascii_only?
puts "[gitea] request url: #{url}"
return url
end
@@ -214,6 +217,14 @@ class Gitea::ClientService < ApplicationService
[body, message]
end
+ def json_parse!(body)
+ return nil unless body.present?
+
+ body = JSON.parse(body)
+ body, message = fix_body(body)
+ body
+ end
+
def log_error(status, body)
puts "[gitea] status: #{status}"
puts "[gitea] body: #{body&.force_encoding('UTF-8')}"
diff --git a/app/services/gitea/organization/repository/create_service.rb b/app/services/gitea/organization/repository/create_service.rb
index 060a8ab05..2990f711e 100644
--- a/app/services/gitea/organization/repository/create_service.rb
+++ b/app/services/gitea/organization/repository/create_service.rb
@@ -15,8 +15,8 @@ class Gitea::Organization::Repository::CreateService < Gitea::ClientService
private
def request_params
- create_params = params.merge(readme: "readme")
- Hash.new.merge(token: token, data: create_params)
+ # create_params = params.merge(readme: "readme")
+ Hash.new.merge(token: token, data: params)
end
def url
diff --git a/app/services/gitea/pull_request/close_service.rb b/app/services/gitea/pull_request/close_service.rb
index aed5251b7..3ca062e64 100644
--- a/app/services/gitea/pull_request/close_service.rb
+++ b/app/services/gitea/pull_request/close_service.rb
@@ -8,7 +8,7 @@ class Gitea::PullRequest::CloseService < Gitea::PullRequest::UpdateService
# number: number of pull request
# token: token of gitea user
# eq:
- # Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gpid, pull.base, current_user.gitea_token)
+ # Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gitea_number, pull.base, current_user.gitea_token)
def initialize(owner, repo, number, base,token=nil)
colse_pull_params = Hash.new.merge(base: base, state: 'closed').compact
diff --git a/app/services/gitea/pull_request/files_service.rb b/app/services/gitea/pull_request/files_service.rb
index 9785588e2..a8cb26627 100644
--- a/app/services/gitea/pull_request/files_service.rb
+++ b/app/services/gitea/pull_request/files_service.rb
@@ -24,7 +24,7 @@ class Gitea::PullRequest::FilesService < Gitea::ClientService
def params
Hash.new.merge(token: token)
end
-
+
def url
"/repos/#{owner}/#{repo}/pulls/#{pull_number}/files".freeze
end
diff --git a/app/services/gitea/pull_request/get_service.rb b/app/services/gitea/pull_request/get_service.rb
index 601c669e1..f9a35fdca 100644
--- a/app/services/gitea/pull_request/get_service.rb
+++ b/app/services/gitea/pull_request/get_service.rb
@@ -3,7 +3,7 @@ class Gitea::PullRequest::GetService < Gitea::ClientService
attr_reader :owner, :repo, :number, :token
#eq:
- # Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gpid, user.gitea_token)
+ # Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gitea_number, user.gitea_token)
def initialize(owner, repo, number, token=nil)
@owner = owner
@repo = repo
diff --git a/app/services/gitea/pull_request/open_service.rb b/app/services/gitea/pull_request/open_service.rb
index affdfe112..4d2137f11 100644
--- a/app/services/gitea/pull_request/open_service.rb
+++ b/app/services/gitea/pull_request/open_service.rb
@@ -8,7 +8,7 @@ class Gitea::PullRequest::OpenService < Gitea::PullRequest::UpdateService
# number: number of pull request
# token: token of gitea user
# eq:
- # Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gpid, pr.base, current_user.gitea_token)
+ # Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gitea_number, pr.base, current_user.gitea_token)
def initialize(owner, repo, number, base, token=nil)
open_pull_params = Hash.new.merge(base: base, state: 'open').compact
diff --git a/app/services/gitea/repository/archive_service.rb b/app/services/gitea/repository/archive_service.rb
new file mode 100644
index 000000000..1b5e1e2a3
--- /dev/null
+++ b/app/services/gitea/repository/archive_service.rb
@@ -0,0 +1,40 @@
+class Gitea::Repository::ArchiveService < Gitea::ClientService
+ attr_reader :owner, :repo, :archive, :token
+
+ def initialize(owner, repo, archive, token=nil)
+ @owner = owner
+ @repo = repo
+ @archive = archive
+ @token = token
+ end
+
+ def call
+ response = get(url, params)
+ response_payload(response)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: token)
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/archive/#{archive}".freeze
+ end
+
+ def response_payload(response)
+ status = response.status
+ body = response&.body
+
+ log_error(status, body)
+ status_payload(status, body)
+ end
+
+ def status_payload(status, body)
+ case status
+ when 200 then success
+ when 404 then error("你操作的链接不存在!")
+ else error("系统错误!")
+ end
+ end
+end
diff --git a/app/services/gitea/repository/branches/list_slice_service.rb b/app/services/gitea/repository/branches/list_slice_service.rb
new file mode 100644
index 000000000..6b643831a
--- /dev/null
+++ b/app/services/gitea/repository/branches/list_slice_service.rb
@@ -0,0 +1,22 @@
+class Gitea::Repository::Branches::ListSliceService < Gitea::ClientService
+ attr_reader :user, :repo
+
+ def initialize(user, repo)
+ @user = user
+ @repo = repo
+ end
+
+ def call
+ response = get(url, params)
+ render_200_response(response)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: user.gitea_token)
+ end
+
+ def url
+ "/repos/#{user.login}/#{repo}/branches/branches_slice".freeze
+ end
+end
diff --git a/app/services/gitea/repository/commits/file_list_service.rb b/app/services/gitea/repository/commits/file_list_service.rb
new file mode 100644
index 000000000..b1606a0f3
--- /dev/null
+++ b/app/services/gitea/repository/commits/file_list_service.rb
@@ -0,0 +1,43 @@
+# Get a list of all commits from a repository
+class Gitea::Repository::Commits::FileListService < Gitea::ClientService
+ attr_reader :owner, :repo_name, :filepath, :args
+
+ # sha: SHA or branch to start listing commits from (usually 'master')
+ # ex:
+ # Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
+ # sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
+ def initialize(owner, repo_name, filepath, **args)
+ @owner = owner
+ @repo_name = repo_name
+ @filepath = filepath
+ @args = args
+ end
+
+ def call
+ response = get(url, params)
+ render_result(response)
+ end
+
+ private
+ def params
+ {sha: args[:sha] || 'master', page: args[:page] || PAGINATE_DEFAULT_PAGE, limit: args[:limit] || PAGINATE_DEFAULT_LIMIT, token: args[:token] || "" }
+ end
+
+ def url
+ "/repos/#{owner}/#{repo_name}/file_commits/#{filepath}".freeze
+ end
+
+ def render_result(response)
+ case response.status
+ when 200
+ result = {}
+ headers = response.headers.to_hash
+ body = JSON.parse(response.body)
+ total_count = headers["x-total"]
+ result.merge(total_count: total_count.to_i, body: body)
+ else
+ nil
+ # {status: -1, message: "#{body['message']}"}
+ end
+ end
+end
diff --git a/app/services/gitea/repository/commits/list_slice_service.rb b/app/services/gitea/repository/commits/list_slice_service.rb
new file mode 100644
index 000000000..04f45f55b
--- /dev/null
+++ b/app/services/gitea/repository/commits/list_slice_service.rb
@@ -0,0 +1,42 @@
+# Get a list of all commits from a repository
+class Gitea::Repository::Commits::ListSliceService < Gitea::ClientService
+ attr_reader :owner, :repo_name, :args
+
+ # sha: SHA or branch to start listing commits from (usually 'master')
+ # ex:
+ # Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
+ # sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
+ def initialize(owner, repo_name, **args)
+ @owner = owner
+ @repo_name = repo_name
+ @args = args
+ end
+
+ def call
+ response = get(url, params)
+ render_result(response)
+ end
+
+ private
+ def params
+ { sha: args[:sha] || 'master', page: args[:page] || PAGINATE_DEFAULT_PAGE, limit: args[:limit] || PAGINATE_DEFAULT_LIMIT, token: args[:token] || "" }
+ end
+
+ def url
+ "/repos/#{owner}/#{repo_name}/commits_slice".freeze
+ end
+
+ def render_result(response)
+ case response.status
+ when 200
+ result = {}
+ headers = response.headers.to_hash
+ body = JSON.parse(response.body)
+ total_count = headers["x-total"]
+ result.merge(total_count: total_count.to_i, body: body)
+ else
+ nil
+ # {status: -1, message: "#{body['message']}"}
+ end
+ end
+end
diff --git a/app/services/gitea/repository/create_service.rb b/app/services/gitea/repository/create_service.rb
index 168aaab24..98a283034 100644
--- a/app/services/gitea/repository/create_service.rb
+++ b/app/services/gitea/repository/create_service.rb
@@ -25,8 +25,8 @@ class Gitea::Repository::CreateService < Gitea::ClientService
private
def request_params
- create_params = params.merge(readme: "readme")
- Hash.new.merge(token: token, data: create_params)
+ # create_params = params.merge(readme: "readme")
+ Hash.new.merge(token: token, data: params)
end
def url
diff --git a/app/services/gitea/repository/entries/create_service.rb b/app/services/gitea/repository/entries/create_service.rb
index 9f5abad2a..5e1a4c4b3 100644
--- a/app/services/gitea/repository/entries/create_service.rb
+++ b/app/services/gitea/repository/entries/create_service.rb
@@ -30,8 +30,7 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService
def call
response = post(url, params)
-
- render_201_response(response)
+ response_payload(response)
end
private
@@ -43,4 +42,21 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService
"/repos/#{owner}/#{repo_name}/contents/#{filepath}".freeze
end
+ def response_payload(response)
+ status = response.status
+ body = response&.body
+
+ log_error(status, body)
+ status_payload(status, body)
+ end
+
+ def status_payload(status, body)
+ case status
+ when 201 then success(json_parse!(body))
+ when 403 then error("你没有权限操作!")
+ when 404 then error("你操作的链接不存在!")
+ when 422 then error("#{filepath}文件已存在,不能重复创建!")
+ else error("系统错误!")
+ end
+ end
end
diff --git a/app/services/gitea/repository/get_branch_and_tag_total_num_service.rb b/app/services/gitea/repository/get_branch_and_tag_total_num_service.rb
new file mode 100644
index 000000000..0b8a52467
--- /dev/null
+++ b/app/services/gitea/repository/get_branch_and_tag_total_num_service.rb
@@ -0,0 +1,37 @@
+
+module Gitea
+ module Repository
+ class GetBranchAndTagTotalNumService < Gitea::ClientService
+ attr_reader :owner, :repo, :token
+
+ def initialize(owner, repo, token=nil)
+ @owner = owner
+ @repo = repo
+ @token = token
+ end
+
+ def call
+ response = get(url, params)
+ render_result(response)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: token)
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/branch_tag_count".freeze
+ end
+
+ def render_result(response)
+ case response.status
+ when 200
+ JSON.parse(response.body)
+ else
+ {}
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/gitea/repository/migrate_service.rb b/app/services/gitea/repository/migrate_service.rb
index 508812087..ab60b42f3 100644
--- a/app/services/gitea/repository/migrate_service.rb
+++ b/app/services/gitea/repository/migrate_service.rb
@@ -33,7 +33,7 @@ class Gitea::Repository::MigrateService < Gitea::ClientService
def call
response = post(url, request_params)
- render_201_response(response)
+ render_response(response)
end
private
diff --git a/app/services/gitea/repository/readme/dir_service.rb b/app/services/gitea/repository/readme/dir_service.rb
new file mode 100644
index 000000000..587fb5d55
--- /dev/null
+++ b/app/services/gitea/repository/readme/dir_service.rb
@@ -0,0 +1,34 @@
+class Gitea::Repository::Readme::DirService < Gitea::ClientService
+ attr_reader :owner, :repo, :ref, :dir, :token
+
+ def initialize(owner, repo, dir, ref='', token=nil)
+ @owner = owner
+ @repo = repo
+ @dir = dir
+ @ref = ref
+ @token = token
+ end
+
+ def call
+ response = get(url, params)
+ status, message, body = render_response(response)
+ json_format(status, message, body)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: token, ref: ref)
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/readme/#{dir}".freeze
+ end
+
+ def json_format(status, message, body)
+ case status
+ when 200 then success(body)
+ when 404 then error(message, 404)
+ else error(message, status)
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/repository/update_service.rb b/app/services/gitea/repository/update_service.rb
index 0d27922b8..6c4eff1b3 100644
--- a/app/services/gitea/repository/update_service.rb
+++ b/app/services/gitea/repository/update_service.rb
@@ -19,7 +19,8 @@ class Gitea::Repository::UpdateService < Gitea::ClientService
end
def call
- patch(url, data_params)
+ response = patch(url, data_params)
+ render_200_response(response)
end
private
diff --git a/app/services/gitea/repository/webhooks/create_service.rb b/app/services/gitea/repository/webhooks/create_service.rb
new file mode 100644
index 000000000..33c9a9b0c
--- /dev/null
+++ b/app/services/gitea/repository/webhooks/create_service.rb
@@ -0,0 +1,23 @@
+class Gitea::Repository::Webhooks::CreateService < Gitea::ClientService
+ attr_reader :token, :owner, :repo, :params
+ def initialize(token, owner, repo, params)
+ @token = token
+ @owner = owner
+ @repo = repo
+ @params = params
+ end
+
+ def call
+ response = post(url, request_params)
+ render_response(response)
+ end
+
+ private
+ def request_params
+ Hash.new.merge({token: token, data: params})
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/hooks".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/repository/webhooks/delete_service.rb b/app/services/gitea/repository/webhooks/delete_service.rb
new file mode 100644
index 000000000..997e9006e
--- /dev/null
+++ b/app/services/gitea/repository/webhooks/delete_service.rb
@@ -0,0 +1,24 @@
+class Gitea::Repository::Webhooks::DeleteService < Gitea::ClientService
+ attr_reader :token, :owner, :repo, :id
+
+ def initialize(token, owner, repo, id)
+ @token = token
+ @owner = owner
+ @repo = repo
+ @id = id
+ end
+
+ def call
+ response = delete(url, params)
+ render_response(response)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: token)
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/hooks/#{id}".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/repository/webhooks/tasks_service.rb b/app/services/gitea/repository/webhooks/tasks_service.rb
new file mode 100644
index 000000000..e4c62edb4
--- /dev/null
+++ b/app/services/gitea/repository/webhooks/tasks_service.rb
@@ -0,0 +1,27 @@
+class Gitea::Repository::Webhooks::TasksService < Gitea::ClientService
+ attr_reader :token, :owner, :repo, :webhook_id
+
+ # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master)
+ # repo_name: the name of repository
+ def initialize(token, owner, repo, webhook_id)
+ @token = token
+ @owner = owner
+ @repo = repo
+ @webhook_id = webhook_id
+ end
+
+ def call
+ response = get(url, params)
+ render_response(response)
+ end
+
+ private
+ def params
+ Hash.new.merge(token: user.gitea_token)
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/hooks/#{webhook_id}/hook_tasks".freeze
+ end
+
+end
diff --git a/app/services/gitea/repository/webhooks/test_service.rb b/app/services/gitea/repository/webhooks/test_service.rb
new file mode 100644
index 000000000..7f1837611
--- /dev/null
+++ b/app/services/gitea/repository/webhooks/test_service.rb
@@ -0,0 +1,24 @@
+class Gitea::Repository::Webhooks::TestService < Gitea::ClientService
+ attr_reader :token, :owner, :repo, :webhook_id
+
+ def initialize(token, owner, repo, webhook_id)
+ @token = token
+ @owner = owner
+ @repo = repo
+ @webhook_id = webhook_id
+ end
+
+ def call
+ response = post(url, request_params)
+ render_response(response)
+ end
+
+ private
+ def request_params
+ Hash.new.merge({token: token})
+ end
+
+ def url
+ "/repos/#{owner}/#{repo}/hooks/#{webhook_id}/tests".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/repository/webhooks/update_service.rb b/app/services/gitea/repository/webhooks/update_service.rb
new file mode 100644
index 000000000..6094c6c51
--- /dev/null
+++ b/app/services/gitea/repository/webhooks/update_service.rb
@@ -0,0 +1,24 @@
+class Gitea::Repository::Webhooks::UpdateService < Gitea::ClientService
+ attr_reader :token, :owner, :repo, :id, :params
+ def initialize(token, owner, repo, id, params)
+ @token = token
+ @owner = owner
+ @repo = repo
+ @id = id
+ @params = params
+ end
+
+ def call
+ response = patch(url, data_params)
+ render_response(response)
+ end
+
+ private
+ def url
+ "/repos/#{owner}/#{repo}/hooks/#{id}"
+ end
+
+ def data_params
+ Hash.new.merge(token: token, data: params).compact
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/user/delete_service.rb b/app/services/gitea/user/delete_service.rb
new file mode 100644
index 000000000..5df3cb6b2
--- /dev/null
+++ b/app/services/gitea/user/delete_service.rb
@@ -0,0 +1,31 @@
+class Gitea::User::DeleteService < Gitea::ClientService
+ attr_reader :username
+
+ def initialize(username)
+ @username = username
+ end
+
+ def call
+ response = delete(request_url, params)
+
+ render_status(response)
+ end
+
+ private
+ def token
+ {
+ username: Gitea.gitea_config[:access_key_id],
+ password: Gitea.gitea_config[:access_key_secret]
+ }
+ end
+
+ def request_url
+ "/admin/users/#{username}"
+ end
+
+ def params
+ Hash.new.merge(token: token)
+ end
+
+
+end
diff --git a/app/services/gitea/user/keys/create_service.rb b/app/services/gitea/user/keys/create_service.rb
new file mode 100644
index 000000000..2b720c483
--- /dev/null
+++ b/app/services/gitea/user/keys/create_service.rb
@@ -0,0 +1,21 @@
+class Gitea::User::Keys::CreateService < Gitea::ClientService
+ attr_reader :token, :params
+ def initialize(token, params)
+ @token = token
+ @params = params
+ end
+
+ def call
+ response = post(url, request_params)
+ render_response(response)
+ end
+
+ private
+ def request_params
+ Hash.new.merge({token: token, data: params})
+ end
+
+ def url
+ '/user/keys'.freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/user/keys/delete_service.rb b/app/services/gitea/user/keys/delete_service.rb
new file mode 100644
index 000000000..3ae263e3b
--- /dev/null
+++ b/app/services/gitea/user/keys/delete_service.rb
@@ -0,0 +1,23 @@
+class Gitea::User::Keys::DeleteService < Gitea::ClientService
+ attr_reader :token, :key_id
+
+ def initialize(token, key_id)
+ @token = token
+ @key_id = key_id
+ end
+
+ def call
+ response = delete(url, params)
+ render_response(response)
+ end
+
+ private
+
+ def params
+ Hash.new.merge(token: token)
+ end
+
+ def url
+ "/user/keys/#{key_id}".freeze
+ end
+end
diff --git a/app/services/gitea/user/keys/get_service.rb b/app/services/gitea/user/keys/get_service.rb
new file mode 100644
index 000000000..fbcf1c86e
--- /dev/null
+++ b/app/services/gitea/user/keys/get_service.rb
@@ -0,0 +1,22 @@
+class Gitea::User::Keys::GetService < Gitea::ClientService
+ attr_reader :token, :key_id
+
+ def initialize(token, key_id)
+ @token = token
+ @key_id = key_id
+ end
+
+ def call
+ response = get(url, params)
+ render_response(response)
+ end
+
+ private
+ def params
+ Hash.new.merge({token: token})
+ end
+
+ def url
+ "/user/keys/#{key_id}".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/gitea/user/keys/list_service.rb b/app/services/gitea/user/keys/list_service.rb
new file mode 100644
index 000000000..1ddfde413
--- /dev/null
+++ b/app/services/gitea/user/keys/list_service.rb
@@ -0,0 +1,26 @@
+class Gitea::User::Keys::ListService < Gitea::ClientService
+ attr_reader :token, :page, :limit, :fingerprint
+
+ def initialize(token, page, limit, fingerprint="")
+ @token = token
+ @page = page
+ @limit = limit
+ @fingerprint = fingerprint
+ end
+
+ def call
+ response = get(url, params)
+ render_response(response)
+ end
+
+ private
+
+ def params
+ Hash.new.merge({token: token, fingerprint: fingerprint, page: page, limit: limit})
+ end
+
+ def url
+ '/user/keys'.freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/gitea/versions/get_service.rb b/app/services/gitea/versions/get_service.rb
new file mode 100644
index 000000000..b3c6cf9cc
--- /dev/null
+++ b/app/services/gitea/versions/get_service.rb
@@ -0,0 +1,37 @@
+# Get a list of all commits from a repository
+class Gitea::Versions::GetService < Gitea::ClientService
+ attr_reader :token, :user_name, :repo, :gid, :args
+
+ # sha: SHA or branch to start listing commits from (usually 'master')
+ def initialize(token, user_name, repo, gid, args={})
+ @token = token
+ @user_name = user_name
+ @repo = repo
+ @gid = gid
+ @args = args
+ end
+
+ def call
+ response = get(url, params)
+ render_result(response)
+ end
+
+ private
+ def params
+ args.merge(token: token)
+ end
+
+ def url
+ "/repos/#{@user_name}/#{@repo}/releases/#{@gid}".freeze
+ end
+
+ def render_result(response)
+ body = JSON.parse(response.body)
+ case response.status
+ when 200
+ body
+ else
+ {status: -1, message: "#{body['message']}"}
+ end
+ end
+end
diff --git a/app/services/notice/read/client_service.rb b/app/services/notice/read/client_service.rb
new file mode 100644
index 000000000..95ab8159e
--- /dev/null
+++ b/app/services/notice/read/client_service.rb
@@ -0,0 +1,108 @@
+class Notice::Read::ClientService < ApplicationService
+ attr_reader :url, :params
+
+ def initialize(options={})
+ @url = options[:url]
+ @params = options[:params]
+ end
+
+ def post(url, params={})
+ puts "[notice][read][POST] request params: #{params}"
+ conn.post do |req|
+ req.url = full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def get(url, params={})
+ puts "[notice][read][GET] request params: #{params}"
+ conn.get do |req|
+ req.url full_url(url, 'get')
+ params.each_pair do |key, value|
+ req.params["#{key}"] = value
+ end
+ end
+ end
+
+ def delete(url, params={})
+ puts "[notice][read][DELETE] request params: #{params}"
+ conn.delete do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def patch(url, params={})
+ puts "[notice][read][PATCH] request params: #{params}"
+ conn.patch do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def put(url, params={})
+ puts "[notice][read][PUT] request params: #{params}"
+ conn.put do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def platform
+ Notice.notice_config[:platform]
+ end
+
+ private
+ def conn
+ @client ||= begin
+ Faraday.new(url: domain) do |req|
+ req.request :url_encoded
+ req.headers['Content-Type'] = 'application/json'
+ req.adapter Faraday.default_adapter
+ end
+ end
+
+ @client
+ end
+
+ def base_url
+ Notice.notice_config[:base_url]
+ end
+
+ def domain
+ Notice.notice_config[:read_domain]
+ end
+
+ def api_url
+ [domain, base_url].join('')
+ end
+
+ def full_url(api_rest, action='post')
+ url = [api_url, api_rest].join('').freeze
+ url = action === 'get' ? url : URI.escape(url)
+ url = URI.escape(url) unless url.ascii_only?
+ puts "[notice][read] request url: #{url}"
+ return url
+ end
+
+ def log_error(status, body)
+ puts "[notice][read] status: #{status}"
+ puts "[notice][read] body: #{body}"
+ end
+
+ def render_response(response)
+ status = response.status
+ body = JSON.parse(response&.body)
+
+ log_error(status, body)
+
+ if status == 200
+ if body["code"] == 1
+ return [body["code"], body["message"], body["data"]]
+ else
+ puts "[notice][read][ERROR] code: #{body["code"]}"
+ puts "[notice][read][ERROR] message: #{body["message"]}"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/read/count_service.rb b/app/services/notice/read/count_service.rb
new file mode 100644
index 000000000..fade12278
--- /dev/null
+++ b/app/services/notice/read/count_service.rb
@@ -0,0 +1,25 @@
+class Notice::Read::CountService < Notice::Read::ClientService
+ attr_accessor :receiver, :type
+
+ def initialize(receiver, type=-1)
+ @receiver = receiver
+ @type = type
+ end
+
+ def call
+ result = get(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+ def request_params
+ {
+ receiver: receiver,
+ type: type
+ }.stringify_keys
+ end
+
+ def url
+ "/notification/#{platform}/count".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/read/list_service.rb b/app/services/notice/read/list_service.rb
new file mode 100644
index 000000000..3f6645d77
--- /dev/null
+++ b/app/services/notice/read/list_service.rb
@@ -0,0 +1,32 @@
+class Notice::Read::ListService < Notice::Read::ClientService
+ attr_accessor :receiver, :type, :status, :page, :size
+
+ def initialize(receiver, type=-1, status=2, page=1, size=15)
+ @receiver = receiver
+ @type = type
+ @status = status
+ @page = page
+ @size = size
+ end
+
+ def call
+ result = get(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_params
+ {
+ receiver: receiver,
+ page: page,
+ status: status,
+ size: size,
+ type: type
+ }.stringify_keys
+ end
+
+ def url
+ "/notification/#{platform}/list".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/write/change_status_service.rb b/app/services/notice/write/change_status_service.rb
new file mode 100644
index 000000000..de2c89815
--- /dev/null
+++ b/app/services/notice/write/change_status_service.rb
@@ -0,0 +1,35 @@
+class Notice::Write::ChangeStatusService < Notice::Write::ClientService
+ attr_accessor :notification_ids, :receiver, :type, :status
+
+ def initialize(notification_ids, receiver, type=-1, status=2)
+ @notification_ids = notification_ids
+ @receiver = receiver
+ @type = type
+ @status = status
+ end
+
+ def call
+ result = put(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_notification_ids
+ notification_ids.join(",")
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ notificationIds: request_notification_ids,
+ receiver: receiver,
+ type: type,
+ status: status
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/client_service.rb b/app/services/notice/write/client_service.rb
new file mode 100644
index 000000000..c76691cfb
--- /dev/null
+++ b/app/services/notice/write/client_service.rb
@@ -0,0 +1,108 @@
+class Notice::Write::ClientService < ApplicationService
+ attr_reader :url, :params
+
+ def initialize(options={})
+ @url = options[:url]
+ @params = options[:params]
+ end
+
+ def post(url, params={})
+ puts "[notice][write][POST] request params: #{params}"
+ conn.post do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def get(url, params={})
+ puts "[notice][write][GET] request params: #{params}"
+ conn.get do |req|
+ req.url full_url(url, 'get')
+ params.each_pair do |key, value|
+ req.params["#{key}"] = value
+ end
+ end
+ end
+
+ def delete(url, params={})
+ puts "[notice][write][DELETE] request params: #{params}"
+ conn.delete do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def patch(url, params={})
+ puts "[notice][write][PATCH] request params: #{params}"
+ conn.patch do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def put(url, params={})
+ puts "[notice][write][PUT] request params: #{params}"
+ conn.put do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def platform
+ Notice.notice_config[:platform]
+ end
+
+ private
+ def conn
+ @client ||= begin
+ Faraday.new(url: domain) do |req|
+ req.request :url_encoded
+ req.headers['Content-Type'] = 'application/json'
+ req.adapter Faraday.default_adapter
+ end
+ end
+
+ @client
+ end
+
+ def base_url
+ Notice.notice_config[:base_url]
+ end
+
+ def domain
+ Notice.notice_config[:write_domain]
+ end
+
+ def api_url
+ [domain, base_url].join('')
+ end
+
+ def full_url(api_rest, action='post')
+ url = [api_url, api_rest].join('').freeze
+ url = action === 'get' ? url : URI.escape(url)
+ url = URI.escape(url) unless url.ascii_only?
+ puts "[notice][write] request url: #{url}"
+ return url
+ end
+
+ def log_error(status, body)
+ puts "[notice][write] status: #{status}"
+ puts "[notice][write] body: #{body}"
+ end
+
+ def render_response(response)
+ status = response.status
+ body = JSON.parse(response&.body)
+
+ log_error(status, body)
+
+ if status == 200
+ if body["code"] == 1
+ return [body["code"], body["message"], body["data"]]
+ else
+ puts "[notice][write][ERROR] code: #{body["code"]}"
+ puts "[notice][write][ERROR] message: #{body["message"]}"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/write/create_service.rb b/app/services/notice/write/create_service.rb
new file mode 100644
index 000000000..8dfc88483
--- /dev/null
+++ b/app/services/notice/write/create_service.rb
@@ -0,0 +1,42 @@
+class Notice::Write::CreateService < Notice::Write::ClientService
+ attr_accessor :receivers, :sender, :content, :notification_url, :source, :extra, :type
+
+ def initialize(receivers, content, notification_url, source, extra={}, type=1, sender=-1)
+ @receivers = receivers
+ @sender = sender
+ @content = content
+ @notification_url = notification_url
+ @source = source
+ @extra = extra
+ @type = type
+ end
+
+ def call
+ return nil if request_receivers.blank?
+ result = post(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_receivers
+ receivers.is_a?(Array) ? receivers.join(",") : receivers
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ receivers: request_receivers,
+ sender: sender,
+ content: content,
+ notification_url: notification_url,
+ source: source,
+ extra: extra.to_json.to_s,
+ type: type
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/delete_service.rb b/app/services/notice/write/delete_service.rb
new file mode 100644
index 000000000..f63584819
--- /dev/null
+++ b/app/services/notice/write/delete_service.rb
@@ -0,0 +1,33 @@
+class Notice::Write::DeleteService < Notice::Write::ClientService
+ attr_accessor :notification_ids, :receiver, :type
+
+ def initialize(notification_ids, receiver, type=-1)
+ @notification_ids = notification_ids
+ @receiver = receiver
+ @type = type
+ end
+
+ def call
+ result = delete(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_notification_ids
+ notification_ids.join(",")
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ notificationIds: request_notification_ids,
+ receiver: receiver,
+ type: type
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/email_create_service.rb b/app/services/notice/write/email_create_service.rb
new file mode 100644
index 000000000..86ec2761f
--- /dev/null
+++ b/app/services/notice/write/email_create_service.rb
@@ -0,0 +1,40 @@
+class Notice::Write::EmailCreateService < Notice::Write::ClientService
+ attr_accessor :receivers, :sender, :content, :subject
+
+ def initialize(receivers, subject, content, sender=-1)
+ @receivers = receivers
+ @sender = sender
+ @content = content
+ @subject = subject
+ end
+
+ def call
+ return nil if request_receivers.blank?
+ result = post(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_receivers
+ receivers.is_a?(Array) ? receivers.join(",") : receivers
+ end
+
+ def request_subject
+ "#{subject}"
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ emails: request_receivers,
+ sender: sender,
+ content: content,
+ subject: request_subject
+ }.stringify_keys)
+ end
+
+ def url
+ "/email/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/organizations/teams/create_service.rb b/app/services/organizations/teams/create_service.rb
index c3fc5f599..171732293 100644
--- a/app/services/organizations/teams/create_service.rb
+++ b/app/services/organizations/teams/create_service.rb
@@ -37,7 +37,7 @@ class Organizations::Teams::CreateService < ApplicationService
end
def authorize
- params[:authorize].present? ? params[:authorize] : "common"
+ params[:authorize].present? ? params[:authorize] : "read"
end
def includes_all_project
@@ -54,7 +54,7 @@ class Organizations::Teams::CreateService < ApplicationService
end
def units_params
- %w(admin owner).include?(authorize) ? %w(code issues pulls releases) : params[:unit_types]
+ %w(code issues pulls wiki releases)
end
def create_units
diff --git a/app/services/organizations/teams/update_service.rb b/app/services/organizations/teams/update_service.rb
index b5b273d8a..d77bba9e4 100644
--- a/app/services/organizations/teams/update_service.rb
+++ b/app/services/organizations/teams/update_service.rb
@@ -25,7 +25,7 @@ class Organizations::Teams::UpdateService < ApplicationService
private
def update_params
if team.authorize == "owner"
- update_params = params.slice(:description)
+ update_params = params.slice(:description, :nickname)
else
update_params = params.slice(:name, :nickname, :description, :authorize, :includes_all_project, :can_create_org_project)
end
@@ -33,7 +33,7 @@ class Organizations::Teams::UpdateService < ApplicationService
end
def units_params
- %w(admin owner).include?(team.authorize) ? %w(code issues pulls releases) : params[:unit_types]
+ %w(code issues pulls wiki releases)
end
def update_team(update_params)
diff --git a/app/services/projects/accept_join_service.rb b/app/services/projects/accept_join_service.rb
index 69cb97603..2bbacad69 100644
--- a/app/services/projects/accept_join_service.rb
+++ b/app/services/projects/accept_join_service.rb
@@ -53,6 +53,8 @@ class Projects::AcceptJoinService < ApplicationService
def operate_project_member
Projects::AddMemberInteractor.call(@project.owner, @project, @applied_project.user, permission)
+ SendTemplateMessageJob.perform_later('ProjectJoined', @user.id, @applied_project.user_id, @project.id) if Site.has_notice_menu?
+ SendTemplateMessageJob.perform_later('ProjectMemberJoined', @user.id, @applied_project.user_id, @project.id) if Site.has_notice_menu?
end
def send_apply_message
diff --git a/app/services/projects/apply_join_service.rb b/app/services/projects/apply_join_service.rb
index 677ee20c1..958fd810c 100644
--- a/app/services/projects/apply_join_service.rb
+++ b/app/services/projects/apply_join_service.rb
@@ -65,7 +65,7 @@ class Projects::ApplyJoinService < ApplicationService
owner = project.user
return if owner.phone.blank?
- Educoder::Sms.send(mobile: owner.phone, send_type:'applied_project_info',
+ Gitlink::Sms.send(mobile: owner.phone, send_type:'applied_project_info',
user_name: owner.show_name, name: project.name)
rescue Exception => ex
Rails.logger.error("发送短信失败 => #{ex.message}")
diff --git a/app/services/projects/apply_transfer_service.rb b/app/services/projects/apply_transfer_service.rb
index 28097bed5..98847a91c 100644
--- a/app/services/projects/apply_transfer_service.rb
+++ b/app/services/projects/apply_transfer_service.rb
@@ -24,13 +24,14 @@ class Projects::ApplyTransferService < ApplicationService
raise Error, '仓库标识不正确' if @project.identifier != params[:identifier]
raise Error, '该仓库正在迁移' if @project.is_transfering
raise Error, '新拥有者不存在' unless @owner.present?
+ raise Error, '新拥有者资料不完善' if @owner.is_a?(User) && !@owner.profile_is_completed?
raise Error, '新拥有者已经存在同名仓库!' if Project.where(user_id: @owner.id, identifier: params[:identifier]).present?
raise Error, '未拥有转移权限' unless is_permit_owner
end
def is_permit_owner
return true unless @owner.is_a?(Organization)
- return @owner.is_owner?(@user)
+ return @owner.is_admin?(@user)
end
def create_apply
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index f014b8d7f..72ad8f161 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -8,6 +8,7 @@ class Projects::CreateService < ApplicationService
def call
Rails.logger.info("#############__________project_params______###########{project_params}")
+ raise Error, "user_id不正确." unless authroize_user_id_success
@project = Project.new(project_params)
ActiveRecord::Base.transaction do
@@ -27,6 +28,10 @@ class Projects::CreateService < ApplicationService
private
+ def authroize_user_id_success
+ (user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?)
+ end
+
def project_params
{
name: params[:name],
@@ -38,7 +43,7 @@ class Projects::CreateService < ApplicationService
ignore_id: params[:ignore_id],
license_id: params[:license_id],
website: params[:website],
- identifier: params[:repository_name] #新增,hs
+ identifier: params[:repository_name]
}
end
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 8ae787c52..84b80f50f 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -15,8 +15,11 @@ class Projects::ForkService < ApplicationService
:rep_identifier, :project_category_id, :project_language_id,
:license_id, :ignore_id, {repository: [:identifier, :hidden]}]
+ result = Gitea::Repository::ForkService.new(@project.owner, @target_owner, @project.identifier, @organization).call
+
clone_project.owner = @target_owner
clone_project.forked_from_project_id = @project.id
+ clone_project.gpid = result['id']
clone_project.save!
new_repository = clone_project.repository
@@ -26,8 +29,6 @@ class Projects::ForkService < ApplicationService
ProjectUnit.init_types(clone_project.id)
- result = Gitea::Repository::ForkService.new(@project.owner, @target_owner, @project.identifier, @organization).call
-
@project.update_column('forked_count', @project&.forked_count.to_i + 1)
new_repository.update_column('url', result['clone_url']) if result
diff --git a/app/services/projects/migrate_service.rb b/app/services/projects/migrate_service.rb
index 7df08f9eb..68ed9f642 100644
--- a/app/services/projects/migrate_service.rb
+++ b/app/services/projects/migrate_service.rb
@@ -8,6 +8,8 @@ class Projects::MigrateService < ApplicationService
end
def call
+ raise Error, "user_id不正确." unless authroize_user_id_success
+
@project = Project.new(project_params)
if @project.save!
ProjectUnit.init_types(@project.id, project.project_type)
@@ -24,6 +26,9 @@ class Projects::MigrateService < ApplicationService
end
private
+ def authroize_user_id_success
+ (user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?)
+ end
def project_params
{
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 0b4f1d998..71c6ff68e 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -23,12 +23,12 @@ class Projects::TransferService < ApplicationService
private
def update_owner
- project.members.find_by(user_id: owner.id).destroy! if owner.is_a?(User)
+ project.members.map{|m| m.destroy! if m.user_id == owner.id || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) }
project.update!(user_id: new_owner.id)
end
def update_repo_url
- project.repository.update!(url: @gitea_repo["clone_url"])
+ project.repository.update!(user_id: new_owner.id, url: @gitea_repo["clone_url"])
end
def update_visit_teams
diff --git a/app/services/pull_requests/close_service.rb b/app/services/pull_requests/close_service.rb
index e0ac19b4e..60a0ab13f 100644
--- a/app/services/pull_requests/close_service.rb
+++ b/app/services/pull_requests/close_service.rb
@@ -23,7 +23,7 @@ class PullRequests::CloseService < ApplicationService
def close_gitea_pull
Gitea::PullRequest::CloseService.call(@owner.login, @repo.identifier,
- @pull.gpid, @pull.base, current_user.gitea_token)
+ @pull.gitea_number, @pull.base, current_user.gitea_token)
end
def update_pull_status!
diff --git a/app/services/pull_requests/merge_service.rb b/app/services/pull_requests/merge_service.rb
index d5fc102ec..463412120 100644
--- a/app/services/pull_requests/merge_service.rb
+++ b/app/services/pull_requests/merge_service.rb
@@ -22,7 +22,7 @@ class PullRequests::MergeService < ApplicationService
def gitea_pull_merge!
result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login,
- @repo.identifier, @pull.gpid, gitea_merge_pull_params)
+ @repo.identifier, @pull.gitea_number, gitea_merge_pull_params)
@status, @message = result
end
diff --git a/app/services/pull_requests/open_service.rb b/app/services/pull_requests/open_service.rb
index 3081e52b5..490071c05 100644
--- a/app/services/pull_requests/open_service.rb
+++ b/app/services/pull_requests/open_service.rb
@@ -23,7 +23,7 @@ class PullRequests::OpenService < ApplicationService
def open_gitea_pull
Gitea::PullRequest::OpenService.call(@owner.login, @repo.identifier,
- @pull.gpid, @pull.base, @current_user.gitea_token)
+ @pull.gitea_number, @pull.base, @current_user.gitea_token)
end
def update_pull_status!
diff --git a/app/services/repositories/detail_service.rb b/app/services/repositories/detail_service.rb
index d8853cf45..b2e7a69e6 100644
--- a/app/services/repositories/detail_service.rb
+++ b/app/services/repositories/detail_service.rb
@@ -8,49 +8,34 @@ class Repositories::DetailService < ApplicationService
end
def call
- if @repo.project.educoder?
- return {
- repo: {},
- release: [],
- branch: [],
- tag: [],
- contributor: [],
- language: {},
- readme: {}
- }
- else
- return {
- repo: repo_suitable,
- release: release_suitable,
- branch: branch_suitable,
- tag: tag_suitable,
- contributor: contributor_suitable,
- language: language_suitable,
- readme: readme_suitable
- }
- end
+ return {
+ repo: repo_suitable,
+ contributor: contributor_suitable,
+ language: language_suitable,
+ branch_tag_total_count: branch_tag_total_count
+ }
+ rescue
+ return {
+ repo: {},
+ release: [],
+ branch: [],
+ branch_type: [],
+ tag: [],
+ contributor: [],
+ language: {},
+ readme: {}
+ }
end
private
+ def branch_tag_total_count
+ Gitea::Repository::GetBranchAndTagTotalNumService.call(@owner.login, @repo.identifier, @owner.gitea_token)
+ end
+
def repo_suitable
Gitea::Repository::GetService.call(@owner, @repo.identifier)
end
- def release_suitable
- releases = Gitea::Versions::ListService.call(@owner.gitea_token, @owner.try(:login), @repo.try(:identifier), {page: 1, limit: 1})
- releases.is_a?(Hash) && releases[:status] == -1 ? [] : releases
- end
-
- def branch_suitable
- branches = Gitea::Repository::Branches::ListService.call(@owner, @repo.identifier)
- branches.is_a?(Hash) && branches[:status] == :error ? [] : branches
- end
-
- def tag_suitable
- tags = Gitea::Repository::Tags::ListService.call(@owner&.gitea_token, @owner.login, @repo.identifier)
- tags.is_a?(Hash) && tags[:status] == -1 ? [] : tags
- end
-
def contributor_suitable
contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repo.identifier)
contributors.is_a?(Hash) && contributors.key?(:status) ? [] : contributors
@@ -60,9 +45,4 @@ class Repositories::DetailService < ApplicationService
result = Gitea::Repository::Languages::ListService.call(@owner.login, @repo.identifier, @user&.gitea_token)
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
end
-
- def readme_suitable
- result = Gitea::Repository::Readme::GetService.call(@owner.login, @repo.identifier, @repo.default_branch, @owner.gitea_token)
- result[:status] === :success ? result[:body] : nil
- end
end
diff --git a/app/services/repositories/migrate_service.rb b/app/services/repositories/migrate_service.rb
index 374115bf0..cccfaed04 100644
--- a/app/services/repositories/migrate_service.rb
+++ b/app/services/repositories/migrate_service.rb
@@ -32,7 +32,7 @@ class Repositories::MigrateService < ApplicationService
private: params[:hidden],
mirror: wrapper_mirror || false,
auth_username: params[:login],
- auth_password: params[:password]
+ auth_password: Base64.decode64(params[:password] || "")
}
end
diff --git a/app/services/reward_experience_service.rb b/app/services/reward_experience_service.rb
deleted file mode 100644
index 70b47d1a3..000000000
--- a/app/services/reward_experience_service.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-class RewardExperienceService
- attr_reader :user, :attrs
-
- def initialize(user, **attrs)
- @user = user
- @attrs = attrs.slice(*%i[container_id container_type score])
- end
-
- def call
- return if user.experiences.exists?(attrs.except(:score))
-
- ActiveRecord::Base.transaction do
- experience = user.experiences.create!(attrs)
-
- user.increment!(:experience, experience.score)
-
- experience
- end
- end
-
- def self.call(user, **attrs)
- new(user, attrs).call
- end
-end
\ No newline at end of file
diff --git a/app/services/users/apply_authentication_service.rb b/app/services/users/apply_authentication_service.rb
index a6b02f431..cd7b931a5 100644
--- a/app/services/users/apply_authentication_service.rb
+++ b/app/services/users/apply_authentication_service.rb
@@ -7,7 +7,7 @@ class Users::ApplyAuthenticationService < ApplicationService
end
def call
- raise Error, '请先完善基本信息' unless user.profile_completed?
+ raise Error, '请先完善基本信息' unless user.profile_is_completed?
Users::ApplyAuthenticationForm.new(params).validate!
# raise Error, '您已经申请过实名认证了' if ApplyUserAuthentication.real_name_auth.processing.exists?(user_id: user.id)
@@ -52,7 +52,7 @@ class Users::ApplyAuthenticationService < ApplicationService
end
def sms_notify_admin
- Educoder::Sms.notify_admin(send_type: 'apply_auth')
+ Gitlink::Sms.notify_admin(send_type: 'apply_auth')
rescue => ex
Util.logger_error(ex)
end
diff --git a/app/services/users/apply_professional_auth_service.rb b/app/services/users/apply_professional_auth_service.rb
index c94481890..2d487f3c3 100644
--- a/app/services/users/apply_professional_auth_service.rb
+++ b/app/services/users/apply_professional_auth_service.rb
@@ -9,7 +9,7 @@ class Users::ApplyProfessionalAuthService < ApplicationService
end
def call
- raise Error, '请先完善基本信息' unless user.profile_completed?
+ raise Error, '请先完善基本信息' unless user.profile_is_completed?
Users::ApplyProfessionalAuthForm.new(params).validate!
# raise Error, '您已经申请过职业认证了' if ApplyUserAuthentication.professional_auth.processing.exists?(user_id: user.id)
@@ -62,7 +62,7 @@ class Users::ApplyProfessionalAuthService < ApplicationService
def sms_notify_admin
sms_cache = Rails.cache.read('apply_pro_certification')
if sms_cache.nil?
- Educoder::Sms.notify_admin(send_type: 'apply_pro_certification')
+ Gitlink::Sms.notify_admin(send_type: 'apply_pro_certification')
Rails.cache.write('apply_pro_certification', 1, expires_in: 5.minutes)
end
rescue => ex
diff --git a/app/services/users/apply_trail_service.rb b/app/services/users/apply_trail_service.rb
index 082a89c9a..d058bb5d0 100644
--- a/app/services/users/apply_trail_service.rb
+++ b/app/services/users/apply_trail_service.rb
@@ -51,7 +51,7 @@ class Users::ApplyTrailService < ApplicationService
end
def send_trial_apply_notify!
- Educoder::Sms.notify_admin(send_type:'user_apply_auth')
+ Gitlink::Sms.notify_admin(send_type:'user_apply_auth')
rescue => ex
Rails.logger.error('发送通知管理员短信失败')
Rails.logger.error(ex.message)
diff --git a/app/services/users/course_service.rb b/app/services/users/course_service.rb
deleted file mode 100644
index 6cc9669cb..000000000
--- a/app/services/users/course_service.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-class Users::CourseService
- include CustomSortable
-
- sort_columns :created_at, :updated_at, default_by: :updated_at, default_direction: :desc
-
- attr_reader :user, :params
-
- def initialize(user, params)
- @user = user
- @params = params
- end
-
- def call
- courses = category_scope_courses.not_deleted.not_excellent
-
- courses = status_filter(courses)
-
- custom_sort(courses, params[:sort_by], params[:sort_direction])
- end
-
- private
-
- def category_scope_courses
- case params[:category]
- when 'study' then
- user.as_student_courses.started
- when 'manage' then
- user.manage_courses
- else
- ids = user.as_student_courses.started.pluck(:id) + user.manage_courses.pluck(:id)
- Course.where(id: ids)
- end
- end
-
- def status_filter(relations)
- # 只有自己查看才有过滤
- return relations unless observed_logged_user?
-
- case params[:status]
- when 'processing' then
- relations.processing
- when 'end' then
- relations.ended
- else
- relations
- end
- end
-
- def observed_logged_user?
- User.current.id == user.id
- end
-end
diff --git a/app/services/users/question_bank_service.rb b/app/services/users/question_bank_service.rb
deleted file mode 100644
index dbaa92e6e..000000000
--- a/app/services/users/question_bank_service.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-class Users::QuestionBankService
- attr_reader :user, :params
-
- def initialize(user, params)
- @user = user
- @params = params
- end
-
- def call
- relations = class_name.classify.constantize.all
-
- relations = category_filter(relations)
- relations = type_filter(relations) if params[:type].present?
-
- relations = relations.where(course_list_id: params[:course_list_id]) if params[:course_list_id].present?
-
- custom_sort(relations, params[:sort_by], params[:sort_direction])
- end
-
- def course_lists
- relation_name = class_name.underscore.pluralize.to_sym
- course_lists = CourseList.joins(relation_name).where.not(relation_name => { id: nil })
-
- category_condition =
- case params[:object_type]
- when 'normal' then { homework_type: 1 }
- when 'group' then { homework_type: 3 }
- when 'exercise' then { container_type: 'Exercise' }
- when 'poll' then { container_type: 'Poll' }
- when 'gtask', 'gtopic' then {}
- else raise ArgumentError
- end
- course_lists = course_lists.where(relation_name => category_condition) if category_condition.present?
-
- type_condition =
- case params[:type]
- when 'personal' then { user_id: user.id }
- when 'publicly' then { is_public: true }
- else {}
- end
- course_lists = course_lists.where(relation_name => type_condition) if type_condition.present?
-
- course_lists.distinct.select(:id, :name)
- end
-
- private
-
- def class_name
- @_class_name ||= begin
- case params[:object_type]
- when 'normal', 'group' then 'HomeworkBank'
- when 'exercise', 'poll' then 'ExerciseBank'
- when 'gtask' then 'GtaskBank'
- when 'gtopic' then 'GtopicBank'
- else raise ArgumentError
- end
- end
- end
-
- def category_filter(relations)
- case params[:object_type]
- when 'normal' then
- relations.where(homework_type: 1)
- when 'group' then
- relations.where(homework_type: 3)
- when 'exercise' then
- relations.where(container_type: 'Exercise')
- when 'poll' then
- relations.where(container_type: 'Poll')
- when 'gtask', 'gtopic' then
- relations.all
- else
- raise ArgumentError
- end
- end
-
- def type_filter(relations)
- case params[:type]
- when 'personal' then relations.where(user_id: user.id)
- when 'publicly' then relations.where(is_public: true)
- else relations
- end
- end
-
- def custom_sort(relations, sort_by, sort_direction)
- case sort_by
- when 'updated_at' then
- relations.order("updated_at #{sort_direction}, id #{sort_direction}")
- when 'name' then
- relations.order("CONVERT(name USING gbk) COLLATE gbk_chinese_ci #{sort_direction}")
- when 'contributor' then
- order_sql = "CONVERT (users.lastname USING gbk) COLLATE gbk_chinese_ci #{sort_direction},"\
- " CONVERT (users.firstname USING gbk) COLLATE gbk_chinese_ci #{sort_direction}"
- relations.joins(:user).where(users: { status: 1 }).order(order_sql)
- else
- relations
- end
- end
-end
diff --git a/app/services/users/register_service.rb b/app/services/users/register_service.rb
new file mode 100644
index 000000000..bb3b3ada1
--- /dev/null
+++ b/app/services/users/register_service.rb
@@ -0,0 +1,58 @@
+class Users::RegisterService < ApplicationService
+ def initialize(params)
+ @login = params[:login]
+ @namespace = params[:namespace]
+ @password = params[:password]
+ @code = params[:code]
+ end
+
+ def call
+ code = strip(@code)
+ login = strip(@login)
+ namespace = strip(@namespace)
+ password = strip(@password)
+
+ Rails.logger.info "Users::RegisterService params: ##### #{params} "
+
+ email, phone =
+ if register_type == 1
+ phone_register(login, code)
+ elsif register_type == 0
+ mail_register(login, code)
+ end
+
+ user = User.new(admin: false, login: namespace, mail: email, phone: phone, type: "User")
+ user.password = password
+ user.activate # 现在因为是验证码,所以在注册的时候就可以激活
+
+ user
+ end
+
+ private
+ # 手机注册
+ def phone_register(login, code)
+ Rails.logger.info("start register by phone: phone is #{login}")
+ email = nil
+ phone = login
+
+ [email, phone]
+ end
+
+ # 邮箱注册
+ def mail_register(login, code)
+ Rails.logger.info("start register by email: email is #{login}")
+ email = login
+ phone = nil
+
+ [email, phone]
+ end
+
+ def register_type
+ phone_mail_type(@login)
+ end
+
+ def phone_mail_type value
+ value =~ /^1\d{10}$/ ? 1 : 0
+ end
+
+end
diff --git a/app/services/users/update_account_service.rb b/app/services/users/update_account_service.rb
index 16824a90e..f8024ff18 100644
--- a/app/services/users/update_account_service.rb
+++ b/app/services/users/update_account_service.rb
@@ -43,7 +43,7 @@ class Users::UpdateAccountService < ApplicationService
end
# 表示资料完整
- user.profile_completed = true
+ # user.profile_completed = true
extension.save!
user.save!
@@ -71,7 +71,7 @@ class Users::UpdateAccountService < ApplicationService
end
def sms_notify_admin name
- Educoder::Sms.send(mobile:'17680641960', send_type:'teacher_register', name: name, user_name:'管理员')
+ Gitlink::Sms.send(mobile:'17680641960', send_type:'teacher_register', name: name, user_name:'管理员')
rescue => ex
Util.logger_error(ex)
end
diff --git a/app/services/weapps/create_course_service.rb b/app/services/weapps/create_course_service.rb
deleted file mode 100644
index 2e5cc5d2f..000000000
--- a/app/services/weapps/create_course_service.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-class Weapps::CreateCourseService < ApplicationService
- attr_reader :course, :params
-
- def initialize(course, params)
- @course = course
- @params = params
- end
-
- def call
- Weapps::CreateCourseForm.new(form_params).validate!
-
- ActiveRecord::Base.transaction do
- course.name = params[:name].to_s.strip
- course.school_id = course.teacher&.school_id
- course.is_public = 0
- course.credit = params[:credit].blank? ? nil : params[:credit]
- course.end_date = params[:end_date].blank? ? nil : params[:end_date]
- course_list = CourseList.find_by(name: params[:course_list_name].to_s.strip)
- if course_list
- course.course_list_id = course_list.id
- else
- new_course_list = CourseList.create!(name: params[:course_list_name].to_s.strip, user_id: course.tea_id, is_admin: 0)
- course.course_list_id = new_course_list.id
- end
- course.is_end = course.end_date.present? && course.end_date < Date.today
-
- course.save!
-
- course.generate_invite_code
- CourseMember.create!(course_id: course.id, user_id: course.tea_id, role: 1)
- course.create_course_modules(params[:course_module_types])
- end
- end
-
- private
-
- def form_params
- params.merge(course: course)
- end
-end
\ No newline at end of file
diff --git a/app/services/weapps/update_course_service.rb b/app/services/weapps/update_course_service.rb
deleted file mode 100644
index b6663bc73..000000000
--- a/app/services/weapps/update_course_service.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class Weapps::UpdateCourseService < ApplicationService
- attr_reader :course, :params
-
- def initialize(course, params)
- @course = course
- @params = params
- end
-
- def call
- Weapps::UpdateCourseForm.new(form_params).validate!
-
- ActiveRecord::Base.transaction do
- course.name = params[:name].to_s.strip
- course.credit = params[:credit].blank? ? nil : params[:credit]
- course.end_date = params[:end_date].blank? ? nil : params[:end_date]
- course_list = CourseList.find_by(name: params[:course_list_name].to_s.strip)
- if course_list
- course.course_list_id = course_list.id
- else
- new_course_list = CourseList.create!(name: params[:course_list_name].to_s.strip, user_id: course.tea_id, is_admin: 0)
- course.course_list_id = new_course_list.id
- end
- course.is_end = course.end_date.present? && course.end_date < Date.today
- course.save!
- end
- course
- end
-
- private
-
- def form_params
- params.merge(course: course)
- end
-end
\ No newline at end of file
diff --git a/app/views/admins/course_lists/index.html.erb b/app/views/admins/course_lists/index.html.erb
deleted file mode 100644
index cd814ed8a..000000000
--- a/app/views/admins/course_lists/index.html.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('课程列表') %>
-<% end %>
-
-
-
-
- <%= render partial: 'admins/course_lists/shared/list', locals: { courses: @course_lists } %>
-
-
-<%= render 'admins/course_lists/shared/merge_course_list_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/course_lists/index.js.erb b/app/views/admins/course_lists/index.js.erb
deleted file mode 100644
index e4bfead7d..000000000
--- a/app/views/admins/course_lists/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$(".course-list-list-container").html("<%= j render partial: 'admins/course_lists/shared/list', locals: { courses: @course_lists }%>");
\ No newline at end of file
diff --git a/app/views/admins/course_lists/shared/_list.html.erb b/app/views/admins/course_lists/shared/_list.html.erb
deleted file mode 100644
index 228385b3e..000000000
--- a/app/views/admins/course_lists/shared/_list.html.erb
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
- 序号
- ID
- 课程名称
- 课堂数
- 创建者
- <%= sort_tag('创建时间', name: 'created_at', path: admins_course_lists_path) %>
- 操作
-
-
- <% if courses.present? %>
- <% courses.each_with_index do |course_list,index| %>
-
- <%= list_index_no(@params_page.to_i, index) %>
- <%= course_list.id %>
- <%= course_list.name %>
- <% course_count = course_list.courses.size %>
- <%= course_count %>
- <%= link_to course_list.user.try(:real_name),"/users/#{course_list.user.try(:login)}",target:'_blank' %>
- <%= format_time course_list.created_at %>
-
- <% if course_count == 0 %>
- <%= delete_link '删除', admins_course_list_path(course_list, element: ".course-list-item-#{course_list.id}"), class: 'delete-department-action' %>
- <% end %>
- <%= javascript_void_link '修改', class: 'action', data: { course_list_id: course_list.id,
- toggle: 'modal', target: '.admin-merge-course-list-modal', url: merge_admins_course_lists_path } %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: courses } %>
\ No newline at end of file
diff --git a/app/views/admins/course_lists/shared/_merge_course_list_modal.html.erb b/app/views/admins/course_lists/shared/_merge_course_list_modal.html.erb
deleted file mode 100644
index 4858f5372..000000000
--- a/app/views/admins/course_lists/shared/_merge_course_list_modal.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/courses/destroy.js.erb b/app/views/admins/courses/destroy.js.erb
deleted file mode 100644
index 811038193..000000000
--- a/app/views/admins/courses/destroy.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-alert("删除成功");
-$(".course-item-<%= @course.id %>").find(".delete-course-action").remove();
\ No newline at end of file
diff --git a/app/views/admins/courses/index.html.erb b/app/views/admins/courses/index.html.erb
deleted file mode 100644
index 84ea98223..000000000
--- a/app/views/admins/courses/index.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('课堂列表') %>
-<% end %>
-
-
-
-
- <%= render partial: 'admins/courses/shared/list', locals: { courses: @courses } %>
-
\ No newline at end of file
diff --git a/app/views/admins/courses/index.js.erb b/app/views/admins/courses/index.js.erb
deleted file mode 100644
index 7073c2a81..000000000
--- a/app/views/admins/courses/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.course-list-container').html("<%= j( render partial: 'admins/courses/shared/list', locals: { courses: @courses } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/courses/index.xlsx.axlsx b/app/views/admins/courses/index.xlsx.axlsx
deleted file mode 100644
index 7cab54482..000000000
--- a/app/views/admins/courses/index.xlsx.axlsx
+++ /dev/null
@@ -1,29 +0,0 @@
-wb = xlsx_package.workbook
-
-wb.styles do |s|
- blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 25,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center}
- wb.add_worksheet(name: "课堂列表") do |sheet|
- sheet.add_row %w(ID 课堂名称 成员 资源 普通作业 分组作业 实训作业 试卷 评测次数 私有 状态 单位 创建者 创建时间 动态时间), :height => 25,:style => blue_cell
-
- @courses.each do |course|
- data = [
- course.id,
- course.name,
- course.course_members_count,
- get_attachment_count(course, 0),
- course.course_homework_count(1),
- course.course_homework_count(3),
- course.course_homework_count(4),
- course.exercises_count,
- course.evaluate_count,
- course.is_public == 1 ? "--" : "√",
- course.is_end ? "已结束" : "正在进行",
- course.school&.name,
- course.teacher&.real_name,
- course.created_at&.strftime('%Y-%m-%d %H:%M'),
- course.max_activity_time ? course.max_activity_time&.strftime('%Y-%m-%d %H:%M') : "--"
- ]
- sheet.add_row(data)
- end
- end
-end
diff --git a/app/views/admins/courses/shared/_import_course_member_modal.html.erb b/app/views/admins/courses/shared/_import_course_member_modal.html.erb
deleted file mode 100644
index d52a60b09..000000000
--- a/app/views/admins/courses/shared/_import_course_member_modal.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/courses/shared/_list.html.erb b/app/views/admins/courses/shared/_list.html.erb
deleted file mode 100644
index 4105c8153..000000000
--- a/app/views/admins/courses/shared/_list.html.erb
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- 序号
- ID
- 课堂名称
- 成员
- 资源
- 普通作业
- 分组作业
- 实训作业
- 试卷
- 评测次数
- 私有
- 状态
- 单位
- 创建者
- <%= sort_tag('创建时间', name: 'created_at', path: admins_courses_path) %>
- 首页
- 邮件通知
- 操作
-
-
-
- <% if courses.present? %>
- <% courses.each_with_index do |course, index| %>
-
- <%= render partial: 'admins/courses/shared/td', locals: {course: course, no: index} %>
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: courses } %>
\ No newline at end of file
diff --git a/app/views/admins/courses/shared/_td.html.erb b/app/views/admins/courses/shared/_td.html.erb
deleted file mode 100644
index 51cc4b199..000000000
--- a/app/views/admins/courses/shared/_td.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-<%= list_index_no((params[:page] || 1).to_i, no) %>
-<%= course.id %>
-
- <%= link_to(course.name, "/courses/#{course.id}", target: '_blank') %>
-
-<%= course.course_members_count %>
-<%= get_attachment_count(course, 0) %>
-<%= course.course_homework_count(1) %>
-<%= course.course_homework_count(3) %>
-<%= course.course_homework_count(4) %>
-<%= course.exercises_count %>
-<%= course.evaluate_count %>
-<%= course.is_public == 1 ? "--" : "√" %>
-<%= course.is_end ? "已结束" : "正在进行" %>
-<%= course.school&.name %>
-<%= course.teacher&.real_name %>
-<%= course.created_at&.strftime('%Y-%m-%d %H:%M') %>
-
- <%= check_box_tag :homepage_show,!course.homepage_show,course.homepage_show,remote:true,data:{id:course.id},class:"course-setting-form" %>
-
-
- <%= check_box_tag :email_notify,!course.email_notify,course.email_notify,remote:true,data:{id:course.id},class:"course-setting-form" %>
-
-
- <% if course.is_delete == 0 %>
- <%= delete_link '删除', admins_course_path(course, element: ".course-item-#{course.id}"), class: 'delete-course-action' %>
- <% end %>
-
\ No newline at end of file
diff --git a/app/views/admins/courses/update.js.erb b/app/views/admins/courses/update.js.erb
deleted file mode 100644
index 983ac22f0..000000000
--- a/app/views/admins/courses/update.js.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-var index = $("#course-item-<%= @course.id %>").children(":first").html();
-$("#course-item-<%= @course.id %>").html("<%= j render partial: "admins/courses/shared/td",locals: {course: @course, no: 1} %>");
-$("#course-item-<%= @course.id %>").children(":first").html(index);
\ No newline at end of file
diff --git a/app/views/admins/customers/index.html.erb b/app/views/admins/customers/index.html.erb
deleted file mode 100644
index b93a5c1e8..000000000
--- a/app/views/admins/customers/index.html.erb
+++ /dev/null
@@ -1,19 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('合作伙伴', admins_partners_path) %>
- <% add_admin_breadcrumb(current_partner.school&.name || current_partner.name) %>
-<% end %>
-
-
- <%= form_tag(admins_partner_customers_path(current_partner), method: :get, class: 'form-inline search-form', remote: true) do %>
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-md-4 ml-3', placeholder: '客户名称检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
- <% end %>
-
- <%= javascript_void_link('添加', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-select-school-modal' }) %>
-
-
-
- <%= render 'admins/customers/shared/list', customers: @customers %>
-
-
-<%= render partial: 'admins/shared/modal/select_school_modal', locals: { title: '添加客户', multiple: true, url: admins_partner_customers_path(current_partner) } %>
\ No newline at end of file
diff --git a/app/views/admins/customers/index.js.erb b/app/views/admins/customers/index.js.erb
deleted file mode 100644
index 8fa2e205d..000000000
--- a/app/views/admins/customers/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.customer-list-container').html("<%= j(render partial: 'admins/customers/shared/list', locals: { customers: @customers }) %>");
\ No newline at end of file
diff --git a/app/views/admins/customers/shared/_list.html.erb b/app/views/admins/customers/shared/_list.html.erb
deleted file mode 100644
index 6f84db4e5..000000000
--- a/app/views/admins/customers/shared/_list.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- 序号
- 客户名称
- <%= sort_tag('添加时间', name: 'created_at', path: admins_partner_customers_path(current_partner)) %>
- 操作
-
-
-
- <% if customers.present? %>
- <% customers.each_with_index do |customer, index| %>
-
- <%= list_index_no((params[:page] || 1).to_i, index) %>
- <%= customer.school&.name %>
- <%= customer.created_at&.strftime('%Y-%m-%d %H:%M') %>
-
- <%= delete_link '删除', admins_partner_customer_path(current_partner, customer, element: ".customer-item-#{customer.id}"), class: 'delete-customer-action' %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: customers } %>
\ No newline at end of file
diff --git a/app/views/admins/daily_school_statistics/export.xlsx.axlsx b/app/views/admins/daily_school_statistics/export.xlsx.axlsx
deleted file mode 100644
index 1757a8fe2..000000000
--- a/app/views/admins/daily_school_statistics/export.xlsx.axlsx
+++ /dev/null
@@ -1,13 +0,0 @@
-wb = xlsx_package.workbook
-wb.add_worksheet(name: '统计总表') do |sheet|
- sheet.add_row %w(ID 单位名称 教师总人数 学生总人数 课堂总数 正在进行课堂数 总实训数 实训评测总数 实训作业总数 其它作业总数 动态时间)
-
- @schools.each do |school|
- sheet.add_row([
- school[:id].to_s, school[:name].to_s, (school[:teacher_count] || 0).to_s, (school[:student_count] || 0).to_s,
- (school[:course_count] || 0).to_s, (school[:active_course_count] || 0).to_s,
- (school[:shixun_count] || 0).to_s,(school[:shixun_evaluate_count] || 0).to_s, (school[:homework_count] || 0).to_s,
- (school[:other_homework_count] || 0).to_s, format_time(school[:nearly_course_time])
- ])
- end
-end
\ No newline at end of file
diff --git a/app/views/admins/daily_school_statistics/index.html.erb b/app/views/admins/daily_school_statistics/index.html.erb
deleted file mode 100644
index c3eb43691..000000000
--- a/app/views/admins/daily_school_statistics/index.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('统计总表', admins_daily_school_statistics_path) %>
-<% end %>
-
-
- <%= form_tag(admins_daily_school_statistics_path, method: :get, class: 'form-inline search-form', remote: true) do %>
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/单位名称搜索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
- <% end %>
-
- <%#= link_to '导出Excel', export_admins_daily_school_statistics_path(format: :xlsx), class: 'btn btn-outline-primary export-action' %>
- <%= javascript_void_link '导出Excel', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_daily_school_statistics_path(format: :xlsx) %>
-
-
-
- 统计总计:
- 教师总人数<%= @teacher_total %> 人,
- 学生总人数<%= @student_total %> 人,
- 课堂总数<%= @course_total %> 个,
- 正在进行课堂总数<%= @active_course_total %> 个,
- 实训总数<%= @shixun_total %> 个,
- 实训评测总数<%= @shixun_evaluate_total %> 个,
- 实训作业总数<%= @shixun_homework_total %> 个,
- 其它作业总数<%= @other_homework_total %> 个
-
-
-
- <%= render partial: 'admins/daily_school_statistics/shared/list', locals: { statistics: @statistics } %>
-
\ No newline at end of file
diff --git a/app/views/admins/daily_school_statistics/index.js.erb b/app/views/admins/daily_school_statistics/index.js.erb
deleted file mode 100644
index d3e261f64..000000000
--- a/app/views/admins/daily_school_statistics/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$(".daily-school-statistic-list-container").html("<%= j(render partial: 'admins/daily_school_statistics/shared/list', locals: { statistics: @statistics }) %>")
\ No newline at end of file
diff --git a/app/views/admins/daily_school_statistics/shared/_list.html.erb b/app/views/admins/daily_school_statistics/shared/_list.html.erb
deleted file mode 100644
index 6982891ee..000000000
--- a/app/views/admins/daily_school_statistics/shared/_list.html.erb
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
- 序号
- 单位名称
- <%= sort_tag('教师总数', name: 'teacher_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('学生总数', name: 'student_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('课堂总数', name: 'course_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('正在进行课堂数', name: 'active_course_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('实训总数', name: 'shixun_count', path: admins_daily_school_statistics_path) %>
-
- <%= sort_tag(name: 'shixun_evaluate_count', path: admins_daily_school_statistics_path) do %>
- 实训评测总数
-
- <% end %>
-
- <%= sort_tag('实训作业总数', name: 'homework_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('其它作业总数', name: 'other_homework_count', path: admins_daily_school_statistics_path) %>
- <%= sort_tag('动态时间', name: 'nearly_course_time', path: admins_daily_school_statistics_path) %>
-
-
-
- <% if statistics.present? %>
- <% statistics.each_with_index do |statistic, index| %>
-
- <%= list_index_no(@params_page.to_i, index) %>
-
- <%= link_to statistic[:name], "/colleges/#{statistic[:id]}/statistics",
- target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %>
-
- <%= statistic[:teacher_count].to_i %>
- <%= statistic[:student_count].to_i %>
- <%= statistic[:course_count].to_i %>
- <%= statistic[:active_course_count].to_i %>
- <%= statistic[:shixun_count].to_i %>
- <%= statistic[:shixun_evaluate_count].to_i %>
- <%= statistic[:homework_count].to_i %>
- <%= statistic[:other_homework_count].to_i %>
- <%= statistic[:nearly_course_time]&.strftime('%Y-%m-%d %H:%M') %>
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: statistics } %>
\ No newline at end of file
diff --git a/app/views/admins/department_applies/index.html.erb b/app/views/admins/department_applies/index.html.erb
deleted file mode 100644
index 8a8a41e41..000000000
--- a/app/views/admins/department_applies/index.html.erb
+++ /dev/null
@@ -1,18 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('部门审批') %>
-<% end %>
-
-
- <%= form_tag(admins_department_applies_path(unsafe_params), method: :get, class: 'form-inline search-form mt-3', remote: true) do %>
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '部门名称检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with':"搜索中...") %>
- <%= link_to "清除",admins_department_applies_path(keyword:nil),class:"btn btn-default",remote:true %>
- <% end %>
-
-
-
- <%= render(partial: 'admins/department_applies/shared/list', locals: { applies: @depart_applies }) %>
-
-
-<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>
-<%= render 'admins/departments/shared/merge_department_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/department_applies/index.js.erb b/app/views/admins/department_applies/index.js.erb
deleted file mode 100644
index 8e11b834c..000000000
--- a/app/views/admins/department_applies/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$(".department-applies-list-container").html("<%= j render partial: "admins/department_applies/shared/list",locals: {applies:@depart_applies} %>")
\ No newline at end of file
diff --git a/app/views/admins/department_applies/shared/_list.html.erb b/app/views/admins/department_applies/shared/_list.html.erb
deleted file mode 100644
index 87d5ab66f..000000000
--- a/app/views/admins/department_applies/shared/_list.html.erb
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- 序号
- ID
- 部门名称
- 单位名称
- 创建者
- <%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %>
- 操作
-
-
-
- <% if applies.present? %>
- <% applies.each_with_index do |apply, index| %>
-
- <%= list_index_no((params[:page] || 1).to_i, index) %>
- <%= apply.id %>
- <%= apply.name %>
- <%= apply.school.try(:name) %>
- <%= apply&.user&.real_name %>
- <%= format_time apply.created_at %>
-
- <%= agree_link '批准', agree_admins_department_apply_path(apply, element: ".department-apply-#{apply.id}"), 'data-confirm': '确认批准通过?' %>
- <%= javascript_void_link('删除', class: 'action refuse-action',
- data: {
- toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id, title: "删除原因", type: "delete",
- url: admins_department_apply_path(apply,tip:"unapplied", element: ".department-apply-#{apply.id}")
- }) %>
- <%= javascript_void_link '更改', class: 'action', data: { school_id: apply.school_id, department_id: apply.id,
- toggle: 'modal', target: '.admin-merge-department-modal', url: merge_admins_department_applies_path } %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
\ No newline at end of file
diff --git a/app/views/admins/department_members/create.js.erb b/app/views/admins/department_members/create.js.erb
deleted file mode 100644
index 6bf0a6ac3..000000000
--- a/app/views/admins/department_members/create.js.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-$('.modal.admin-add-department-member-modal').modal('hide');
-$.notify({ message: '操作成功' });
-
-var index = $(".department-item-<%= current_department.id %>").children(":first").html();
-$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department, index: 1 }) %>");
-$(".department-item-<%= current_department.id %>").children(":first").html(index);
\ No newline at end of file
diff --git a/app/views/admins/department_members/destroy.js.erb b/app/views/admins/department_members/destroy.js.erb
deleted file mode 100644
index d3eb3755b..000000000
--- a/app/views/admins/department_members/destroy.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$.notify({ message: '操作成功' });
-$('.department-list-container .department-item-<%= current_department.id %> .member-user-item-<%= @member.user_id %>').remove();
\ No newline at end of file
diff --git a/app/views/admins/departments/edit.js.erb b/app/views/admins/departments/edit.js.erb
deleted file mode 100644
index dc86d3ae0..000000000
--- a/app/views/admins/departments/edit.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$('.admin-modal-container').html("<%= j( render partial: 'admins/departments/shared/edit_department_modal', locals: { department: current_department } ) %>");
-$('.modal.admin-edit-department-modal').modal('show');
\ No newline at end of file
diff --git a/app/views/admins/departments/index.html.erb b/app/views/admins/departments/index.html.erb
deleted file mode 100644
index b1a0fee3e..000000000
--- a/app/views/admins/departments/index.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('部门列表') %>
-<% end %>
-
-
-
-
- <%= render partial: 'admins/departments/shared/list',
- locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count } %>
-
-
-<%= render 'admins/departments/shared/create_department_modal' %>
-<%= render 'admins/departments/shared/add_department_member_modal' %>
-<%= render 'admins/departments/shared/merge_department_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/departments/index.js.erb b/app/views/admins/departments/index.js.erb
deleted file mode 100644
index bd2e4b25d..000000000
--- a/app/views/admins/departments/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.department-list-container').html("<%= j(render partial: 'admins/departments/shared/list', locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count }) %>");
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_add_department_member_modal.html.erb b/app/views/admins/departments/shared/_add_department_member_modal.html.erb
deleted file mode 100644
index 5d2707222..000000000
--- a/app/views/admins/departments/shared/_add_department_member_modal.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_create_department_modal.html.erb b/app/views/admins/departments/shared/_create_department_modal.html.erb
deleted file mode 100644
index ae6605eb8..000000000
--- a/app/views/admins/departments/shared/_create_department_modal.html.erb
+++ /dev/null
@@ -1,35 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_department_item.html.erb b/app/views/admins/departments/shared/_department_item.html.erb
deleted file mode 100644
index 6018686ff..000000000
--- a/app/views/admins/departments/shared/_department_item.html.erb
+++ /dev/null
@@ -1,36 +0,0 @@
-<%= list_index_no((params[:page] || 1).to_i, index) %>
-<% not_list = defined?(:users_count) %>
-
-<%= overflow_hidden_span department.name, width: 150 %>
-<%= overflow_hidden_span department.school.name, width: 150 %>
-
-<% if not_list %>
- <%= department.user_extensions.count %>
- <%= department.user_extensions.joins(:user).where(users: { professional_certification: true }).count %>
-<% else %>
- <%= users_count.fetch(department.id, 0) %>
- <%= professional_auth_count.fetch(department.id, 0) %>
-<% end %>
-
-
- <%= render partial: 'admins/departments/shared/member_users', locals: { department: department } %>
-
-
- <% if department.identifier.present? %>
- <%= link_to department.identifier.to_s, "/colleges/#{department.identifier}/statistics", target: '_blank' %>
- <% else %>
- --
- <% end %>
-
-<%= department.host_count %>
-<%= department.created_at&.strftime('%Y-%m-%d %H:%M') %>
-
- <%= link_to '编辑', edit_admins_department_path(department), remote: true, class: 'action' %>
-
- <%= javascript_void_link '添加管理员', class: 'action', data: { department_id: department.id, toggle: 'modal', target: '.admin-add-department-member-modal' } %>
-
- <%= javascript_void_link '更改', class: 'action', data: { school_id: department.school_id, department_id: department.id,
- toggle: 'modal', target: '.admin-merge-department-modal', url: merge_admins_departments_path } %>
-
- <%= delete_link '删除', admins_department_path(department, element: ".department-item-#{department.id}"), class: 'delete-department-action' %>
-
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_edit_department_modal.html.erb b/app/views/admins/departments/shared/_edit_department_modal.html.erb
deleted file mode 100644
index 38b43bbce..000000000
--- a/app/views/admins/departments/shared/_edit_department_modal.html.erb
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
- <%= simple_form_for([:admins, department], html: { class: 'admin-edit-department-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
- <%= f.input :name, as: :string, label: '名称' %>
- <%= f.input :identifier, as: :string, label: '统计链接' %>
- <%= f.input :host_count, as: :integer, label: '云主机数' %>
-
-
- <% end %>
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_list.html.erb b/app/views/admins/departments/shared/_list.html.erb
deleted file mode 100644
index 09ba2a65f..000000000
--- a/app/views/admins/departments/shared/_list.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- 序号
- 部门名称
- 单位名称
- 用户数
- 已职业认证
- 部门管理员
- 统计链接
- 云主机数
- <%= sort_tag('创建时间', name: 'created_at', path: admins_departments_path) %>
- 操作
-
-
-
- <% if departments.present? %>
- <% departments.each_with_index do |department, index| %>
-
- <%= render partial: 'admins/departments/shared/department_item', locals: {department: department, index: index} %>
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: departments } %>
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_member_users.html.erb b/app/views/admins/departments/shared/_member_users.html.erb
deleted file mode 100644
index 8d4d466db..000000000
--- a/app/views/admins/departments/shared/_member_users.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-
- <% department.member_users.each do |user| %>
-
- <%= link_to user.real_name, "/users/#{user.login}", target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } %>
- <%= link_to(admins_department_department_member_path(department, user_id: user.id),
- method: :delete, remote: true, class: 'ml-1 delete-member-action',
- data: { confirm: '确认删除吗?' }) do %>
-
- <% end %>
-
- <% end %>
-
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_merge_department_modal.html.erb b/app/views/admins/departments/shared/_merge_department_modal.html.erb
deleted file mode 100644
index 5c1ca6892..000000000
--- a/app/views/admins/departments/shared/_merge_department_modal.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/departments/update.js.erb b/app/views/admins/departments/update.js.erb
deleted file mode 100644
index d20ca9524..000000000
--- a/app/views/admins/departments/update.js.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-$('.modal.admin-edit-department-modal').modal('hide');
-$.notify({ message: '操作成功' });
-
-var index = $(".department-item-<%= current_department.id %>").children(":first").html();
-$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: {department: current_department, index: 1}) %>");
-$(".department-item-<%= current_department.id %>").children(":first").html(index);
\ No newline at end of file
diff --git a/app/views/admins/disciplines/adjust_position.js.erb b/app/views/admins/disciplines/adjust_position.js.erb
deleted file mode 100644
index a0928056e..000000000
--- a/app/views/admins/disciplines/adjust_position.js.erb
+++ /dev/null
@@ -1,5 +0,0 @@
-<% if @message.present? %>
-$.notify({ message: "<%= @message %>" });
-<% else %>
-$(".discipline-list-container").html("<%= j(render :partial => 'admins/disciplines/shared/list') %>");
-<% end %>
\ No newline at end of file
diff --git a/app/views/admins/disciplines/destroy.js.erb b/app/views/admins/disciplines/destroy.js.erb
deleted file mode 100644
index ea9aedcd8..000000000
--- a/app/views/admins/disciplines/destroy.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$.notify({ message: '删除成功' });
-$(".discipline-item-<%= @discipline_id %>").remove();
\ No newline at end of file
diff --git a/app/views/admins/disciplines/edit.js.erb b/app/views/admins/disciplines/edit.js.erb
deleted file mode 100644
index 48c5b789f..000000000
--- a/app/views/admins/disciplines/edit.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$('.admin-modal-container').html("<%= j( render partial: 'admins/disciplines/shared/edit_discipline_modal', locals: { discipline: @discipline } ) %>");
-$('.modal.admin-edit-discipline-modal').modal('show');
\ No newline at end of file
diff --git a/app/views/admins/disciplines/index.html.erb b/app/views/admins/disciplines/index.html.erb
deleted file mode 100644
index f4b116b93..000000000
--- a/app/views/admins/disciplines/index.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('课程方向', admins_disciplines_path) %>
-<% end %>
-
-
-
-
- <%= render(partial: 'admins/disciplines/shared/list') %>
-
-
-<%= render 'admins/disciplines/shared/create_discipline_modal' %>
-<%= render partial: 'admins/disciplines/shared/import_discipline_modal' %>
diff --git a/app/views/admins/disciplines/shared/_create_discipline_modal.html.erb b/app/views/admins/disciplines/shared/_create_discipline_modal.html.erb
deleted file mode 100644
index 7eb5d8985..000000000
--- a/app/views/admins/disciplines/shared/_create_discipline_modal.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/disciplines/shared/_edit_discipline_modal.html.erb b/app/views/admins/disciplines/shared/_edit_discipline_modal.html.erb
deleted file mode 100644
index ce511e27c..000000000
--- a/app/views/admins/disciplines/shared/_edit_discipline_modal.html.erb
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
- <%= simple_form_for([:admins, discipline], html: { class: 'admin-edit-discipline-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
- <%= f.input :name, as: :string, label: '名称' %>
-
-
- <% end %>
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/admins/disciplines/shared/_import_discipline_modal.html.erb b/app/views/admins/disciplines/shared/_import_discipline_modal.html.erb
deleted file mode 100644
index de54fd758..000000000
--- a/app/views/admins/disciplines/shared/_import_discipline_modal.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/disciplines/shared/_list.html.erb b/app/views/admins/disciplines/shared/_list.html.erb
deleted file mode 100644
index 38cbe8c9c..000000000
--- a/app/views/admins/disciplines/shared/_list.html.erb
+++ /dev/null
@@ -1,37 +0,0 @@
-<% max_position = @disciplines.pluck(:position).max %>
-
-
-
- 序号
- 课程方向
- 实践课程
- 实训
- 题库
- 操作
-
-
-
- <% if @disciplines.present? %>
- <% @disciplines.each do |discipline| %>
-
- <%= discipline.position %>
-
- <%= link_to discipline.name, admins_sub_disciplines_path(discipline_id: discipline), :title => discipline.name %>
-
- <%= check_box_tag :subject,!discipline.subject,discipline.subject,remote:true,data:{id:discipline.id},class:"discipline-source-form" %>
- <%= check_box_tag :shixun,!discipline.shixun,discipline.shixun,remote:true,data:{id:discipline.id},class:"discipline-source-form" %>
- <%= check_box_tag :question,!discipline.question,discipline.question,remote:true,data:{id:discipline.id},class:"discipline-source-form" %>
-
- <%= javascript_void_link('上移', class: 'move-action', data: { id: discipline.id, opr: "up" }, style: discipline.position == 1 ? 'display:none' : '') %>
- <%= javascript_void_link('下移', class: 'move-action', data: { id: discipline.id, opr: "down" }, style: discipline.position == max_position ? 'display:none' : '') %>
-
- <%= link_to '编辑', edit_admins_discipline_path(discipline), remote: true, class: 'action' %>
- <%= delete_link '删除', admins_discipline_path(discipline, element: ".discipline-item-#{discipline.id}"), class: 'delete-discipline-action' %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/admins/disciplines/update.js.erb b/app/views/admins/disciplines/update.js.erb
deleted file mode 100644
index 0c051e1dd..000000000
--- a/app/views/admins/disciplines/update.js.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-<% if @message.present? %>
-$.notify({ message: "<%= @message %>" });
-<% else %>
-$('.modal.admin-edit-discipline-modal').modal("hide");
-$(".discipline-list-container").html("<%= j(render :partial => 'admins/disciplines/shared/list') %>");
-<% end %>
\ No newline at end of file
diff --git a/app/views/admins/edu_settings/_form.html.erb b/app/views/admins/edu_settings/_form.html.erb
new file mode 100644
index 000000000..cce930f2a
--- /dev/null
+++ b/app/views/admins/edu_settings/_form.html.erb
@@ -0,0 +1,38 @@
+
+
+
+
+ <%= form_for @edu_setting, url: {controller: "edu_settings", action: "#{type}"} do |p| %>
+
+
+
+ 变量名 *
+
+ <%= p.text_field :name, class: "form-control input-lg",required: true%>
+
+
+
+ 变量值 *
+
+ <%= p.text_field :value, class: "form-control input-lg",required: true%>
+
+
+
+ 备注说明
+
+ <%= p.text_area :description, class: "form-control", placeholder: ""%>
+
+
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/edu_settings/_list.html.erb b/app/views/admins/edu_settings/_list.html.erb
new file mode 100644
index 000000000..a37cc9bef
--- /dev/null
+++ b/app/views/admins/edu_settings/_list.html.erb
@@ -0,0 +1,36 @@
+
+
+
+ 序号
+ 变量名
+ 变量值
+ 备注说明
+ <%= sort_tag('创建时间', name: 'created_at', path: admins_edu_settings_path) %>
+ 操作
+
+
+
+ <% if edu_settings.present? %>
+ <% edu_settings.each_with_index do |edu_setting, index| %>
+
+ <%= list_index_no((params[:page] || 1).to_i, index) %>
+
+ <%= edu_setting.name %>
+
+ <%= edu_setting.value %>
+
+ <%= overflow_hidden_span display_text(edu_setting.description), width: 200 %>
+ <%= edu_setting.created_at&.strftime('%Y-%m-%d %H:%M') %>
+
+ <%= link_to "编辑", edit_admins_edu_setting_path(edu_setting), remote: true, class: "action" %>
+ <%= link_to "删除", admins_edu_setting_path(edu_setting), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %>
+
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: edu_settings } %>
\ No newline at end of file
diff --git a/app/views/admins/edu_settings/edit.js.erb b/app/views/admins/edu_settings/edit.js.erb
new file mode 100644
index 000000000..c2e0405f2
--- /dev/null
+++ b/app/views/admins/edu_settings/edit.js.erb
@@ -0,0 +1,2 @@
+$("#edu_setting-modals").html("<%= j render(partial: 'admins/edu_settings/form', locals: {type: 'update'}) %>")
+$(".edu_setting-change-modal").modal('show');
\ No newline at end of file
diff --git a/app/views/admins/edu_settings/index.html.erb b/app/views/admins/edu_settings/index.html.erb
new file mode 100644
index 000000000..d52480bae
--- /dev/null
+++ b/app/views/admins/edu_settings/index.html.erb
@@ -0,0 +1,22 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('全局变量配置') %>
+<% end %>
+
+
+ <%= form_tag(admins_edu_settings_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
+ <%= text_field_tag(:search, params[:search], class: 'form-control col-12 col-md-2 mr-3', placeholder: '关键字检索') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
+
+ <% end %>
+ <%= link_to "新增", new_admins_edu_setting_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
+
+
+
+ 说明:该界面适用于存储全局变量.
+
+
+
+ <%= render partial: 'admins/edu_settings/list', locals: { edu_settings: @edu_settings } %>
+
+
+
diff --git a/app/views/admins/edu_settings/index.js.erb b/app/views/admins/edu_settings/index.js.erb
new file mode 100644
index 000000000..92a4bfeff
--- /dev/null
+++ b/app/views/admins/edu_settings/index.js.erb
@@ -0,0 +1 @@
+$('.edu_settings-list-container').html("<%= j( render partial: 'admins/edu_settings/list', locals: { edu_settings: @edu_settings } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/edu_settings/new.js.erb b/app/views/admins/edu_settings/new.js.erb
new file mode 100644
index 000000000..21abf3895
--- /dev/null
+++ b/app/views/admins/edu_settings/new.js.erb
@@ -0,0 +1,2 @@
+$("#edu_setting-modals").html("<%= j render(partial: 'admins/edu_settings/form', locals: {type: 'create'}) %>")
+$(".edu_setting-change-modal").modal('show');
\ No newline at end of file
diff --git a/app/views/admins/examination_authentications/index.html.erb b/app/views/admins/examination_authentications/index.html.erb
deleted file mode 100644
index c360a7a18..000000000
--- a/app/views/admins/examination_authentications/index.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('试卷审批') %>
-<% end %>
-
-
-
-
- <%= render(partial: 'admins/examination_authentications/shared/list', locals: { applies: @applies }) %>
-
\ No newline at end of file
diff --git a/app/views/admins/examination_authentications/index.js.erb b/app/views/admins/examination_authentications/index.js.erb
deleted file mode 100644
index 361059e73..000000000
--- a/app/views/admins/examination_authentications/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.examination-authentication-list-container').html("<%= j( render partial: 'admins/examination_authentications/shared/list', locals: { applies: @applies } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/examination_authentications/shared/_item_show_modal.html.erb b/app/views/admins/examination_authentications/shared/_item_show_modal.html.erb
deleted file mode 100644
index 9a1c891fe..000000000
--- a/app/views/admins/examination_authentications/shared/_item_show_modal.html.erb
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
题型:<%= item.type_string %>
-
难度:<%= item.difficulty_string %>
-
-
-
-
<%= item.name %>
- <% item.item_choices.each do |choice| %>
-
- <% if item.item_type == "MULTIPLE" %>
- <%= check_box_tag(:choice, true, choice.is_answer, class: 'form-check-input') %>
- <%= choice.choice_text %>
- <% elsif item.item_type == "SINGLE" || item.item_type == "JUDGMENT" %>
- <%= radio_button_tag(:choice, true, choice.is_answer, class: 'form-check-input') %>
- <%= choice.choice_text %>
- <% else %>
- 答案:<%= choice.choice_text %>
- <% end %>
-
- <% end %>
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/admins/examination_authentications/shared/_list.html.erb b/app/views/admins/examination_authentications/shared/_list.html.erb
deleted file mode 100644
index a751a7fa9..000000000
--- a/app/views/admins/examination_authentications/shared/_list.html.erb
+++ /dev/null
@@ -1,54 +0,0 @@
-<% is_processed = params[:status].to_s != 'pending' %>
-
-
-
- 序号
- 头像
- 创建者
- 学校
- 试卷
- 提交时间
- <% if !is_processed %>
- 操作
- <% else %>
- 审批结果
- <% end %>
-
-
-
- <% if applies.present? %>
- <% applies.each_with_index do |apply, index| %>
- <% user = apply.user %>
- <% exam = ExaminationBank.find apply.container_id %>
-
- <%= list_index_no((params[:page] || 1).to_i, index) %>
-
- <%= link_to "/users/#{user.login}", class: 'examination-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
-
- <% end %>
-
- <%= user.real_name %>
- <%= raw [user.school_name.presence, user.department_name.presence].compact.join(' ') %>
-
- <%= link_to exam.name, "/paperlibrary/see/#{exam.id}", target: "_blank" %>
-
-
- <%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %>
-
-
- <% if !is_processed %>
- <%= agree_link '同意', agree_admins_examination_authentication_path(apply, element: ".examination-authentication-#{apply.id}"), 'data-confirm': '确认同意该审批?', 'data-disable-with': "提交中..." %>
- <%= agree_link '拒绝', refuse_admins_examination_authentication_path(apply, element: ".examination-authentication-#{apply.id}"), 'data-confirm': '确认拒绝该审批?', 'data-disable-with': "拒绝中..." %>
- <% else %>
- <%= apply.status_text %>
- <% end %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
\ No newline at end of file
diff --git a/app/views/admins/examination_authentications/show.js.erb b/app/views/admins/examination_authentications/show.js.erb
deleted file mode 100644
index 70e44404f..000000000
--- a/app/views/admins/examination_authentications/show.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$('.admin-modal-container').html("<%= j( render partial: 'admins/item_authentications/shared/item_show_modal', locals: { item: @item } ) %>");
-$('.modal.admin-item-show-modal').modal('show');
\ No newline at end of file
diff --git a/app/views/admins/laboratories/index.html.erb b/app/views/admins/laboratories/index.html.erb
index 397f50cbe..8811f4ab3 100644
--- a/app/views/admins/laboratories/index.html.erb
+++ b/app/views/admins/laboratories/index.html.erb
@@ -4,7 +4,7 @@
<%= form_tag(admins_laboratories_path(unsafe_params), method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-6 col-md-4 ml-3', placeholder: '学校名称/二级域名前缀检索') %>
+ <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-6 col-md-4 ml-3', placeholder: '单位名称/二级域名前缀检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
diff --git a/app/views/admins/laboratories/shared/_laboratory_item.html.erb b/app/views/admins/laboratories/shared/_laboratory_item.html.erb
index a121528e3..b4b4921ee 100644
--- a/app/views/admins/laboratories/shared/_laboratory_item.html.erb
+++ b/app/views/admins/laboratories/shared/_laboratory_item.html.erb
@@ -1,6 +1,6 @@
<% school = laboratory&.school %>
<%= list_index_no((params[:page] || 1).to_i, index) %>
-
<%= school&.name || 'Trustie主站' %>
+
<%= school&.name || '主站' %>
<% if laboratory.identifier %>
<%= link_to laboratory.site, "https://#{laboratory.site}", target: '_blank' %>
@@ -29,40 +29,10 @@
<%= laboratory.created_at.strftime('%Y-%m-%d %H:%M') %>
-
- <% if school.present? && laboratory.id != 1 %>
- <%= check_box_tag :sync_course,!laboratory.sync_course,laboratory.sync_course,remote:true,data:{id:laboratory.id},class:"laboratory-sync-form" %>
- <% end %>
-
-
- <% if school.present? && laboratory.id != 1 %>
- <%= check_box_tag :sync_subject,!laboratory.sync_subject,laboratory.sync_subject,remote:true,data:{id:laboratory.id},class:"laboratory-sync-form" %>
- <% end %>
-
-
- <% if school.present? && laboratory.id != 1 %>
- <%= check_box_tag :sync_shixun,!laboratory.sync_shixun,laboratory.sync_shixun,remote:true,data:{id:laboratory.id},class:"laboratory-sync-form" %>
- <% end %>
-
- <%= link_to '定制', admins_laboratory_laboratory_setting_path(laboratory), class: 'action' %>
+ <%= link_to '设置', admins_laboratory_laboratory_setting_path(laboratory), class: 'action' %>
<% if school.present? && laboratory.id != 1 %>
- <%= javascript_void_link '添加管理员', class: 'action', data: { laboratory_id: laboratory.id, toggle: 'modal', target: '.admin-add-laboratory-user-modal' } %>
- <%= link_to '同步用户', synchronize_user_admins_laboratory_path(laboratory), remote: true, data: { confirm: '确认同步该单位下的所有用户到云上实验室吗?' }, class: 'action' %>
-<% end %>
-
-
- <%= javascript_void_link('更多', class: 'action dropdown-toggle', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false) %>
-
-
+ <%= delete_link '删除', admins_laboratory_path(laboratory, element: ".laboratory-item-#{laboratory.id}"), class: 'action' %>
+ <% end %>
diff --git a/app/views/admins/laboratories/shared/_list.html.erb b/app/views/admins/laboratories/shared/_list.html.erb
index 621ad7a41..0b6466039 100644
--- a/app/views/admins/laboratories/shared/_list.html.erb
+++ b/app/views/admins/laboratories/shared/_list.html.erb
@@ -7,9 +7,6 @@
统计链接
管理员
<%= sort_tag('创建时间', name: 'id', path: admins_laboratories_path) %>
-
同步课堂
-
同步实践课程
-
同步实训
操作
diff --git a/app/views/admins/laboratory_settings/show.html.erb b/app/views/admins/laboratory_settings/show.html.erb
index 67536af24..f30e92b8f 100644
--- a/app/views/admins/laboratory_settings/show.html.erb
+++ b/app/views/admins/laboratory_settings/show.html.erb
@@ -21,7 +21,7 @@
style: 'text-transform:lowercase'%>
<% rails_env = EduSetting.get('rails_env') %>
- <%= rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' %>
+ <%= rails_env && rails_env != 'production' ? ".#{rails_env}.gitlink.org.cn" : '.gitlink.org.cn' %>
<%# if @laboratory.errors && @laboratory.errors.key?(:identifier) %>
@@ -86,7 +86,9 @@
-
-
+
+<%
+=end%>
diff --git a/app/views/admins/laboratory_shixuns/index.html.erb b/app/views/admins/laboratory_shixuns/index.html.erb
deleted file mode 100644
index c91ddc60b..000000000
--- a/app/views/admins/laboratory_shixuns/index.html.erb
+++ /dev/null
@@ -1,45 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('云上实验室', admins_laboratories_path) %>
- <% add_admin_breadcrumb("#{current_laboratory.name} - 实训项目") %>
-<% end %>
-
-
-
- <%= form_tag(admins_laboratory_laboratory_shixuns_path(current_laboratory), method: :get, class: 'form-inline search-form', remote: true) do %>
-
- 状态:
- <% status_options = [['全部', ''], ['编辑中', 0], ['审核中', 1], ['已发布', 2], ['已关闭', 3]] %>
- <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
-
-
-
- 技术平台:
- <%= select_tag(:tag_id, options_for_select(MirrorRepository.pluck(:type_name,:id).unshift(['']), params[:tag_id]), class: 'form-control') %>
-
-
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-12 col-md-2 mr-3', placeholder: '创建者/实训名称检索') %>
-
-
- <%= hidden_field_tag(:homepage, false, id:'') %>
- <%= check_box_tag(:homepage, true, params[:homepage].to_s == 'true', class: 'form-check-input') %>
- 只看首页展示
-
-
-
- <%= hidden_field_tag(:ownership, false, id:'') %>
- <%= check_box_tag(:ownership, true, params[:ownership].to_s == 'true', class: 'form-check-input') %>
- 只看自建
-
-
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
- <%= link_to '清空', admins_laboratory_laboratory_shixuns_path(current_laboratory), class: 'btn btn-default','data-disable-with': '清空中...' %>
- <% end %>
-
- <%= javascript_void_link('添加实训', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-add-laboratory-shixun-modal' }) %>
-
-
-
- <%= render partial: 'admins/laboratory_shixuns/shared/list', locals: { laboratory_shixuns: @laboratory_shixuns } %>
-
-
-<%= render partial: 'admins/laboratory_shixuns/shared/add_laboratory_shixun_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/laboratory_shixuns/index.js.erb b/app/views/admins/laboratory_shixuns/index.js.erb
deleted file mode 100644
index 0a51afa21..000000000
--- a/app/views/admins/laboratory_shixuns/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.laboratory-shixun-list-container').html("<%= j(render partial: 'admins/laboratory_shixuns/shared/list', locals: { laboratory_shixuns: @laboratory_shixuns }) %>");
\ No newline at end of file
diff --git a/app/views/admins/laboratory_shixuns/shared/_add_laboratory_shixun_modal.html.erb b/app/views/admins/laboratory_shixuns/shared/_add_laboratory_shixun_modal.html.erb
deleted file mode 100644
index 56d01d663..000000000
--- a/app/views/admins/laboratory_shixuns/shared/_add_laboratory_shixun_modal.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/laboratory_shixuns/shared/_list.html.erb b/app/views/admins/laboratory_shixuns/shared/_list.html.erb
deleted file mode 100644
index 462486f4b..000000000
--- a/app/views/admins/laboratory_shixuns/shared/_list.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- 序号
- 实训名称
- 技术平台
- 技术体系
- 封面
- 创建者
- 状态
- 执行时间
- 操作
-
-
-
- <% if laboratory_shixuns.present? %>
- <% laboratory_shixuns.each_with_index do |laboratory_shixun, index| %>
-
- <%= render partial: 'admins/laboratory_shixuns/shared/td', locals: { laboratory_shixun: laboratory_shixun, index: index } %>
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: laboratory_shixuns } %>
\ No newline at end of file
diff --git a/app/views/admins/laboratory_shixuns/shared/_td.html.erb b/app/views/admins/laboratory_shixuns/shared/_td.html.erb
deleted file mode 100644
index d987b53b4..000000000
--- a/app/views/admins/laboratory_shixuns/shared/_td.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-<%- shixun = laboratory_shixun.shixun -%>
-
-
<%= list_index_no((params[:page] || 1).to_i, index) %>
-
- <%= link_to "/shixuns/#{shixun.identifier}", target: '_blank' do %>
- <%= shixun.name %>
- 首页
- 自建
- <% end %>
-
-
<%= shixun.shixun_main_name %>
-
- <% shixun.tag_repertoires.each do |tag| %>
- <%= tag.name %>
- <% end %>
-
-
- <% imageExists = Util::FileManage.exists?(shixun) %>
- <% imageUrl = imageExists ? '/' + url_to_avatar(shixun) : '' %>
- <%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image shixun-image-#{shixun.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: imageExists ? '' : 'display:none') %>
-
-
<%= link_to shixun.user&.real_name, "/users/#{shixun.user&.login}", target:'_blank' %>
-
<%= t("shixun.status.#{shixun.status}") %>
-
<%= shixun.excute_time %>
-
- <%= link_to('去修改', admins_shixun_settings_path(id: laboratory_shixun.shixun_id)) %>
- <%= javascript_void_link('首页展示', class: 'action homepage-show-action', data: { id: laboratory_shixun.id }, style: laboratory_shixun.homepage? ? 'display:none' : '') %>
- <%= javascript_void_link('取消首页展示', class: 'action homepage-hide-action', data: { id: laboratory_shixun.id }, style: laboratory_shixun.homepage? ? '' : 'display:none') %>
-
- <% unless laboratory_shixun.ownership? %>
- <%= delete_link '删除', admins_laboratory_laboratory_shixun_path(current_laboratory, laboratory_shixun, element: ".laboratory-shixun-item-#{laboratory_shixun.id}") %>
- <% end %>
-
\ No newline at end of file
diff --git a/app/views/admins/laboratory_subjects/index.html.erb b/app/views/admins/laboratory_subjects/index.html.erb
deleted file mode 100644
index 211bf24f3..000000000
--- a/app/views/admins/laboratory_subjects/index.html.erb
+++ /dev/null
@@ -1,45 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('云上实验室', admins_laboratories_path) %>
- <% add_admin_breadcrumb("#{current_laboratory.name} - 实践课程") %>
-<% end %>
-
-
-
- <%= form_tag(admins_laboratory_laboratory_subjects_path(current_laboratory), method: :get, class: 'form-inline search-form', remote: true) do %>
-
- 状态:
- <% status_options = [['全部', ''], ['编辑中', 0], ['审核中', 1], ['已发布', 2]] %>
- <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
-
-
-
- 单位:
- <%= select_tag :school_id, options_for_select([''], params[:school_id]), class: 'form-control school-select flex-1' %>
-
-
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-12 col-md-2 mr-3', placeholder: '创建者/课程名称检索') %>
-
-
- <%= hidden_field_tag(:homepage, false, id:'') %>
- <%= check_box_tag(:homepage, true, params[:homepage].to_s == 'true', class: 'form-check-input') %>
- 只看首页展示
-
-
-
- <%= hidden_field_tag(:ownership, false, id:'') %>
- <%= check_box_tag(:ownership, true, params[:ownership].to_s == 'true', class: 'form-check-input') %>
- 只看自建
-
-
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
- <%= link_to '清空', admins_laboratory_laboratory_subjects_path(current_laboratory), class: 'btn btn-default','data-disable-with': '清空中...' %>
- <% end %>
-
- <%= javascript_void_link('添加课程', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-add-laboratory-subject-modal' }) %>
-
-
-
- <%= render partial: 'admins/laboratory_subjects/shared/list', locals: { laboratory_subjects: @laboratory_subjects } %>
-
-
-<%= render partial: 'admins/laboratory_subjects/shared/add_laboratory_subject_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/laboratory_subjects/index.js.erb b/app/views/admins/laboratory_subjects/index.js.erb
deleted file mode 100644
index 3ebc1286c..000000000
--- a/app/views/admins/laboratory_subjects/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.laboratory-subject-list-container').html("<%= j(render partial: 'admins/laboratory_subjects/shared/list', locals: { laboratory_subjects: @laboratory_subjects }) %>");
\ No newline at end of file
diff --git a/app/views/admins/laboratory_subjects/shared/_add_laboratory_subject_modal.html.erb b/app/views/admins/laboratory_subjects/shared/_add_laboratory_subject_modal.html.erb
deleted file mode 100644
index 63ab3fdf1..000000000
--- a/app/views/admins/laboratory_subjects/shared/_add_laboratory_subject_modal.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/admins/laboratory_subjects/shared/_list.html.erb b/app/views/admins/laboratory_subjects/shared/_list.html.erb
deleted file mode 100644
index c40d02260..000000000
--- a/app/views/admins/laboratory_subjects/shared/_list.html.erb
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
- 序号
- 课程名称
- 技术体系
- 等级体系
- 封面
- 创建者
- 单位
- 状态
- 操作
-
-
-
- <% if laboratory_subjects.present? %>
- <% laboratory_subjects.each_with_index do |laboratory_subject, index| %>
-
- <%- subject = laboratory_subject.subject -%>
-
- <%= list_index_no((params[:page] || 1).to_i, index) %>
-
- <%= link_to(subject.name, "/paths/#{subject.id}", target: '_blank') %>
- 首页
- 自建
-
- <%= display_text subject.repertoire&.name %>
- <%= display_text subject.subject_level_system&.name %>
-
- <% image_exists = Util::FileManage.exists?(subject) %>
- <%= image_tag(image_exists ? Util::FileManage.source_disk_file_url(subject) : '', height: 40, class: "w-100 preview-image subject-image-#{subject.id}", style: image_exists ? '' : 'display:none') %>
-
- <%= subject.user.real_name %>
- <%= subject.user.school_name %>
- <%= display_subject_status(subject) %>
-
-
- <%= link_to('去修改', admins_subjects_path(id: laboratory_subject.subject_id)) %>
- <%= javascript_void_link('首页展示', class: 'action homepage-show-action', data: { id: laboratory_subject.id }, style: laboratory_subject.homepage? ? 'display:none' : '') %>
- <%= javascript_void_link('取消首页展示', class: 'action homepage-hide-action', data: { id: laboratory_subject.id }, style: laboratory_subject.homepage? ? '' : 'display:none') %>
-
- <% unless laboratory_subject.ownership? %>
- <%= delete_link '删除', admins_laboratory_laboratory_subject_path(current_laboratory, laboratory_subject, element: ".laboratory-subject-item-#{laboratory_subject.id}") %>
- <% end %>
-
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: laboratory_subjects } %>
\ No newline at end of file
diff --git a/app/views/admins/library_applies/index.html.erb b/app/views/admins/library_applies/index.html.erb
deleted file mode 100644
index 9d2ae8e66..000000000
--- a/app/views/admins/library_applies/index.html.erb
+++ /dev/null
@@ -1,32 +0,0 @@
-<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('教学案例发布') %>
-<% end %>
-
-
-
-
- <%= render(partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies }) %>
-
-
-<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>
\ No newline at end of file
diff --git a/app/views/admins/library_applies/index.js.erb b/app/views/admins/library_applies/index.js.erb
deleted file mode 100644
index 6f4c3e712..000000000
--- a/app/views/admins/library_applies/index.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$('.library-applies-list-container').html("<%= j( render partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/library_applies/shared/_list.html.erb b/app/views/admins/library_applies/shared/_list.html.erb
deleted file mode 100644
index fde3d1d1a..000000000
--- a/app/views/admins/library_applies/shared/_list.html.erb
+++ /dev/null
@@ -1,58 +0,0 @@
-<% is_processed = params[:status].to_s != 'pending' %>
-
-
-
-
- 序号
- 头像
- 姓名
- 教学案例
- 案例描述
- 时间
- <% if is_processed %>
- 拒绝原因
- 状态
- <% else %>
- 操作
- <% end %>
-
-
-
- <% if applies.present? %>
- <% applies.each_with_index do |apply, index| %>
- <% user = apply.library.user %>
- <% library = apply.library %>
-
- <%= list_index_no((params[:page] || 1).to_i, index) %>
-
- <%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
-
- <% end %>
-
- <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %>
- <%= link_to library.title, library_path(library), :target => "_blank" %>
- <%= overflow_hidden_span library.content[0..50]%>
- <%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %>
-
- <% if is_processed %>
- <%= overflow_hidden_span apply.reason %>
- <%= t("library_apply.status.#{apply.status}") %>
- <% else %>
-
- <%= agree_link '同意', agree_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
- <%= javascript_void_link('拒绝', class: 'action refuse-action',
- data: {
- toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
- url: refuse_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}")
- }) %>
-
- <% end %>
-
- <% end %>
- <% else %>
- <%= render 'admins/shared/no_data_for_table' %>
- <% end %>
-
-
-
-<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
\ No newline at end of file
diff --git a/app/views/admins/message_templates/_form.html.erb b/app/views/admins/message_templates/_form.html.erb
new file mode 100644
index 000000000..4b2a6c767
--- /dev/null
+++ b/app/views/admins/message_templates/_form.html.erb
@@ -0,0 +1,65 @@
+
+
+
+ <%= form_for @message_template, url: {controller: "message_templates", action: "#{type}"} do |f| %>
+
+
+
+
+
+
+
+ <%= f.submit "确认", class: "btn btn-primary submit-btn" %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/admins/message_templates/_list.html.erb b/app/views/admins/message_templates/_list.html.erb
new file mode 100644
index 000000000..4082735f5
--- /dev/null
+++ b/app/views/admins/message_templates/_list.html.erb
@@ -0,0 +1,39 @@
+
+
+
+ 序号
+ 类型
+ 系统消息模版
+ 邮件模版
+ 通知地址
+ 操作
+
+
+
+ <% if message_templates.present? %>
+ <% message_templates.each_with_index do |message_template_type, index| %>
+ <% message_template = message_template_type.constantize.last%>
+
+ <%= list_index_no((params[:page] || 1).to_i, index) %>
+ <%= message_template.simple_type %>
+
+ <%= message_template.sys_notice.to_s.truncate(200) %>
+
+
+ <%= message_template.email.to_s.truncate(100) %>
+
+
+ <%= message_template.notification_url.to_s.truncate(200) %>
+
+
+ <%= link_to "编辑", edit_admins_message_template_path(message_template),remote: true, class: "action" %>
+
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: message_templates } %>
\ No newline at end of file
diff --git a/app/views/admins/message_templates/edit.js.erb b/app/views/admins/message_templates/edit.js.erb
new file mode 100644
index 000000000..5d797af2f
--- /dev/null
+++ b/app/views/admins/message_templates/edit.js.erb
@@ -0,0 +1,2 @@
+$("#admins-message-templates-content").html("<%= j render partial: 'admins/message_templates/form', locals:{type: 'update'} %>")
+createMDEditor('message-template-email-editor', { height: 500, placeholder: '请输入邮件模版' });
diff --git a/app/views/admins/message_templates/index.html.erb b/app/views/admins/message_templates/index.html.erb
new file mode 100644
index 000000000..54d273332
--- /dev/null
+++ b/app/views/admins/message_templates/index.html.erb
@@ -0,0 +1,12 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('消息模版') %>
+<% end %>
+
+
+ <%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary pull-right", "data-disabled-with":"...初始化数据" %>
+
+
+ <%= render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } %>
+
+
+
diff --git a/app/views/admins/message_templates/index.js.erb b/app/views/admins/message_templates/index.js.erb
new file mode 100644
index 000000000..d8e0fdd26
--- /dev/null
+++ b/app/views/admins/message_templates/index.js.erb
@@ -0,0 +1 @@
+$('.message-templates-list-container').html("<%= j( render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/project_categories/_form_modal.html.erb b/app/views/admins/project_categories/_form_modal.html.erb
index fd20936b6..fc58d3345 100644
--- a/app/views/admins/project_categories/_form_modal.html.erb
+++ b/app/views/admins/project_categories/_form_modal.html.erb
@@ -7,9 +7,33 @@
×
- <%= form_for @project_category, url: {controller: "project_categories", action: "#{type}"} do |p| %>
+ <%= form_for @project_category, url: {controller: "project_categories", action: "#{type}"}, html: { enctype: 'multipart/form-data' } do |p| %>
- <%= p.text_field :name,class: "form-control input-lg",placeholder: "分类名称",required: true, maxlength: 64%>
+
+
+ 分类名称 *
+
+ <%= p.text_field :name,class: "form-control input-lg",placeholder: "分类名称",required: true, maxlength: 64%>
+
+
+
+ 精选等级
+
+ <%= p.number_field :pinned_index,class: "form-control input-lg",placeholder: "精选等级",required: true%>
+
+
+ <% logo_img = @project_category.logo_url %>
+
+
+ <%= file_field_tag(:logo, accept: 'image/png,image/jpg,image/jpeg',style: "display: none", value: params[:logo]) %>
+
+
+
+
logo
+
格式:PNG、JPG
+
尺寸:高度38px以内,宽等比例缩放
+
+