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" + } + ] +} +``` + + +## 创建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" +} +``` + + + +## 删除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" +} +``` + + 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 %> - -
- <%= form_tag(admins_course_lists_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> -
- - <% auto_trial_options = [['创建者姓名', 0], ['课程名称', 1]] %> - <%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %> -
- <%= 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_course_lists_path,class: "btn btn-default",id:"course-lists-clear-search",'data-disable-with': '清除中...' %> - <% 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 @@ - - - - - - - - - - - - <% if courses.present? %> - <% courses.each_with_index do |course_list,index| %> - - - - - <% course_count = course_list.courses.size %> - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号ID课程名称课堂数创建者<%= sort_tag('创建时间', name: 'created_at', path: admins_course_lists_path) %>操作
<%= list_index_no(@params_page.to_i, index) %><%= course_list.id %><%= course_list.name %><%= 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 } %> -
- -<%= 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 %> - -
- <%= form_tag(admins_courses_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> -
- - <% status_options = [['全部', ''], ["正在进行(#{@processed_courses})", 'processing'], ["已结束#{@ended_courses}", 'ended']] %> - <%= 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_show, false, id:'') %> - <%= check_box_tag(:homepage_show, true, params[:homepage_show].to_s == 'true', class: 'form-check-input course-homepage-show') %> - -
- - <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> - - <% 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - <% 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 %> - -
序号ID课堂名称成员资源普通作业分组作业实训作业试卷评测次数私有状态单位创建者<%= sort_tag('创建时间', name: 'created_at', path: admins_courses_path) %>首页邮件通知操作
- -<%= 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 @@ - - - - - - - - - - - <% if customers.present? %> - <% customers.each_with_index do |customer, index| %> - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号客户名称<%= sort_tag('添加时间', name: 'created_at', path: admins_partner_customers_path(current_partner)) %>操作
<%= 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' %> -
- -<%= 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 @@ - - - - - - - - - - - - - - - - - - <% if statistics.present? %> - <% statistics.each_with_index do |statistic, index| %> - - - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号单位名称<%= 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) %>
<%= 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') %>
- -<%= 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 @@ - - - - - - - - - - - - - - <% if applies.present? %> - <% applies.each_with_index do |apply, index| %> - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号ID部门名称单位名称创建者<%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %>操作
<%= 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 } %> -
- -<%= 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 %> - -
- <%= form_tag(admins_departments_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> -
- <%= hidden_field_tag(:with_member, false,id:'') %> - <%= check_box_tag(:with_member, true, params[:with_member].to_s == 'true', class: 'form-check-input') %> - -
- -
- <%= hidden_field_tag(:with_identifier, false,id:'') %> - <%= check_box_tag(:with_identifier, true, params[:with_identifier].to_s == 'true', class: 'form-check-input') %> - -
- - <%= 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': '搜索中...') %> - <% end %> - - <%= javascript_void_link '新建部门', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-department-modal' } %> -
- -
- <%= 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 @@ - \ 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 @@ - - - - - - - - - - - - - - - - - <% 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 %> - -
序号部门名称单位名称用户数已职业认证部门管理员统计链接云主机数<%= sort_tag('创建时间', name: 'created_at', path: admins_departments_path) %>操作
- -<%= 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 %> - -
-
- <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-discipline-modal' } %> -
- <%= javascript_void_link '导入数据', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-import-discipline-modal'} %> -
- -
- <%= 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 @@ - \ 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| %> - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号课程方向实践课程实训题库操作
<%= 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' %> -
\ 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 @@ + \ 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 @@ + + + + + + + + + + + + + <% if edu_settings.present? %> + <% edu_settings.each_with_index do |edu_setting, index| %> + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号变量名变量值备注说明<%= sort_tag('创建时间', name: 'created_at', path: admins_edu_settings_path) %>操作
<%= 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" %> +
+ +<%= 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 %> - -
- - - <%= form_tag(admins_examination_authentications_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %> -
- - <% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %> - <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %> -
- <%= 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': '搜索中...') %> - <% 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 @@ - \ 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 %> - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号头像创建者学校试卷提交时间操作审批结果
<%= 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 %> -
- -<%= 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 @@ -
+ <% +=begin%> +
Banner设置
@@ -140,7 +142,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 -%> - - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号课程名称技术体系等级体系封面创建者单位状态操作
<%= 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 %> -
- -<%= 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 %> - -
- - - <%= form_tag(admins_library_applies_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %> -
- - <% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %> - <%= select_tag(:status, options_for_select(status_options) ,class: 'form-control') %> -
- <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '编号/名称检索') %> - <%= submit_tag('搜索', class: 'btn btn-primary ml-3') %> - <% 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 %> - - - - - - - - - <% if is_processed %> - - - <% else %> - - <% end %> - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号头像姓名教学案例案例描述时间拒绝原因状态操作
<%= 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') %><%= overflow_hidden_span apply.reason %><%= t("library_apply.status.#{apply.status}") %> - <%= 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}") - }) %> -
- -<%= 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 @@ +
+
<%= type == "create" ? "新建" : "编辑" %><%= @message_template.simple_type %>消息模版
+ <%= link_to "返回", admins_message_templates_path, class: "btn btn-default pull-right" %> +
+ +
+ <%= form_for @message_template, url: {controller: "message_templates", action: "#{type}"} do |f| %> + +
+ +
+ <%= f.text_area :sys_notice, class:"form-control", rows: "10", cols: "20",placeholer: "请输入站内信" %> +
+ + + +
+
+ +
+ <%= f.text_field :notification_url, class: "form-control input-lg", maxlength: "60", placeholder: "请输入站内信跳转地址" %> +
+ +
+
+ +
+ <%= f.text_field :email_title, class: "form-control input-lg", maxlength: "60", placeholder: "请输入邮件标题" %> +
+ +
+
+ +
+
+ <%= f.text_area :email, class:"form-control", style: 'display: none;', rows: "10", cols: "20", placeholer: "请输入邮件正文" %> +
+
+
+ +
+ <%= 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%> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号类型系统消息模版邮件模版通知地址操作
<%= 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" %> +
+ +<%= 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| %> + +
+
diff --git a/app/views/admins/projects/shared/_form_modal.html.erb b/app/views/admins/projects/shared/_form_modal.html.erb new file mode 100644 index 000000000..b9796756a --- /dev/null +++ b/app/views/admins/projects/shared/_form_modal.html.erb @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/app/views/admins/projects/shared/_list.html.erb b/app/views/admins/projects/shared/_list.html.erb index fe8d96e9d..c2d300c2d 100644 --- a/app/views/admins/projects/shared/_list.html.erb +++ b/app/views/admins/projects/shared/_list.html.erb @@ -1,19 +1,20 @@ - - - - - + + + + + + + - - + - - - - + + + + @@ -23,13 +24,14 @@ + + - - + + <% end %> <% else %> diff --git a/app/views/admins/reversed_keywords/_form_modal.html.erb b/app/views/admins/reversed_keywords/_form_modal.html.erb new file mode 100644 index 000000000..7dd2f2ba4 --- /dev/null +++ b/app/views/admins/reversed_keywords/_form_modal.html.erb @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/app/views/admins/reversed_keywords/_list.html.erb b/app/views/admins/reversed_keywords/_list.html.erb new file mode 100644 index 000000000..5577c9999 --- /dev/null +++ b/app/views/admins/reversed_keywords/_list.html.erb @@ -0,0 +1,37 @@ +
序号ID项目名称公开issue序号ID项目名称公开精选推荐Issues 资源版本库PullRequestPulls 里程碑成员管理员<%= sort_tag('创建时间', name: 'created_on', path: admins_projects_path) %>操作成员管理员<%= sort_tag('创建时间', name: 'created_on', path: admins_projects_path) %>操作
<%= list_index_no((params[:page] || 1).to_i, index) %> <%= project.id %> - <%= link_to(project.name, "/projects/#{project&.owner&.login}/#{project.identifier}", target: '_blank') %> + <%= link_to(project.name, "/#{project&.owner&.login}/#{project.identifier}", target: '_blank') %> <%= project.is_public ? '√' : '' %><%= project.is_pinned ? '√' : '' %><%= project.recommend ? '√' : '' %> <%= project.issues.size %> <%= project.attachments.size %><%= project&.project_score.try(:changeset_num).to_i %><%= project&.project_score.try(:pull_request_num).to_i %><%= project&.pull_requests_count %> <%= project.versions.size %> <%= project.members.size %> @@ -37,8 +39,15 @@ <%= project.created_on&.strftime('%Y-%m-%d %H:%M') %> + <% if project.is_public %> + <%= javascript_void_link '精选', class: 'action pinned-action', data: { id: project.id }, style: project.is_pinned ? 'display: none;' : '' %> + <%= javascript_void_link '取消精选', class: 'action unpinned-action', data: { id: project.id }, style: project.is_pinned ? '' : 'display: none;' %> + <%= javascript_void_link '推荐', class: 'action recommend-action', data: { id: project.id }, style: project.recommend ? 'display: none;' : '' %> + <%= javascript_void_link '取消推荐', class: 'action unrecommend-action', data: { id: project.id }, style: project.recommend ? '' : 'display: none;' %> + <%= link_to "设置推荐等级", edit_admins_project_path(project.id), remote: true, class: "action edit-recommend-action", style: project.recommend ? '' : 'display: none;' %> + <% end %> <%= link_to "删除", admins_project_path(project.id), method: :delete, data:{confirm: "确认删除的吗?"}, class: "delete-project-action" %> -
+ + + + + + + + + + + + <% if keywords.present? %> + <% keywords.each_with_index do |keyword, index| %> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号<%= sort_tag('标识', name: 'identifier', path: admins_reversed_keywords_path) %>描述<%= sort_tag('限制是否开启', name: 'closed', path: admins_reversed_keywords_path) %><%= sort_tag('创建时间', name: 'created_at', path: admins_reversed_keywords_path) %>操作
<%= list_index_no((params[:page] || 1).to_i, index) %> + <%= link_to(keyword.identifier, "javascript:void(0)") %> + <%= keyword.description %><%= !keyword.closed ? '√' : '' %><%= keyword.created_at&.strftime('%Y-%m-%d %H:%M') %> + <%= javascript_void_link '开启限制', class: 'action unclose-action', data: { id: keyword.id }, style: keyword.closed? ? '' : 'display: none;' %> + <%= javascript_void_link '关闭限制', class: 'action close-action', data: { id: keyword.id }, style: keyword.closed? ? 'display: none;' : '' %> + <%= link_to "编辑", edit_admins_reversed_keyword_path(keyword), remote: true, class: "action" %> + <%= link_to "删除", admins_reversed_keyword_path(keyword), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: keywords } %> \ No newline at end of file diff --git a/app/views/admins/reversed_keywords/edit.js.erb b/app/views/admins/reversed_keywords/edit.js.erb new file mode 100644 index 000000000..0cb61e6fd --- /dev/null +++ b/app/views/admins/reversed_keywords/edit.js.erb @@ -0,0 +1,2 @@ +$("#reversed-keyword-modals").html("<%= j render(partial: 'admins/reversed_keywords/form_modal', locals: {type: 'update'}) %>") +$(".reversed-keyword-change-modal").modal('show'); \ No newline at end of file diff --git a/app/views/admins/reversed_keywords/index.html.erb b/app/views/admins/reversed_keywords/index.html.erb new file mode 100644 index 000000000..a5218c9c9 --- /dev/null +++ b/app/views/admins/reversed_keywords/index.html.erb @@ -0,0 +1,22 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('系统保留关键词') %> +<% end %> + +
+ <%= form_tag(admins_reversed_keywords_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_reversed_keyword_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %> +
+ +
+ 旨在为特殊用户群体、特殊场景、路由而保留的关键词,如:Gitlink、Trustie等;目前主要在用户注册、创建组织、创建项目等场景下做关键词的验证. +
+ +
+ <%= render partial: 'admins/reversed_keywords/list', locals: { keywords: @keywords } %> +
+
+
diff --git a/app/views/admins/reversed_keywords/index.js.erb b/app/views/admins/reversed_keywords/index.js.erb new file mode 100644 index 000000000..859d7be89 --- /dev/null +++ b/app/views/admins/reversed_keywords/index.js.erb @@ -0,0 +1 @@ +$('.reversed-keyword-list-container').html("<%= j( render partial: 'admins/reversed_keywords/list', locals: { keywords: @keywords } ) %>"); \ No newline at end of file diff --git a/app/views/admins/reversed_keywords/new.js.erb b/app/views/admins/reversed_keywords/new.js.erb new file mode 100644 index 000000000..91af4adc5 --- /dev/null +++ b/app/views/admins/reversed_keywords/new.js.erb @@ -0,0 +1,2 @@ +$("#reversed-keyword-modals").html("<%= j render(partial: 'admins/reversed_keywords/form_modal', locals: {type: 'create'}) %>") +$(".reversed-keyword-change-modal").modal('show'); \ No newline at end of file diff --git a/app/views/admins/salesman_channels/destroy.js.erb b/app/views/admins/salesman_channels/destroy.js.erb deleted file mode 100644 index d00e4fa08..000000000 --- a/app/views/admins/salesman_channels/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '操作成功' },{ type: 'success' }); -$("<%= params[:element]%>").remove(); \ No newline at end of file diff --git a/app/views/admins/salesman_channels/index.html.erb b/app/views/admins/salesman_channels/index.html.erb deleted file mode 100644 index 75847a542..000000000 --- a/app/views/admins/salesman_channels/index.html.erb +++ /dev/null @@ -1,36 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb("#{@salesman.name}的渠道", admins_salesmans_path) %> -<% end %> - -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('数据变化报表', admins_school_statistics_path) %> -<% end %> - -
-
-
-
-
- <%= text_field_tag :start_date, params[:start_date], class: 'form-control start-date mx-0', placeholder: '开始时间' %> -
- <%= text_field_tag :end_date, params[:end_date], class: 'form-control end-date mx-0', placeholder: '结束时间' %> -
-
- -
- <%= text_field_tag :keyword, params[:keyword], placeholder: 'ID/单位名称检索', class: 'form-control mx-3 search-input' %> - - <%= javascript_void_link '搜索', class: 'btn btn-primary search-btn', target: '' %> - -
-
- <%= javascript_void_link '新增渠道', class: 'btn btn-primary', data: {toggle: 'modal', target: '.admin-add-salesman-channel-user-modal' } %> -
-
- - -
- <%= render(partial: 'admins/salesman_channels/shared/list') %> -
- -<%= render 'admins/salesman_channels/shared/add_salesman_channels_user_modal' %> diff --git a/app/views/admins/salesman_channels/index.js.erb b/app/views/admins/salesman_channels/index.js.erb deleted file mode 100644 index 422cfe5cb..000000000 --- a/app/views/admins/salesman_channels/index.js.erb +++ /dev/null @@ -1 +0,0 @@ - $(".salesman-channel-list-container").html("<%= j(render partial: 'admins/salesman_channels/shared/list') %>") \ No newline at end of file diff --git a/app/views/admins/salesman_channels/shared/_add_salesman_channels_user_modal.html.erb b/app/views/admins/salesman_channels/shared/_add_salesman_channels_user_modal.html.erb deleted file mode 100644 index 121e711be..000000000 --- a/app/views/admins/salesman_channels/shared/_add_salesman_channels_user_modal.html.erb +++ /dev/null @@ -1,29 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/salesman_channels/shared/_list.html.erb b/app/views/admins/salesman_channels/shared/_list.html.erb deleted file mode 100644 index 8116e6cf6..000000000 --- a/app/views/admins/salesman_channels/shared/_list.html.erb +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - <% if @channels.present? %> - <% @channels.each_with_index do |channel, index| %> - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号名称教师数学生数课堂数实训数操作
<%= index + 1 %> - <%= channel.school_name %> - - <%= channel.teacher_count(@start_time, @end_time) %> - - <%= channel.student_count(@start_time, @end_time) %> - - <%= channel.course_count(@start_time, @end_time) %> - - <%= channel.shixuns_count(@start_time, @end_time) %> - - <%= delete_link '删除', admins_salesman_channel_path(channel, salesman_id: channel.salesman_id, element: ".salesman-channel-item-#{channel.id}"), class: 'delete-salesman-action' %> -
\ No newline at end of file diff --git a/app/views/admins/salesman_customers/destroy.js.erb b/app/views/admins/salesman_customers/destroy.js.erb deleted file mode 100644 index d00e4fa08..000000000 --- a/app/views/admins/salesman_customers/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '操作成功' },{ type: 'success' }); -$("<%= params[:element]%>").remove(); \ No newline at end of file diff --git a/app/views/admins/salesman_customers/index.html.erb b/app/views/admins/salesman_customers/index.html.erb deleted file mode 100644 index f7948b0f0..000000000 --- a/app/views/admins/salesman_customers/index.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb("#{@salesman.name}的客户", admins_salesmans_path) %> -<% end %> - -
-
- <%= javascript_void_link '新增客户', class: 'btn btn-primary', data: {salesman_id: @salesman.id, toggle: 'modal', target: '.admin-add-salesman-customer-user-modal' } %> -
-
- -
- <%= render(partial: 'admins/salesman_customers/shared/list') %> -
- -<%= render 'admins/salesman_customers/shared/add_salesman_customers_user_modal' %> diff --git a/app/views/admins/salesman_customers/index.js.erb b/app/views/admins/salesman_customers/index.js.erb deleted file mode 100644 index ed90f5394..000000000 --- a/app/views/admins/salesman_customers/index.js.erb +++ /dev/null @@ -1 +0,0 @@ - $(".salesman-customer-list-container").html("<%= j(render partial: 'admins/salesman_customers/shared/list') %>") \ No newline at end of file diff --git a/app/views/admins/salesman_customers/shared/_add_salesman_customers_user_modal.html.erb b/app/views/admins/salesman_customers/shared/_add_salesman_customers_user_modal.html.erb deleted file mode 100644 index f31499f52..000000000 --- a/app/views/admins/salesman_customers/shared/_add_salesman_customers_user_modal.html.erb +++ /dev/null @@ -1,30 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/salesman_customers/shared/_list.html.erb b/app/views/admins/salesman_customers/shared/_list.html.erb deleted file mode 100644 index 21e639865..000000000 --- a/app/views/admins/salesman_customers/shared/_list.html.erb +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - <% if @customers.present? %> - <% @customers.each_with_index do |customer, index| %> - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号名称单位课堂数实训数操作
<%= index + 1 %> - <%= link_to customer.name, user_path(customer), :title => customer.name %> - - <%= customer.school_name %> - - <%= customer.courses_count %> - - <%= customer.shixuns_count %> - - <%= delete_link '删除', admins_salesman_customer_path(customer, salesman_id: customer.salesman_id, element: ".salesman-customer-item-#{customer.id}"), class: 'delete-salesman--action' %> -
\ No newline at end of file diff --git a/app/views/admins/salesmans/destroy.js.erb b/app/views/admins/salesmans/destroy.js.erb deleted file mode 100644 index 0a9fa8518..000000000 --- a/app/views/admins/salesmans/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '操作成功' },{ type: 'success' }); -$(".salesman-item-<%= params[:id]%>").remove(); \ No newline at end of file diff --git a/app/views/admins/salesmans/index.html.erb b/app/views/admins/salesmans/index.html.erb deleted file mode 100644 index 2c5a095ef..000000000 --- a/app/views/admins/salesmans/index.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('销售数据列表', admins_salesmans_path) %> -<% end %> - -
-
- <%= javascript_void_link '新增销售人员', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-add-salesman-user-modal' } %> -
-
- -
- <%= render(partial: 'admins/salesmans/shared/list') %> -
- -<%= render 'admins/salesmans/shared/add_salesman_user_modal' %> diff --git a/app/views/admins/salesmans/shared/_add_salesman_user_modal.html.erb b/app/views/admins/salesmans/shared/_add_salesman_user_modal.html.erb deleted file mode 100644 index 20e2befda..000000000 --- a/app/views/admins/salesmans/shared/_add_salesman_user_modal.html.erb +++ /dev/null @@ -1,30 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/salesmans/shared/_list.html.erb b/app/views/admins/salesmans/shared/_list.html.erb deleted file mode 100644 index 8293b4575..000000000 --- a/app/views/admins/salesmans/shared/_list.html.erb +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - <% if @salesmans.present? %> - <% @salesmans.each_with_index do |salesman, index| %> - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号业务员重点跟踪客户(点击数字客户列表)重点跟踪院校(点击数字渠道列表)操作
<%= index + 1 %> - <%= link_to salesman.name, admins_salesman_path(salesman), :title => salesman.name %> - - <%= link_to salesman.salesman_customers_count.to_i, - admins_salesman_customers_path(salesman_id: salesman), :title => "点击进入客户列表" %> - - <%= link_to salesman.salesman_channels_count.to_i, admins_salesman_channels_path(salesman_id: salesman), - :title => "点击进入渠道列表" %> - - <%= delete_link '删除', admins_salesman_path(salesman, element: ".salesman-item-#{salesman.id}"), - class: 'delete-salesman-action' %> -
\ No newline at end of file diff --git a/app/views/admins/school_statistics/contrast.js.erb b/app/views/admins/school_statistics/contrast.js.erb deleted file mode 100644 index bc9916c12..000000000 --- a/app/views/admins/school_statistics/contrast.js.erb +++ /dev/null @@ -1 +0,0 @@ -$(".school-statistic-list-container").html("<%= j(render partial: 'admins/school_statistics/shared/contrast_list', locals: { statistics: @statistics, select_options: @select_options }) %>") \ No newline at end of file diff --git a/app/views/admins/school_statistics/index.html.erb b/app/views/admins/school_statistics/index.html.erb deleted file mode 100644 index d726adb22..000000000 --- a/app/views/admins/school_statistics/index.html.erb +++ /dev/null @@ -1,49 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('数据变化报表', admins_school_statistics_path) %> -<% end %> - -
-
-
- - <%= hidden_field_tag :contrast_column, params[:contrast_column] %> - -
-
- <%= text_field_tag :grow_begin_date, params[:grow_begin_date], class: 'form-control start-date mx-0', placeholder: '开始时间' %> -
- <%= text_field_tag :grow_end_date, params[:grow_end_date], class: 'form-control end-date mx-0', placeholder: '结束时间' %> -
-
-
-
- <%= text_field_tag :begin_date, params[:begin_date], class: 'form-control start-date mx-0', placeholder: '开始时间' %> -
- <%= text_field_tag :end_date, params[:end_date], class: 'form-control end-date mx-0', placeholder: '结束时间' %> -
-
VS
-
- <%= text_field_tag :other_begin_date, params[:other_begin_date], class: 'form-control start-date mx-0', placeholder: '开始时间' %> -
- <%= text_field_tag :other_end_date, params[:other_end_date], class: 'form-control end-date mx-0', placeholder: '结束时间' %> -
-
-
- -
- <%= hidden_field_tag :data_type, params[:data_type] || 'grow' %> - <%= javascript_void_link '时段对比', class: "btn btn-outline-info btn-sm contrast-btn #{params[:data_type] == 'contrast' ? 'active' : ''}", - data: { toggle: 'tooltip', trigger: 'hover', title: '请在左侧分别选择需进行对比的两个时段,具体从当日5:00开始计算,下表显示两时段选定指标两时段变化情况对比' } %> - <%= javascript_void_link '数据变化', class: "btn btn-outline-info btn-sm grow-btn #{params[:data_type] == 'contrast' ? '' : 'active'}", - data: { toggle: 'tooltip', trigger: 'hover', title: '请在左侧选择时间段,具体从当日5:00开始计算,下表显示选定时间段内各项指标数据变化情况' } %> -
- - <%= text_field_tag :keyword, params[:keyword], placeholder: 'ID/单位名称检索', class: 'form-control mx-3 search-input' %> - - <%= javascript_void_link '搜索', class: 'btn btn-primary search-btn' %> -
-
- -
- <%= render partial: 'admins/school_statistics/shared/list', locals: { statistics: @statistics } %> -
\ No newline at end of file diff --git a/app/views/admins/school_statistics/index.js.erb b/app/views/admins/school_statistics/index.js.erb deleted file mode 100644 index 3f5f7334b..000000000 --- a/app/views/admins/school_statistics/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$(".school-statistic-list-container").html("<%= j(render partial: 'admins/school_statistics/shared/list', locals: { statistics: @statistics }) %>") \ No newline at end of file diff --git a/app/views/admins/school_statistics/shared/_contrast_list.html.erb b/app/views/admins/school_statistics/shared/_contrast_list.html.erb deleted file mode 100644 index 928340c80..000000000 --- a/app/views/admins/school_statistics/shared/_contrast_list.html.erb +++ /dev/null @@ -1,72 +0,0 @@ -
-
- 学校数据统计(<%= I18n.t("school_daily_report.#{params[:contrast_column]}") %>变化统计情况) -
- <%= select_tag :contrast_column, - options_for_select(select_options, params[:contrast_column]), - class: 'form-control contrast-column-select' %> - - <% if statistics.present? %> -
- 说明:新增数=时段二-时段一;新增百分比=(新增数/时段一)*100%(保留小数点后五位) -
- <% end %> -
- -<% if statistics.present? %> - - - - - - - - - - - <% statistics.each do |statistic| %> - - - - - <% - increase = statistic['other_total'] - statistic['total'] - percentage = statistic['total'].zero? ? increase.to_f * 100 : (increase / statistic['total'].to_f) * 100 - %> - <% if increase > 0 %> - - <% if statistic['total'].zero? %> - - <% else %> - - <% end %> - <% elsif increase.zero? %> - - - <% else %> - - - <% end %> - - <% end %> - -
单位名称时段一
<%= "(#{params[:begin_date]} 05:00至#{(Time.zone.parse(params[:end_date]) + 1.days).strftime('%Y-%m-%d')} 05:00)" %>
时段二
<%= "(#{params[:other_begin_date]} 05:00至#{(Time.zone.parse(params[:other_end_date]) + 1.days).strftime('%Y-%m-%d')} 05:00)" %>
- <%= sort_tag('变化情况', name: 'percentage', path: contrast_admins_school_statistics_path) %> -
( 新 增 数 | 新增百分比) -
- <%= link_to statistic.school_name, "/colleges/#{statistic.school_id}/statistics", - target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %> - <%= statistic['total'] %><%= statistic['other_total'] %> - +<%= increase %> - -+<%= percentage.round(5) %>% - <%= increase %> - <%= percentage.round(5) %>% - <%= increase %> - <%= percentage.round(5) %>%
- - <%= render partial: 'admins/shared/paginate', locals: { objects: statistics } %> -<% else %> -
- 暂无数据,请选择时间段对比 -
-<% end %> \ No newline at end of file diff --git a/app/views/admins/school_statistics/shared/_list.html.erb b/app/views/admins/school_statistics/shared/_list.html.erb deleted file mode 100644 index 9d2a1c209..000000000 --- a/app/views/admins/school_statistics/shared/_list.html.erb +++ /dev/null @@ -1,58 +0,0 @@ -
- 统计总计: - <% if params[:grow_begin_date].present? %> - <%= params[:grow_begin_date] %> 05:00至<%= (Time.zone.parse(params[:grow_end_date]) + 1.days).strftime('%Y-%m-%d') %> 05:00 - <% else %> - <%= (Time.current - 5.hour).beginning_of_day.ago(1.days).strftime('%Y-%m-%d') %> 05:00至 - <%= (Time.current - 5.hour).beginning_of_day.strftime('%Y-%m-%d') %> 05:00, - <% end %> - 新增教师<%= @grow_summary.teacher_increase_count || 0 %>人, - 新增学生<%= @grow_summary.student_increase_count || 0 %>人, - 新增课堂<%= @grow_summary.course_increase_count || 0 %>个, - 新增实训<%= @grow_summary.shixun_increase_count || 0 %>个, - 新增实训作业<%= @grow_summary.shixun_homework_count || 0 %>个, - 新增实训评测<%= @grow_summary.shixun_evaluate_count || 0 %>个, - 活跃用户 - <%= @grow_summary.uniq_active_user_count.to_i.zero? ? @grow_summary.active_user_count.to_i : @grow_summary.uniq_active_user_count.to_i %> - 个 -
- - - - - - - - - - - - - - - - - <% if statistics.present? %> - <% statistics.each_with_index do |statistic, index| %> - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号单位名称<%= sort_tag('新增教师', name: 'teacher_increase_count', path: admins_school_statistics_path) %><%= sort_tag('新增学生', name: 'student_increase_count', path: admins_school_statistics_path) %><%= sort_tag('新增课堂', name: 'course_increase_count', path: admins_school_statistics_path) %><%= sort_tag('新增实训', name: 'shixun_increase_count', path: admins_school_statistics_path) %><%= sort_tag('新增实训作业', name: 'shixun_homework_count', path: admins_school_statistics_path) %><%= sort_tag('新增实训评测', name: 'shixun_evaluate_count', path: admins_school_statistics_path) %><%= sort_tag('活跃用户', name: 'uniq_active_user_count', path: admins_school_statistics_path) %>
<%= list_index_no(@params_page.to_i, index) %> - <%= link_to statistic.school_name, "/colleges/#{statistic.school_id}/statistics", - target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %> - <%= statistic.teacher_increase_count.to_i %><%= statistic.student_increase_count.to_i %><%= statistic.course_increase_count.to_i %><%= statistic.shixun_increase_count.to_i %><%= statistic.shixun_homework_count.to_i %><%= statistic.shixun_evaluate_count.to_i %><%= statistic.uniq_active_user_count.to_i.zero? ? statistic.active_user_count.to_i : statistic.uniq_active_user_count.to_i %>
- -<%= render partial: 'admins/shared/paginate', locals: { objects: statistics } %> \ No newline at end of file diff --git a/app/views/admins/schools/index.html.erb b/app/views/admins/schools/index.html.erb deleted file mode 100644 index 56cbadd9d..000000000 --- a/app/views/admins/schools/index.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('单位列表') %> -<% end %> - -
- <%= form_tag(admins_schools_path, method: :get, class: 'form-inline search-form flex-1', 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': '搜索中...') %> - <% end %> - - <%#= javascript_void_link '新建单位', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-school-modal' } %> -
- -
- <%= render partial: 'admins/schools/shared/list', locals: { schools: @schools } %> -
\ No newline at end of file diff --git a/app/views/admins/schools/index.js.erb b/app/views/admins/schools/index.js.erb deleted file mode 100644 index 41a2454be..000000000 --- a/app/views/admins/schools/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('.school-list-container').html("<%= j(render partial: 'admins/schools/shared/list', locals: { schools: @schools }) %>"); \ No newline at end of file diff --git a/app/views/admins/schools/index.json.jbuilder b/app/views/admins/schools/index.json.jbuilder deleted file mode 100644 index 3f358191f..000000000 --- a/app/views/admins/schools/index.json.jbuilder +++ /dev/null @@ -1,6 +0,0 @@ -json.count @total_count -json.schools do - json.array! @schools.each do |school| - json.extract! school, :id, :name - end -end \ No newline at end of file diff --git a/app/views/admins/schools/shared/_list.html.erb b/app/views/admins/schools/shared/_list.html.erb deleted file mode 100644 index dd0a054e3..000000000 --- a/app/views/admins/schools/shared/_list.html.erb +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - <% if schools.present? %> - <% schools.each_with_index do |school, index| %> - - - - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
序号IDLOGO标识码单位名称地区城市详细地址<%= sort_tag('用户数', name: 'users_count', path: admins_schools_path) %>部门数<%= sort_tag('创建时间', name: 'created_at', path: admins_schools_path) %>操作
<%= list_index_no((params[:page] || 1).to_i, index) %><%= school.id %> - <% if Util::FileManage.exists?(school) %> - <%= image_tag(Util::FileManage.source_disk_file_url(school).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image') %> - <% else %> - <%= content_tag(:span, '--', class: 'text-secondary') %> - <% end %> - <%= display_text school.identifier %><%= school.name %><%= school.province %><%= school.city %><%= school.address %><%= school.users_count %><%= @department_count.fetch(school.id, 0) %><%= school.created_at&.strftime('%Y-%m-%d %H:%M') %> - <%= delete_link '删除', admins_school_path(school, element: ".school-item-#{school.id}"), class: 'delete-school-action' %> -
- -<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %> \ No newline at end of file diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 82553d9a0..d757758e4 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -29,18 +29,22 @@ <% end %> +
  • <%= sidebar_item(admins_reversed_keywords_path, '系统保留关键词', icon: 'key', controller: 'admins-reversed_keywords') %>
  • <%= sidebar_item(admins_laboratories_path, '云上实验室', icon: 'cloud', controller: 'admins-laboratories') %>
  • <%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %> -
  • <%= sidebar_item(edit_admins_about_path, '关于我们', icon: 'smile-o', controller: 'admins-abouts') %>
  • -
  • <%= sidebar_item(edit_admins_contact_us_path, '联系我们', icon: 'commenting-o', controller: 'admins-contact_us') %>
  • -
  • <%= sidebar_item(admins_cooperatives_path, '合作伙伴', icon: 'handshake-o', controller: 'admins-cooperatives') %>
  • -
  • <%= sidebar_item(edit_admins_agreement_path, '服务协议', icon: 'file-text-o', controller: 'admins-agreements') %>
  • -
  • <%= sidebar_item(edit_admins_help_center_path, '帮助中心', icon: 'question-circle-o', controller: 'admins-help_centers') %>
  • <%= sidebar_item(admins_faqs_path, 'FAQ', icon: 'question-circle', controller: 'admins-faqs') %>
  • <% end %> +
  • + <%= sidebar_item_group('#setting-system', '系统配置', icon: 'wrench') do %> +
  • <%= sidebar_item(admins_sites_path, 'setting接口配置', icon: 'deaf', controller: 'admins-sites') %>
  • +
  • <%= sidebar_item(admins_edu_settings_path, '全局变量配置', icon: 'pencil-square', controller: 'admins-edu_settings') %>
  • +
  • <%= sidebar_item(admins_system_notifications_path, '系统通知配置', icon: 'bell', controller: 'admins-system_notifications') %>
  • +
  • <%= sidebar_item(admins_message_templates_path, '消息模版配置', icon: 'folder', controller: 'admins-message_templates') %>
  • + <% end %> +
  • <%= sidebar_item('/admins/sidekiq', '定时任务', icon: 'bell', controller: 'root') %>
  • diff --git a/app/views/admins/sites/_form.html.erb b/app/views/admins/sites/_form.html.erb new file mode 100644 index 000000000..1776bcd03 --- /dev/null +++ b/app/views/admins/sites/_form.html.erb @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/app/views/admins/sites/_list.html.erb b/app/views/admins/sites/_list.html.erb new file mode 100644 index 000000000..bef39cf1f --- /dev/null +++ b/app/views/admins/sites/_list.html.erb @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + <% if sites.present? %> + <% sites.each_with_index do |site, index| %> + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
    序号名称路由标识类型<%= sort_tag('创建时间', name: 'created_at', path: admins_sites_path) %>操作
    <%= list_index_no((params[:page] || 1).to_i, index) %> + <%= overflow_hidden_span display_text(site.name), width: 150 %> + <%= site.url %><%= overflow_hidden_span display_text(site.key), width: 150 %><%= site.site_type.humanize %><%= site.created_at&.strftime('%Y-%m-%d %H:%M') %> + <%= link_to "编辑", edit_admins_site_path(site), remote: true, class: "action" %> + <%= link_to "删除", admins_site_path(site), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %> +
    + +<%= render partial: 'admins/shared/paginate', locals: { objects: sites } %> \ No newline at end of file diff --git a/app/views/admins/sites/edit.js.erb b/app/views/admins/sites/edit.js.erb new file mode 100644 index 000000000..6711ffc1f --- /dev/null +++ b/app/views/admins/sites/edit.js.erb @@ -0,0 +1,2 @@ +$("#site-modals").html("<%= j render(partial: 'admins/sites/form', locals: {type: 'update'}) %>") +$(".site-change-modal").modal('show'); \ No newline at end of file diff --git a/app/views/admins/sites/index.html.erb b/app/views/admins/sites/index.html.erb new file mode 100644 index 000000000..8a5fa1bfc --- /dev/null +++ b/app/views/admins/sites/index.html.erb @@ -0,0 +1,24 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('Setting接口配置') %> +<% end %> + +
    + <%= form_tag(admins_sites_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> +
    + + <% type_options = [['全部', ''], ['Add', Site.site_types[:add]], ['Personal', Site.site_types[:personal]], ['Common', Site.site_types[:common]]] %> + <%= select_tag(:site_type, options_for_select(type_options), class: 'form-control') %> +
    + + <%= 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_site_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %> +
    + +
    + <%= render partial: 'admins/sites/list', locals: { sites: @sites } %> +
    +
    +
    diff --git a/app/views/admins/sites/index.js.erb b/app/views/admins/sites/index.js.erb new file mode 100644 index 000000000..797d58296 --- /dev/null +++ b/app/views/admins/sites/index.js.erb @@ -0,0 +1 @@ +$('.sites-list-container').html("<%= j( render partial: 'admins/sites/list', locals: { sites: @sites } ) %>"); \ No newline at end of file diff --git a/app/views/admins/sites/new.js.erb b/app/views/admins/sites/new.js.erb new file mode 100644 index 000000000..6978fed32 --- /dev/null +++ b/app/views/admins/sites/new.js.erb @@ -0,0 +1,2 @@ +$("#site-modals").html("<%= j render(partial: 'admins/sites/form', locals: {type: 'create'}) %>") +$(".site-change-modal").modal('show'); \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/adjust_position.js.erb b/app/views/admins/sub_disciplines/adjust_position.js.erb deleted file mode 100644 index 0dae991c1..000000000 --- a/app/views/admins/sub_disciplines/adjust_position.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% if @message.present? %> -$.notify({ message: "<%= @message %>" }); -<% else %> -$(".sub-discipline-list-container").html("<%= j(render :partial => 'admins/sub_disciplines/shared/list') %>"); -<% end %> \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/destroy.js.erb b/app/views/admins/sub_disciplines/destroy.js.erb deleted file mode 100644 index bb03cdcf1..000000000 --- a/app/views/admins/sub_disciplines/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '删除成功' }); -$(".sub-discipline-item-<%= @sub_discipline_id %>").remove(); \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/edit.js.erb b/app/views/admins/sub_disciplines/edit.js.erb deleted file mode 100644 index aa7219de5..000000000 --- a/app/views/admins/sub_disciplines/edit.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.admin-modal-container').html("<%= j( render partial: 'admins/sub_disciplines/shared/edit_sub_discipline_modal', locals: { sub_discipline: @sub_discipline } ) %>"); -$('.modal.admin-edit-sub-discipline-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/index.html.erb b/app/views/admins/sub_disciplines/index.html.erb deleted file mode 100644 index d782e00ae..000000000 --- a/app/views/admins/sub_disciplines/index.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('课程方向', admins_disciplines_path) %> - <% add_admin_breadcrumb(@discipline.name) %> -<% end %> - -
    - <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-sub-discipline-modal' } %> -
    - -
    - <%= render(partial: 'admins/sub_disciplines/shared/list') %> -
    - -<%= render 'admins/sub_disciplines/shared/create_sub_discipline_modal' %> diff --git a/app/views/admins/sub_disciplines/shared/_create_sub_discipline_modal.html.erb b/app/views/admins/sub_disciplines/shared/_create_sub_discipline_modal.html.erb deleted file mode 100644 index a8b00b051..000000000 --- a/app/views/admins/sub_disciplines/shared/_create_sub_discipline_modal.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/shared/_edit_sub_discipline_modal.html.erb b/app/views/admins/sub_disciplines/shared/_edit_sub_discipline_modal.html.erb deleted file mode 100644 index b51c267bb..000000000 --- a/app/views/admins/sub_disciplines/shared/_edit_sub_discipline_modal.html.erb +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/shared/_list.html.erb b/app/views/admins/sub_disciplines/shared/_list.html.erb deleted file mode 100644 index cd0b02f88..000000000 --- a/app/views/admins/sub_disciplines/shared/_list.html.erb +++ /dev/null @@ -1,37 +0,0 @@ -<% max_position = @sub_disciplines.pluck(:position).max %> - - - - - - - - - - - - - <% if @sub_disciplines.present? %> - <% @sub_disciplines.each do |sub| %> - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号课程实践课程实训题库操作
    <%= sub.position %> - <%= link_to sub.name, admins_tag_disciplines_path(sub_discipline_id: sub), :title => sub.name %> - <%= check_box_tag :subject,!sub.subject,sub.subject,disabled:!sub.discipline&.subject,remote:true,data:{id:sub.id},class:"sub-discipline-source-form" %><%= check_box_tag :shixun,!sub.shixun,sub.shixun,disabled:!sub.discipline&.shixun,remote:true,data:{id:sub.id},class:"sub-discipline-source-form" %><%= check_box_tag :question,!sub.question,sub.question,disabled:!sub.discipline&.question,remote:true,data:{id:sub.id},class:"sub-discipline-source-form" %> - <%= javascript_void_link('上移', class: 'move-action', data: { id: sub.id, opr: "up" }, style: sub.position == 1 ? 'display:none' : '') %> - <%= javascript_void_link('下移', class: 'move-action', data: { id: sub.id, opr: "down" }, style: sub.position == max_position ? 'display:none' : '') %> - - <%= link_to '编辑', edit_admins_sub_discipline_path(sub), remote: true, class: 'action' %> - <%= delete_link '删除', admins_sub_discipline_path(sub, element: ".sub-discipline-item-#{sub.id}"), class: 'delete-sub-discipline-action' %> -
    \ No newline at end of file diff --git a/app/views/admins/sub_disciplines/update.js.erb b/app/views/admins/sub_disciplines/update.js.erb deleted file mode 100644 index 395e06778..000000000 --- a/app/views/admins/sub_disciplines/update.js.erb +++ /dev/null @@ -1,6 +0,0 @@ -<% if @message.present? %> -$.notify({ message: "<%= @message %>" }); -<% else %> -$('.modal.admin-edit-sub-discipline-modal').modal("hide"); -$(".sub-discipline-list-container").html("<%= j(render :partial => 'admins/sub_disciplines/shared/list') %>"); -<% end %> \ No newline at end of file diff --git a/app/views/admins/sub_repertoires/destroy.js.erb b/app/views/admins/sub_repertoires/destroy.js.erb deleted file mode 100644 index 4575f811c..000000000 --- a/app/views/admins/sub_repertoires/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '删除成功' }); -$(".sub-repertoire-item-<%= @sub_repertoire_id %>").remove(); \ No newline at end of file diff --git a/app/views/admins/sub_repertoires/edit.js.erb b/app/views/admins/sub_repertoires/edit.js.erb deleted file mode 100644 index 10fe19697..000000000 --- a/app/views/admins/sub_repertoires/edit.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.admin-modal-container').html("<%= j( render partial: 'admins/sub_repertoires/shared/edit_sub_repertoire_modal', locals: { sub_repertoire: @sub_repertoire } ) %>"); -$('.modal.admin-edit-sub-repertoire-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/sub_repertoires/index.html.erb b/app/views/admins/sub_repertoires/index.html.erb deleted file mode 100644 index be8ec98f9..000000000 --- a/app/views/admins/sub_repertoires/index.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('技术体系', admins_repertoires_path) %> - <% add_admin_breadcrumb(@repertoire.name) %> -<% end %> - -
    - <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-sub-repertoire-modal' } %> -
    - -
    - <%= render(partial: 'admins/sub_repertoires/shared/list') %> -
    - -<%= render 'admins/sub_repertoires/shared/create_sub_repertoire_modal' %> diff --git a/app/views/admins/sub_repertoires/shared/_create_sub_repertoire_modal.html.erb b/app/views/admins/sub_repertoires/shared/_create_sub_repertoire_modal.html.erb deleted file mode 100644 index 435f2fb32..000000000 --- a/app/views/admins/sub_repertoires/shared/_create_sub_repertoire_modal.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/sub_repertoires/shared/_edit_sub_repertoire_modal.html.erb b/app/views/admins/sub_repertoires/shared/_edit_sub_repertoire_modal.html.erb deleted file mode 100644 index 28ff8a169..000000000 --- a/app/views/admins/sub_repertoires/shared/_edit_sub_repertoire_modal.html.erb +++ /dev/null @@ -1,23 +0,0 @@ - diff --git a/app/views/admins/sub_repertoires/shared/_list.html.erb b/app/views/admins/sub_repertoires/shared/_list.html.erb deleted file mode 100644 index 77d20ef4c..000000000 --- a/app/views/admins/sub_repertoires/shared/_list.html.erb +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - <% if @sub_repertoires.present? %> - <% @sub_repertoires.each_with_index do |sub, index| %> - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号课程操作
    <%= index + 1 %> - <%= link_to sub.name, admins_tag_repertoires_path(sub_repertoire_id: sub), :title => sub.name %> - - <%= link_to '编辑', edit_admins_sub_repertoire_path(sub), remote: true, class: 'action' %> - <%= delete_link '删除', admins_sub_repertoire_path(sub, element: ".sub-repertoire-item-#{sub.id}"), class: 'delete-sub-repertoire-action' %> -
    \ No newline at end of file diff --git a/app/views/admins/sub_repertoires/update.js.erb b/app/views/admins/sub_repertoires/update.js.erb deleted file mode 100644 index 04d282c5a..000000000 --- a/app/views/admins/sub_repertoires/update.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.modal.admin-edit-sub-repertoire-modal').modal("hide"); -$(".sub-repertoire-list-container").html("<%= j(render :partial => 'admins/sub_repertoires/shared/list') %>"); \ No newline at end of file diff --git a/app/views/admins/subject_authorizations/index.html.erb b/app/views/admins/subject_authorizations/index.html.erb deleted file mode 100644 index f3ae7bf56..000000000 --- a/app/views/admins/subject_authorizations/index.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('实践课程发布') %> -<% end %> - -
    - - - <%= form_tag(admins_subject_authorizations_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %> -
    - - <% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %> - <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %> -
    - <%= 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': '搜索中...') %> - <% end %> -
    - -
    - <%= render(partial: 'admins/subject_authorizations/shared/list', - locals: { applies: @applies, subject_map: @subject_map, challenge_count_map: @challenge_count_map }) %> -
    - -<%= render(partial: 'admins/shared/admin_common_refuse_modal') %> \ No newline at end of file diff --git a/app/views/admins/subject_authorizations/index.js.erb b/app/views/admins/subject_authorizations/index.js.erb deleted file mode 100644 index a21809041..000000000 --- a/app/views/admins/subject_authorizations/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('.subject-authorization-list-container').html("<%= j( render partial: 'admins/subject_authorizations/shared/list', locals: { applies: @applies, subject_map: @subject_map, challenge_count_map: @challenge_count_map } ) %>"); \ No newline at end of file diff --git a/app/views/admins/subject_authorizations/shared/_list.html.erb b/app/views/admins/subject_authorizations/shared/_list.html.erb deleted file mode 100644 index 94503dad7..000000000 --- a/app/views/admins/subject_authorizations/shared/_list.html.erb +++ /dev/null @@ -1,66 +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 %> - <% subject = subject_map[apply.container_id] %> - - - - - - - - - - - <% if is_processed %> - - - <% else %> - - <% end %> - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号头像创建者实践课程名称阶段数实训数关卡数时间拒绝原因状态操作
    <%= list_index_no((params[:page] || 1).to_i, index) %> - <%= link_to "/users/#{user.login}", class: 'subject-authorization-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %> - - <% end %> - <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> - <%= link_to "/paths/#{subject.id}", target: '_blank' do %> - <%= overflow_hidden_span subject.name, width: 300 %> - <% end %> - <%= subject.stages_count %><%= subject.shixuns_count %><%= challenge_count_map.fetch(subject.id, 0) %><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %><%= overflow_hidden_span apply.reason, width: 140 %><%= apply.status_text %> - <%= agree_link '同意', agree_admins_subject_authorization_path(apply, element: ".subject-authorization-#{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_subject_authorization_path(apply, element: ".subject-authorization-#{apply.id}") - }) %> -
    - -<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %> \ No newline at end of file diff --git a/app/views/admins/subject_settings/index.html.erb b/app/views/admins/subject_settings/index.html.erb deleted file mode 100644 index b46c1d90d..000000000 --- a/app/views/admins/subject_settings/index.html.erb +++ /dev/null @@ -1,41 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('课程配置') %> -<% end %> - -
    - <%= form_tag(admins_subject_settings_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> -
    - - <% status_options = [['全部', ''], ['编辑中', 'pending'], ['审核中', 'applying'], ['已公开', 'published']] %> - <%= 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_show, false, id:'') %> - <%= check_box_tag(:homepage_show, true, params[:homepage_show].to_s == 'true', class: 'form-check-input') %> - -
    - -
    - <%= hidden_field_tag(:excellent, false, id:'') %> - <%= check_box_tag(:excellent, true, params[:excellent].to_s == 'true', class: 'form-check-input') %> - -
    - - <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> - - <% end %> -
    - -
    - <%= render partial: 'admins/subject_settings/shared/list', locals: { subjects: @subjects } %> -
    - -<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片', accept: 'image/*' } %> \ No newline at end of file diff --git a/app/views/admins/subject_settings/index.js.erb b/app/views/admins/subject_settings/index.js.erb deleted file mode 100644 index c3f403462..000000000 --- a/app/views/admins/subject_settings/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('.subject-setting-list-container').html("<%= j( render partial: 'admins/subject_settings/shared/list', locals: { subjects: @subjects } ) %>"); \ No newline at end of file diff --git a/app/views/admins/subject_settings/mobile.js.erb b/app/views/admins/subject_settings/mobile.js.erb deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/views/admins/subject_settings/shared/_edit_subject_modal.html.erb b/app/views/admins/subject_settings/shared/_edit_subject_modal.html.erb deleted file mode 100644 index 6e9aa871a..000000000 --- a/app/views/admins/subject_settings/shared/_edit_subject_modal.html.erb +++ /dev/null @@ -1,33 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/subject_settings/shared/_list.html.erb b/app/views/admins/subject_settings/shared/_list.html.erb deleted file mode 100644 index 79411e892..000000000 --- a/app/views/admins/subject_settings/shared/_list.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - <% if subjects.present? %> - <% subjects.each_with_index do |subject, index| %> - - <% page_no = ((params[:page] || 1).to_i - 1) * 20 + index + 1 %> - <%= render partial: "admins/subject_settings/shared/td",locals: {subject: subject,page_no:page_no} %> - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号名称老版技术体系状态课程体系封面开课人数操作
    - -<%= render partial: 'admins/shared/paginate', locals: { objects: subjects } %> \ No newline at end of file diff --git a/app/views/admins/subject_settings/shared/_td.html.erb b/app/views/admins/subject_settings/shared/_td.html.erb deleted file mode 100644 index 94d34f42d..000000000 --- a/app/views/admins/subject_settings/shared/_td.html.erb +++ /dev/null @@ -1,47 +0,0 @@ -<%= page_no %> - - <%= link_to(subject.name, "/paths/#{subject.id}", target: '_blank') %> - 首页 - 金课 - -<%= display_text subject.repertoire&.name %> -<%= display_text subject.public == 2 ? "已公开" : ((subject.public == 1 && subject.status == 2) ? "审核中" : "未发布") %> - - <%= select_tag(:sub_disciplines, options_for_select(@sub_disciplines, subject.sub_disciplines.pluck(:id)),multiple:true,class:"form-control subject-setting-form",data:{id:subject.id},id:"tags-chosen-#{subject.id}") %> - - - <% 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') %> - <%= javascript_void_link image_exists ? '重新上传' : '上传图片', class: 'action upload-image-action', data: { source_id: subject.id, source_type: 'Subject', toggle: 'modal', target: '.admin-upload-file-modal' } %> - -<%= subject.student_count %> - - <%= check_box_tag :show_mobile, !subject.show_mobile, subject.show_mobile, remote: true, - data: {id: subject.id, toggle: "tooltip", placement: "top"}, class: "subject-mobile-form mr10", title: "小程序端显示" %> - <%= link_to('编辑', edit_admins_subject_path(subject), remote: true, class: 'edit-action') %> - - - \ No newline at end of file diff --git a/app/views/admins/subject_settings/update.js.erb b/app/views/admins/subject_settings/update.js.erb deleted file mode 100644 index c95a41ec3..000000000 --- a/app/views/admins/subject_settings/update.js.erb +++ /dev/null @@ -1 +0,0 @@ -$.notify({ message: '更新成功' }); \ No newline at end of file diff --git a/app/views/admins/subject_settings/update_mobile_show.js.erb b/app/views/admins/subject_settings/update_mobile_show.js.erb deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/views/admins/subjects/edit.js.erb b/app/views/admins/subjects/edit.js.erb deleted file mode 100644 index b2e12f9bb..000000000 --- a/app/views/admins/subjects/edit.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.admin-modal-container').html("<%= j( render partial: 'admins/subjects/shared/edit_subject_modal', locals: { subject: @subject } ) %>"); -$('.modal.admin-edit-subject-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/subjects/index.html.erb b/app/views/admins/subjects/index.html.erb deleted file mode 100644 index 39c4a349b..000000000 --- a/app/views/admins/subjects/index.html.erb +++ /dev/null @@ -1,39 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('课程列表') %> -<% end %> - -
    - <%= form_tag(admins_subjects_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> -
    - - <% status_options = [['全部', ''], ["编辑中", "editing"], ["已发布", 'processed'], ["待审核", 'pending'], ["已公开", 'publiced']] %> - <%= 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_show, false, id:'') %> - <%= check_box_tag(:homepage_show, true, params[:homepage_show].to_s == 'true', class: 'form-check-input') %> - -
    - -
    - <%= hidden_field_tag(:excellent, false, id:'') %> - <%= check_box_tag(:excellent, true, params[:excellent].to_s == 'true', class: 'form-check-input') %> - -
    - - <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> - - <% end %> -
    - -
    - <%= render partial: 'admins/subjects/shared/list', locals: { subjects: @subjects } %> -
    \ No newline at end of file diff --git a/app/views/admins/subjects/index.js.erb b/app/views/admins/subjects/index.js.erb deleted file mode 100644 index 20e07f13a..000000000 --- a/app/views/admins/subjects/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('.subject-list-container').html("<%= j( render partial: 'admins/subjects/shared/list', locals: { subjects: @subjects } ) %>"); \ No newline at end of file diff --git a/app/views/admins/subjects/shared/_edit_subject_modal.html.erb b/app/views/admins/subjects/shared/_edit_subject_modal.html.erb deleted file mode 100644 index 6e9aa871a..000000000 --- a/app/views/admins/subjects/shared/_edit_subject_modal.html.erb +++ /dev/null @@ -1,33 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/subjects/shared/_list.html.erb b/app/views/admins/subjects/shared/_list.html.erb deleted file mode 100644 index ee136ddf5..000000000 --- a/app/views/admins/subjects/shared/_list.html.erb +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - <% if subjects.present? %> - <% subjects.each_with_index do |subject, index| %> - - - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号名称阶段数实训数创建者单位<%= sort_tag('创建时间', name: 'created_at', path: admins_subjects_path) %>状态操作
    <%= list_index_no((params[:page] || 1).to_i, index) %> - <%= link_to(subject.name, "/paths/#{subject.id}", target: '_blank') %> - 首页 - 金课 - <%= subject.stages_count %><%= subject.shixuns_count %><%= subject.user.real_name %><%= subject.user.school_name %><%= subject.created_at&.strftime('%Y-%m-%d %H:%M') %> - <%= display_subject_status(subject) %> - - <%= javascript_void_link('隐藏', class: 'hide-action', data: { id: subject.id }, style: subject.hidden? ? 'display:none' : '') %> - <%= javascript_void_link('取消隐藏', class: 'active-action', data: { id: subject.id }, style: subject.hidden? ? '' : 'display:none') %> - - <%= delete_link '删除', admins_subject_path(subject, element: ".subject-item-#{subject.id}"), class: 'delete-subject-action' %> - - <% if subject.published? %> -
    - <%= javascript_void_link('更多', class: 'action dropdown-toggle', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false) %> - -
    - <% end %> -
    - -<%= render partial: 'admins/shared/paginate', locals: { objects: subjects } %> \ No newline at end of file diff --git a/app/views/admins/system_notifications/_form.html.erb b/app/views/admins/system_notifications/_form.html.erb new file mode 100644 index 000000000..33c35747a --- /dev/null +++ b/app/views/admins/system_notifications/_form.html.erb @@ -0,0 +1,57 @@ +
    +
    <%= type == "create" ? "新建" : "编辑" %>系统通知
    + <%= link_to "返回", admins_system_notifications_path, class: "btn btn-default pull-right" %> +
    + +
    + <%= form_for @notification, url: {controller: "system_notifications", action: "#{type}"} do |p| %> +
    + +
    + <%= p.text_field :subject, class: "form-control input-lg", placeholder: "请输入系统通知标题" %> +
    + +
    +
    + +
    + <%= p.text_field :sub_subject, class: "form-control input-lg", placeholder: "请输入系统通知副标题" %> +
    + +
    +
    + +
    + <%= p.text_area :content, class:"form-control", style: 'display: none;', rows: "10", cols: "20", placeholer: "请输入系统通知正文" %> +
    + +
    + +
    +
    + <%= p.check_box :is_top, class: "form-check-input", value:"true"%> + +
    +
    +
    + <%= p.submit "确认", class: "btn btn-primary submit-btn" %> +
    + <% end %> +
    \ No newline at end of file diff --git a/app/views/admins/system_notifications/_form_modal.html.erb b/app/views/admins/system_notifications/_form_modal.html.erb new file mode 100644 index 000000000..658bbc9c0 --- /dev/null +++ b/app/views/admins/system_notifications/_form_modal.html.erb @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/app/views/admins/system_notifications/_list.html.erb b/app/views/admins/system_notifications/_list.html.erb new file mode 100644 index 000000000..0d86ab035 --- /dev/null +++ b/app/views/admins/system_notifications/_list.html.erb @@ -0,0 +1,35 @@ + + + + + + + + + + + + + <% if notifications.present? %> + <% notifications.each_with_index do |notification, index| %> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
    序号标题副标题<%= sort_tag('是否置顶', name: 'is_top', path: admins_system_notifications_path) %><%= sort_tag('创建时间', name: 'created_at', path: admins_system_notifications_path) %>操作
    <%= list_index_no((params[:page] || 1).to_i, index) %><%= notification.subject %><%= notification.sub_subject %><%= notification.is_top ? '√' : '' %><%= notification.created_at&.strftime('%Y-%m-%d %H:%M') %> + <%= javascript_void_link '置顶', class: 'action unclose-action', data: { id: notification.id }, style: notification.is_top ? 'display: none;' : '' %> + <%= javascript_void_link '取消置顶', class: 'action close-action', data: { id: notification.id }, style: notification.is_top ? '' : 'display: none;' %> + <%= link_to "编辑", edit_admins_system_notification_path(notification), remote: true, class: "action" %> + <%= link_to "删除", admins_system_notification_path(notification), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %> +
    + +<%= render partial: 'admins/shared/paginate', locals: { objects: notifications } %> \ No newline at end of file diff --git a/app/views/admins/system_notifications/edit.js.erb b/app/views/admins/system_notifications/edit.js.erb new file mode 100644 index 000000000..e5929f876 --- /dev/null +++ b/app/views/admins/system_notifications/edit.js.erb @@ -0,0 +1,2 @@ +$("#admins-system-notification-content").html("<%= j render(partial: 'admins/system_notifications/form', locals: {type: 'update'}) %>") +createMDEditor('system-notification-content-editor', { height: 500, placeholder: '请输入邮件模版' }); \ No newline at end of file diff --git a/app/views/admins/system_notifications/index.html.erb b/app/views/admins/system_notifications/index.html.erb new file mode 100644 index 000000000..01a35f216 --- /dev/null +++ b/app/views/admins/system_notifications/index.html.erb @@ -0,0 +1,21 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('系统通知模版') %> +<% end %> + +
    +
    + <%= form_tag(admins_system_notifications_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_system_notification_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %> +
    + +
    +
    + +
    + <%= render partial: 'admins/system_notifications/list', locals: { notifications: @notifications } %> +
    +
    \ No newline at end of file diff --git a/app/views/admins/system_notifications/index.js.erb b/app/views/admins/system_notifications/index.js.erb new file mode 100644 index 000000000..a5cfec841 --- /dev/null +++ b/app/views/admins/system_notifications/index.js.erb @@ -0,0 +1 @@ +$('.system-notification-list-container').html("<%= j( render partial: 'admins/system_notifications/list', locals: { notifications: @notifications } ) %>"); \ No newline at end of file diff --git a/app/views/admins/system_notifications/new.js.erb b/app/views/admins/system_notifications/new.js.erb new file mode 100644 index 000000000..885357b5a --- /dev/null +++ b/app/views/admins/system_notifications/new.js.erb @@ -0,0 +1,2 @@ +$("#admins-system-notification-content").html("<%= j render(partial: 'admins/system_notifications/form', locals: {type: 'create'}) %>") +createMDEditor('system-notification-content-editor', { height: 500, placeholder: '请输入邮件模版' }); diff --git a/app/views/admins/tag_disciplines/adjust_position.js.erb b/app/views/admins/tag_disciplines/adjust_position.js.erb deleted file mode 100644 index 32e066698..000000000 --- a/app/views/admins/tag_disciplines/adjust_position.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% if @message.present? %> -$.notify({ message: "<%= @message %>" }); -<% else %> -$(".tag-discipline-list-container").html("<%= j(render :partial => 'admins/tag_disciplines/shared/list') %>"); -<% end %> \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/destroy.js.erb b/app/views/admins/tag_disciplines/destroy.js.erb deleted file mode 100644 index 0b61b7eb7..000000000 --- a/app/views/admins/tag_disciplines/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '删除成功' }); -$(".tag-discipline-item-<%= @tag_discipline_id %>").remove(); \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/edit.js.erb b/app/views/admins/tag_disciplines/edit.js.erb deleted file mode 100644 index 90a4d28d5..000000000 --- a/app/views/admins/tag_disciplines/edit.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.admin-modal-container').html("<%= j( render partial: 'admins/tag_disciplines/shared/edit_tag_discipline_modal', locals: { tag_discipline: @tag_discipline } ) %>"); -$('.modal.admin-edit-tag-discipline-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/index.html.erb b/app/views/admins/tag_disciplines/index.html.erb deleted file mode 100644 index 199137612..000000000 --- a/app/views/admins/tag_disciplines/index.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('课程方向', admins_disciplines_path) %> - <% add_admin_breadcrumb(@sub_discipline&.discipline&.name, admins_sub_disciplines_path(discipline_id: @sub_discipline&.discipline_id)) %> - <% add_admin_breadcrumb(@sub_discipline.name) %> -<% end %> - -
    - <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-tag-discipline-modal' } %> -
    - -
    - <%= render(partial: 'admins/tag_disciplines/shared/list') %> -
    - -<%= render 'admins/tag_disciplines/shared/create_tag_discipline_modal' %> diff --git a/app/views/admins/tag_disciplines/shared/_create_tag_discipline_modal.html.erb b/app/views/admins/tag_disciplines/shared/_create_tag_discipline_modal.html.erb deleted file mode 100644 index 33132285b..000000000 --- a/app/views/admins/tag_disciplines/shared/_create_tag_discipline_modal.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/shared/_edit_tag_discipline_modal.html.erb b/app/views/admins/tag_disciplines/shared/_edit_tag_discipline_modal.html.erb deleted file mode 100644 index 9eb50658c..000000000 --- a/app/views/admins/tag_disciplines/shared/_edit_tag_discipline_modal.html.erb +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/shared/_list.html.erb b/app/views/admins/tag_disciplines/shared/_list.html.erb deleted file mode 100644 index 59420c42c..000000000 --- a/app/views/admins/tag_disciplines/shared/_list.html.erb +++ /dev/null @@ -1,52 +0,0 @@ -<% max_position = @tag_disciplines.pluck(:position).max %> - - - - - - - - - - - - - - <% if @tag_disciplines.present? %> - <% @tag_disciplines.each do |tag| %> - - - - - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号知识点创建者实践课程实训题库操作
    <%= tag.position %><%= tag.name %> - <% if tag.user.present? %> - <%= link_to tag.user.real_name, user_path(tag.user), :target => "_blank" %> - <% else %> - -- - <% end %> - - <% disabled = !(tag.sub_discipline&.subject && tag.discipline&.subject) %> - <%= check_box_tag :subject,!tag.subject,tag.subject,disabled:disabled,remote:true,data:{id:tag.id},class:"tag-discipline-source-form" %> - - <% disabled = !(tag.sub_discipline&.shixun && tag.discipline&.shixun) %> - <%= check_box_tag :shixun,!tag.shixun,tag.shixun,disabled:disabled,remote:true,data:{id:tag.id},class:"tag-discipline-source-form" %> - - <% disabled = !(tag.sub_discipline&.question && tag.discipline&.question) %> - <%= check_box_tag :question,!tag.question,tag.question,disabled:disabled,remote:true,data:{id:tag.id},class:"tag-discipline-source-form" %> - - <%= javascript_void_link('上移', class: 'move-action', data: { id: tag.id, opr: "up" }, style: tag.position == 1 ? 'display:none' : '') %> - <%= javascript_void_link('下移', class: 'move-action', data: { id: tag.id, opr: "down" }, style: tag.position == max_position ? 'display:none' : '') %> - - <%= link_to '编辑', edit_admins_tag_discipline_path(tag), remote: true, class: 'action' %> - <%= delete_link '删除', admins_tag_discipline_path(tag, element: ".tag-discipline-item-#{tag.id}"), class: 'delete-tag-discipline-action' %> -
    \ No newline at end of file diff --git a/app/views/admins/tag_disciplines/update.js.erb b/app/views/admins/tag_disciplines/update.js.erb deleted file mode 100644 index b03f10477..000000000 --- a/app/views/admins/tag_disciplines/update.js.erb +++ /dev/null @@ -1,6 +0,0 @@ -<% if @message.present? %> -$.notify({ message: "<%= @message %>" }); -<% else %> -$('.modal.admin-edit-tag-discipline-modal').modal("hide"); -$(".tag-discipline-list-container").html("<%= j(render :partial => 'admins/tag_disciplines/shared/list') %>"); -<% end %> \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/destroy.js.erb b/app/views/admins/tag_repertoires/destroy.js.erb deleted file mode 100644 index 710f10ca9..000000000 --- a/app/views/admins/tag_repertoires/destroy.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$.notify({ message: '删除成功' }); -$(".tag-repertoire-item-<%= @tag_repertoire_id %>").remove(); \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/edit.js.erb b/app/views/admins/tag_repertoires/edit.js.erb deleted file mode 100644 index 5969eedf7..000000000 --- a/app/views/admins/tag_repertoires/edit.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.admin-modal-container').html("<%= j( render partial: 'admins/tag_repertoires/shared/edit_tag_repertoire_modal', locals: { tag_repertoire: @tag_repertoire } ) %>"); -$('.modal.admin-edit-tag-repertoire-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/index.html.erb b/app/views/admins/tag_repertoires/index.html.erb deleted file mode 100644 index 122cfc6f6..000000000 --- a/app/views/admins/tag_repertoires/index.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('技术体系', admins_repertoires_path) %> - <% add_admin_breadcrumb(@sub_repertoire&.repertoire&.name, admins_sub_repertoires_path(repertoire_id: @sub_repertoire&.repertoire_id)) %> - <% add_admin_breadcrumb(@sub_repertoire.name) %> -<% end %> - -
    - <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-tag-repertoire-modal' } %> -
    - -
    - <%= render(partial: 'admins/tag_repertoires/shared/list') %> -
    - -<%= render 'admins/tag_repertoires/shared/create_tag_repertoire_modal' %> diff --git a/app/views/admins/tag_repertoires/shared/_create_tag_repertoire_modal.html.erb b/app/views/admins/tag_repertoires/shared/_create_tag_repertoire_modal.html.erb deleted file mode 100644 index f952762e4..000000000 --- a/app/views/admins/tag_repertoires/shared/_create_tag_repertoire_modal.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/shared/_edit_tag_repertoire_modal.html.erb b/app/views/admins/tag_repertoires/shared/_edit_tag_repertoire_modal.html.erb deleted file mode 100644 index 3be94dd05..000000000 --- a/app/views/admins/tag_repertoires/shared/_edit_tag_repertoire_modal.html.erb +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/shared/_list.html.erb b/app/views/admins/tag_repertoires/shared/_list.html.erb deleted file mode 100644 index 3d8047f8d..000000000 --- a/app/views/admins/tag_repertoires/shared/_list.html.erb +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - <% if @tag_repertoires.present? %> - <% @tag_repertoires.each_with_index do |tag, index| %> - - - - - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号知识标签操作
    <%= index + 1 %><%= tag.name %> - <%= link_to '编辑', edit_admins_tag_repertoire_path(tag), remote: true, class: 'action' %> - <%= delete_link '删除', admins_tag_repertoire_path(tag, element: ".tag-repertoire-item-#{tag.id}"), class: 'delete-tag-repertoire-action' %> -
    \ No newline at end of file diff --git a/app/views/admins/tag_repertoires/update.js.erb b/app/views/admins/tag_repertoires/update.js.erb deleted file mode 100644 index a55f7f3b9..000000000 --- a/app/views/admins/tag_repertoires/update.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('.modal.admin-edit-tag-repertoire-modal').modal("hide"); -$(".tag-repertoire-list-container").html("<%= j(render :partial => 'admins/tag_repertoires/shared/list') %>"); \ No newline at end of file diff --git a/app/views/admins/unit_applies/edit.js.erb b/app/views/admins/unit_applies/edit.js.erb deleted file mode 100644 index 15fc1f4c2..000000000 --- a/app/views/admins/unit_applies/edit.js.erb +++ /dev/null @@ -1,56 +0,0 @@ -$("body").append("<%= j render partial: "admins/unit_applies/shared/edit_modal",locals: {apply: @unit_apply, schools: @all_schools} %>") -var uni_edit_modal = $(".admin-unit-edit-modal") -uni_edit_modal.modal("show") - -uni_edit_modal.on("hidden.bs.modal",function () { - $(".admin-unit-edit-modal").remove() - $("body").removeClass("modal-open") -}) - -// 初始化学校选择器 -var matcherFunc = function(params, data){ - if ($.trim(params.term) === '') { - return data; - } - if (typeof data.text === 'undefined') { - return null; - } - if (data.name && data.name.indexOf(params.term) > -1) { - var modifiedData = $.extend({}, data, true); - return modifiedData; - } - - // Return `null` if the term should not be displayed - return null; -} -$.ajax({ - url: '/api/schools/for_option.json', - dataType: 'json', - type: 'GET', - success: function(data) { - $("#all-schools").select2({ - theme: 'bootstrap4', - placeholder: '查询学校/单位', - minimumInputLength: 1, - data: data.schools, - templateResult: function (item) { - if(!item.id || item.id === '') return item.text; - return item.name; - }, - templateSelection: function(item){ - return item.name || item.text; - }, - matcher: matcherFunc - }) - } -}); - -$("#all-schools").select2({}) -$("#show-province-<%= @unit_apply.id %>").select2() -$("#schoolCity_<%= @unit_apply.id %>").select2() - -// **************** 地区选择 **************** -$('.province-city-select').cxSelect({ - url: '/javascripts/educoder/province-data.json', - selects: ['province-select', 'city-select'] -}); \ No newline at end of file diff --git a/app/views/admins/unit_applies/index.html.erb b/app/views/admins/unit_applies/index.html.erb deleted file mode 100644 index 2b715b87c..000000000 --- a/app/views/admins/unit_applies/index.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -<% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('单位审批') %> -<% end %> - -
    - <%= form_tag(admins_unit_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_unit_applies_path(keyword:nil),class:"btn btn-default",remote:true %> - <% end %> -
    - -
    - <%= render(partial: 'admins/unit_applies/shared/list', locals: { applies: @unit_applies }) %> -
    - -<%= render(partial: 'admins/shared/admin_common_refuse_modal') %> diff --git a/app/views/admins/unit_applies/index.js.erb b/app/views/admins/unit_applies/index.js.erb deleted file mode 100644 index d9297d51a..000000000 --- a/app/views/admins/unit_applies/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -$(".unit-applies-list-container").html("<%= j render partial: "admins/unit_applies/shared/list", locals: {applies: @unit_applies} %>") diff --git a/app/views/admins/unit_applies/shared/_apply_item.html.erb b/app/views/admins/unit_applies/shared/_apply_item.html.erb deleted file mode 100644 index b7d38b776..000000000 --- a/app/views/admins/unit_applies/shared/_apply_item.html.erb +++ /dev/null @@ -1,18 +0,0 @@ -<%= list_index_no((params[:page] || 1).to_i, index) %> -<%= apply.id %> -<%= overflow_hidden_span apply.name %> - - <%= "#{apply&.province.to_s}"+"#{apply&.city.to_s}" %> - -<%= overflow_hidden_span apply.address %> -<%= link_to apply&.user&.real_name, "/users/#{apply&.user&.login}", target: "_blank" %> -<%= format_time apply.created_at %> - - <%= agree_link '批准', agree_admins_unit_apply_path(apply, element: ".unit-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_unit_apply_path(apply, tip: "unapplied", element: ".unit-apply-#{apply.id}") - }) %> - <%= link_to "更改",edit_admins_unit_apply_path(apply), remote: true, class:"action",'data-disable-with': '打开中...' %> - \ No newline at end of file diff --git a/app/views/admins/unit_applies/shared/_edit_modal.html.erb b/app/views/admins/unit_applies/shared/_edit_modal.html.erb deleted file mode 100644 index 6f8995ae0..000000000 --- a/app/views/admins/unit_applies/shared/_edit_modal.html.erb +++ /dev/null @@ -1,43 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/unit_applies/shared/_list.html.erb b/app/views/admins/unit_applies/shared/_list.html.erb deleted file mode 100644 index 75b9c720b..000000000 --- a/app/views/admins/unit_applies/shared/_list.html.erb +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - <% if applies.present? %> - <% applies.each_with_index do |apply, index| %> - - <%= render partial: "admins/unit_applies/shared/apply_item", locals: {apply: apply, index: index} %> - - <% end %> - <% else %> - <%= render 'admins/shared/no_data_for_table' %> - <% end %> - -
    序号ID单位名称地区详细地址申请者<%= sort_tag('创建于', name: 'created_at', path: admins_unit_applies_path) %>操作
    - -<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %> \ No newline at end of file diff --git a/app/views/admins/unit_applies/update.js.erb b/app/views/admins/unit_applies/update.js.erb deleted file mode 100644 index c710f46b5..000000000 --- a/app/views/admins/unit_applies/update.js.erb +++ /dev/null @@ -1,3 +0,0 @@ -$('.modal.admin-unit-edit-modal').modal('hide'); -$('.unit-applies-list-table .unit-apply-<%= @unit_apply.id %>').remove() -$.notify({ message: '操作成功' }); \ No newline at end of file diff --git a/app/views/admins/users/edit.html.erb b/app/views/admins/users/edit.html.erb index 5abc82711..44d524997 100644 --- a/app/views/admins/users/edit.html.erb +++ b/app/views/admins/users/edit.html.erb @@ -7,8 +7,8 @@