Compare commits

..

134 Commits

Author SHA1 Message Date
vilet.yy ce89ce5169 fix:use concat_ws 2021-04-02 11:39:55 +08:00
vilet.yy b8a4c467fe fix 2021-04-02 11:29:30 +08:00
vilet.yy 300658f8dd fix: apply_signature filter 2021-04-02 11:18:28 +08:00
vilet.yy 9553740960 add: project order index 2021-03-17 15:47:01 +08:00
vilet.yy 1a8d9bb0ce [ADD]add police picture 2021-03-11 10:54:01 +08:00
vilet.yy 8c43f74b69 [ADD]job use model data 2021-03-10 14:11:56 +08:00
vilet.yy 3e7ae82258 [ADD]phenglei user list and cron job 2021-03-10 14:02:41 +08:00
vilet.yy 0aa75e077e [ADD]sync phenglei user job 2021-03-05 17:04:06 +08:00
vilet.yy 8aefcad510 [ADD]create project member rake 2021-03-05 17:04:06 +08:00
vilet.yy 622dcbaf4f Merge branch 'dev_military' of https://git.trustie.net/jasder/forgeplus into dev_military 2021-03-05 17:03:01 +08:00
jasder d91e8dcbfe Merge branch 'dev_military' of https://git.trustie.net/jasder/forgeplus into dev_military 2021-03-05 15:38:06 +08:00
jasder 0c2507b1e9 FIX valid user before register action 2021-03-05 15:37:41 +08:00
vilet.yy 8d29c2bd50 [FIX]org visit phenglei project 2021-03-05 09:50:03 +08:00
vilet.yy 774f632d9a Merge branch 'develop' into dev_military 2021-03-04 13:42:45 +08:00
vilet.yy 2969afd333 [FIX]project category correct projects_count 2021-03-01 16:23:29 +08:00
vilet.yy cc978c8dea [FIX]merge from develop 2021-03-01 13:59:30 +08:00
vilet.yy ce105b4c07 [FIX]project category not include private repo 2021-02-26 16:20:26 +08:00
vilet.yy b5870b1020 [FIX]lose role_name 2021-02-26 15:00:40 +08:00
vilet.yy 1edb3ce7ad [FIX]search projects error 2021-02-25 12:11:32 +08:00
jasder 59257b1caa FIX repo setting api for forbidden 2021-02-09 11:50:12 +08:00
Jasder b552e29aa3 ADD forge host and main web host for setting api 2021-02-04 11:43:11 +08:00
Jasder 21424a23f2 FIX change host 2021-02-04 11:12:51 +08:00
Jasder a82af669bd Merge branch 'dev_military' of http://git.trustie.net/jasder/forgeplus into dev_military 2021-01-28 15:22:53 +08:00
Jasder 0f01abd45f Merge branch 'develop' into dev_military 2021-01-28 15:21:43 +08:00
viletyy 80002be670 [FIX]项目列表total_count 2021-01-28 14:45:33 +08:00
Jasder f7e19cb3a4 Merge branch 'develop' into dev_military 2021-01-14 18:39:31 +08:00
Jasder 5cd6620413 Merge branch 'develop' into dev_military 2021-01-14 18:26:04 +08:00
Jasder f3a9124bdd Merge branch 'develop' into dev_military 2021-01-14 18:23:26 +08:00
Jasder d97a39a3a2 Merge branch 'develop' into dev_military 2021-01-14 17:05:50 +08:00
Jasder 987ff74690 FIX merge 2021-01-13 14:42:26 +08:00
Jasder 37be604e82 FIX [api] get pull files and commits bug 2021-01-13 14:40:23 +08:00
viletyy 83e2c1f889 [FIX]merge 2021-01-13 14:38:02 +08:00
viletyy 46a1c8877b [FIX]pull_request bug 2021-01-13 11:26:21 +08:00
Jasder 0aa39efe9b FIX code bug 2021-01-12 18:25:50 +08:00
Jasder 15d562d7b1 FIX delete batch import users with admin managerment 2021-01-12 18:15:01 +08:00
Jasder 5b261d6e81 FIX merge develop branch 2021-01-12 17:42:44 +08:00
viletyy 4693e77e02 [FIX] 2021-01-11 18:43:22 +08:00
viletyy fbf22ff0df [FIX]增加是否为成员参数 2021-01-11 17:52:58 +08:00
Jasder 0794f77a87 Merge branch 'develop' into dev_military 2021-01-06 14:00:51 +08:00
Jasder e5a46a242f FIX register with validate email 2021-01-06 11:03:00 +08:00
Jasder 4902237bd7 Merge branch 'dev_military_license' of http://git.trustie.net/jasder/forgeplus into dev_military_license 2021-01-06 10:44:37 +08:00
Jasder 4ddc60a1c3 FIX user register bug 2021-01-06 10:44:20 +08:00
viletyy cfa14fff9d [FIX] 2021-01-04 17:52:05 +08:00
viletyy ef327f2994 [FIX] 2021-01-04 16:19:11 +08:00
viletyy bf91c5e382 [FIX] 2021-01-04 15:32:44 +08:00
viletyy 9b687f7885 [FIX] 2021-01-04 15:22:03 +08:00
viletyy a072162324 [ADD]项目创建者审核申请 2021-01-04 12:27:12 +08:00
viletyy 8f1e0f39ea Merge branch 'dev_military_license' of https://git.trustie.net/jasder/forgeplus into dev_military_license 2020-12-31 14:03:06 +08:00
viletyy aaa6483958 [FIX]几处bug修复 2020-12-31 14:02:37 +08:00
Jasder bf730ca18f Merge branch 'dev_military_license' of http://git.trustie.net/jasder/forgeplus into dev_military_license 2020-12-29 18:20:46 +08:00
Jasder 132af875bc Merge branch 'master' into dev_military_license 2020-12-29 18:19:07 +08:00
viletyy a862d994ab [FIX]只有审核成功才添加成员 2020-12-29 18:08:10 +08:00
Jasder 604da93c5c FIX when add members to project, permission set to readable 2020-12-29 17:17:36 +08:00
Jasder 3f525f5779 FIX update model schema 2020-12-29 14:25:40 +08:00
viletyy 05d1e66ea9 [FIX] 2020-12-28 20:29:56 +08:00
viletyy 10c1cccf2c [FIX] 2020-12-28 19:42:59 +08:00
viletyy 27ec7ec7dd [ADD]simple去除访问限制,并加入字段 2020-12-28 18:41:28 +08:00
Jasder 43b4907565 Merge branch 'dev_military_license' of http://git.trustie.net/jasder/forgeplus into dev_military_license 2020-12-28 14:53:52 +08:00
Jasder cb90e1a13f FIX get branches bug 2020-12-28 14:53:30 +08:00
viletyy 749cd058c4 [FIX] 2020-12-28 12:57:58 +08:00
viletyy 47cc70f2c5 [ADD]增加下载文件接口 2020-12-28 12:31:05 +08:00
viletyy 5447d54d30 [FIX] 2020-12-28 10:26:50 +08:00
viletyy 6c436dd631 [ADD]后台审核特殊许可申请 2020-12-27 18:44:03 +08:00
viletyy 9eb7219b9a [FIX] 2020-12-25 18:58:03 +08:00
viletyy ad5fcb25c4 [ADD]接口文档 2020-12-25 17:51:42 +08:00
viletyy d42053ce0c [FIX]merge 2020-12-25 16:33:16 +08:00
viletyy 36bae71947 [ADD]增加特殊许可的验证 2020-12-25 16:17:46 +08:00
Jasder 837aa1ea9e FIX Merge master branch 2020-12-25 15:10:50 +08:00
Sylor-huang c283c7ed58 add: dun_check text and image 2020-11-30 19:36:30 +08:00
sylor_huang@126.com 4cf8588343 Reset Issue Closed_count 2020-09-27 11:17:22 +08:00
sylor_huang@126.com e75fad98f8 change admin projects 2020-09-18 13:41:44 +08:00
sylor_huang@126.com bc37c59f00 Change Header4 2020-09-16 15:08:35 +08:00
sylor_huang@126.com a6a745da93 Change Header1 2020-09-16 14:58:12 +08:00
sylor_huang@126.com 5bef80ee58 Change Index Category 2020-09-11 18:32:42 +08:00
sylor_huang@126.com f9bcc7e02b Close DunCheck 2020-09-07 16:33:26 +08:00
sylor_huang@126.com d35faf3935 Fix:Issues 2020-08-21 11:30:47 +08:00
sylor_huang@126.com 8d7dc9cb60 Test Push 2020-08-21 09:52:31 +08:00
sylor_huang@126.com 248d78d8c1 Merge branch 'dev_trustie' into dev_military 2020-08-20 18:10:07 +08:00
sylor_huang@126.com f632424f13 Change Like 2020-08-20 11:00:19 +08:00
sylor_huang@126.com 95ede63220 Change 2020-08-19 17:58:04 +08:00
sylor_huang@126.com 8fac294d04 Add UserAction Ip 2020-08-18 18:16:58 +08:00
sylor_huang@126.com d67c12beba Ignore migrate files 2020-08-18 18:10:05 +08:00
sylor_huang@126.com a7e4b85352 Change Confilct 2020-08-18 17:54:35 +08:00
Jasder 2ac2920399 FIX merge dev_trustie branch 2020-08-18 17:39:37 +08:00
Jasder 230b934de4 Update remote register forr military platform 2020-08-18 17:33:12 +08:00
sylor_huang@126.com e0bedf175f Change Dun Check 2020-08-18 11:02:09 +08:00
sylor_huang@126.com c9a263e03c Add Dun Check For Project 2020-08-18 10:36:13 +08:00
Jasder 2bd15d9746 Merge branch 'dev_trustie' into dev_military 2020-08-17 18:52:00 +08:00
sylor_huang@126.com fc9588fb63 Add Dun Check 2020-08-17 18:49:18 +08:00
sylor_huang@126.com e611b519ab Fix: Admins page remove .educoer.net words 2020-08-13 14:21:13 +08:00
sylor_huang@126.com 3dd3944ebd Fix: Unknow attribute private for project 2020-08-13 13:50:07 +08:00
sylor_huang@126.com f417bf3308 Change User Defautl Picture 2020-08-13 10:01:13 +08:00
sylor_huang@126.com 9c7c914d12 Change 2020-08-12 18:07:43 +08:00
sylor_huang@126.com b088befae7 Change 2020-08-12 16:39:10 +08:00
sylor_huang@126.com d3636e686b CHange 2020-08-12 16:27:42 +08:00
sylor_huang@126.com 88d98f0ac4 Change 2020-08-12 16:24:30 +08:00
sylor_huang@126.com db6aa954b1 Change 2020-08-12 16:18:16 +08:00
sylor_huang@126.com 04a611a4aa Change 2020-08-12 16:01:42 +08:00
sylor_huang@126.com 9ecea83506 Change 2020-08-12 15:43:55 +08:00
sylor_huang@126.com 82a9907fdc change 2020-08-12 15:31:56 +08:00
sylor_huang@126.com c56c98fd6e Change 2020-08-12 15:30:39 +08:00
sylor_huang@126.com 2948ad2033 Change 2020-08-12 15:28:09 +08:00
sylor_huang@126.com fc611140cf change 2020-08-12 15:25:16 +08:00
sylor_huang@126.com fcb5f58b69 change 2020-08-12 15:15:44 +08:00
sylor_huang@126.com 0f38a130f3 Change 2020-08-12 15:12:26 +08:00
sylor_huang@126.com fc54632a08 Change 2020-08-12 14:45:45 +08:00
sylor_huang@126.com 5963af5c7b Change Sidekiq 2020-08-12 14:41:53 +08:00
sylor_huang@126.com c1f2f7f6e2 Build 2020-08-12 14:06:32 +08:00
sylor_huang@126.com 271699daf1 Change 2020-08-12 11:54:20 +08:00
sylor_huang@126.com 98da7ea34d Change 2020-08-12 11:49:55 +08:00
sylor_huang@126.com 645e4a3586 Change 2020-08-12 11:45:57 +08:00
sylor_huang@126.com 7beca24a05 Change 2020-08-12 11:42:22 +08:00
sylor_huang@126.com d1368c7612 Change 2020-08-12 11:14:37 +08:00
sylor_huang@126.com 28e762810e Set 2020-08-12 10:45:54 +08:00
sylor_huang@126.com 0f60d0adc9 Change 2020-08-11 17:13:42 +08:00
sylor_huang@126.com e634317675 CHnage 2020-08-11 17:11:56 +08:00
sylor_huang@126.com 6b1a0a96c6 CHange 2020-08-11 17:09:48 +08:00
sylor_huang@126.com 298859bd10 Change 2020-08-11 17:07:15 +08:00
sylor_huang@126.com d4d412ab40 Change 2020-08-11 17:00:56 +08:00
sylor_huang@126.com 57d1a1474e Change 2020-08-11 16:21:43 +08:00
sylor_huang@126.com 055b7dbac5 Change 2020-08-11 15:56:37 +08:00
sylor_huang@126.com 30aad87e5a Change 2020-08-11 15:49:03 +08:00
sylor_huang@126.com aecd68fe9a Chnage 2020-08-11 15:44:10 +08:00
sylor_huang@126.com 998a6828d9 change 2020-08-11 15:34:50 +08:00
sylor_huang@126.com 12c04d02e5 Change 2020-08-11 15:30:12 +08:00
sylor_huang@126.com d6ef3d8aa3 Change 2020-08-11 15:23:49 +08:00
sylor_huang@126.com c7a89d1660 Change 2020-08-11 14:49:53 +08:00
sylor_huang@126.com 1939c0d33f Set Auto Login 2020-08-11 11:28:49 +08:00
Jasder 561b9efd92 FIX change manager main site url 2020-08-10 12:08:00 +08:00
Jasder 6c0b87fdd1 FIX bug 2020-08-10 11:26:15 +08:00
Jasder 5d309d1dc4 FIX bug 2020-08-10 11:24:59 +08:00
Jasder 89c230c362 FIX 处理顶部导航错误的问题 2020-08-10 11:23:01 +08:00
Jasder d4156a5582 Delete some url with setting api 2020-08-09 22:07:16 +08:00
Jasder ee8cbb8553 FIX 调整云上实验配置 2020-08-07 14:34:26 +08:00
246 changed files with 20442 additions and 4087 deletions

4
.gitignore vendored
View File

@ -36,7 +36,6 @@ public/react/yarn.lock
/.idea/*
# Ignore react node_modules
public/system/*
public/react/*
/public/react/.cache
/public/react/node_modules/
@ -83,5 +82,4 @@ docker/
educoder.sql
redis_data/
Dockerfile
dump.rdb
.tags*
dump.rdb

View File

@ -1,53 +0,0 @@
# Changelog
## [v3.0.2](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-04-23
* BUGFIXES
* Fix 解决部分用户头像不显示问题
* Fix 解决代码库模块中最左侧目录中的文件定位加载不准确的问题
* FIX 解决团队管理页面中项目链接错误问题
* Fix 解决markdown格式文件显示问题
* Fix 解决组织名下创建项目报错的问题
* Fix 解决组织名下的项目创建issue报错的问题
* Fix 解决组织名下创建团队提示信息信息显示错误问题
* Fix 解决点击组织图片时,链接加载错误问题
* Fix 修复查询版本库信息安全漏洞
* Fix 解决修复团队成员操作访问组织仓库报403错误的问题
* Fix 解决owners团队成员对仓库添加成功失败的问题
* ENHANCEMENTS
* ADD 自动生产用户头像功能
* ADD 创建组织支持中文名称
* ADD 创建团建支持中文名称
* ADD 组织名称统一显示中文名
* ADD 团队名称统一显示中文名
* ADD 用户头像悬浮时展示相关信息
* ADD 项目详情页添加实践课程链接入口
* ADD README文件页面添加添加目录导航功能
* UPDATE 升级改版底部footer信息
* UPDATE 升级用户操作版本库权限
## [v3.0.1](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-03-19
* BUGFIXES
* Fix pull reqeust模块中用户头像显示问题
* Fix 解决issue模块中指派用户的问题
* Fix 解决合并请求失败的后显示message信息不正确
* Fix 代码目录页面readme文件提供单独的api
* ENHANCEMENTS
* 重构项目详情页面
## [v3.0.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2020-12-29
* BUGFIXES
* Fix pull reqeust的访问权限问题 (#14156) (#14171)
* Fix 部分页面访问403的问题
* Fix 合并请求失败的问题
* Fix 代码目录页面,文件夹和文件图片不显示的问题
* Fix Issue列表中按负责人过滤筛选时部分项目成员不在搜索范围没的问题
* Fix 项目更新时间不同步的问题, 添加了定时任务
* ENHANCEMENTS
* 提升获取版本库目录代码查询速度 (#43296)
* tag 列表慢查询速度问题 (#43332)
* API builder 模版中 render partial builder的性能问题

View File

@ -126,5 +126,3 @@ gem 'request_store'
gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar'

View File

@ -162,7 +162,6 @@ GEM
activerecord
kaminari-core (= 1.2.0)
kaminari-core (1.2.0)
letter_avatar (0.3.8)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@ -457,7 +456,6 @@ DEPENDENCIES
jbuilder (~> 2.5)
jquery-rails
kaminari (~> 1.1, >= 1.1.1)
letter_avatar
listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.4, < 0.6.0)
oauth2

View File

@ -11,32 +11,13 @@ Trustie (确实)是一个以大众化协同开发、开放式资源共享、
## 部署
### Depends Versions
* Ruby 2.4.5
* Rails ~> 5.2
* MySql ~> 5.6
* Redis 5+
* imagemagick
### Steps
#### 1. 克隆稳定版本
```
git clone -b standalone https://git.trustie.net/jasder/forgeplus.git
```
#### 2. 安装依赖包
### 1. 安装依赖包
```bash
cd forgeplus && bundle install
bundle install
```
#### 3. 配置初始化文件
### 2. 配置初始化文件
进入项目根目录执行一下命令:
```bash
@ -46,26 +27,12 @@ touch config/redis.yml
touch config/elasticsearch.yml
```
#### 4. 配置数据库
数据库配置信息请查看/config/database.yml文件
项目默认采用mysql数据库, 如需更改,请自行修改配置信息,
默认配置如下:
```bash
default: &default
adapter: mysql2
host: 127.0.0.1
encoding: utf8
username: root
password: 123456
```
#### 5. 配置gitea服务(可选)
### 3. 配置gitea服务(可选)
**如需要部署自己的gitea平台请参考gitea官方平台https://docs.gitea.io/zh-cn/install-from-binary/**
**因目前gitea平台api受限暂时推荐从forge平台获取gitea部署文件进行部署https://forgeplus.trustie.net/projects/Trustie/gitea-binary**
**因目前gitea平台api受限暂时推荐从forge平台获取gitea部署文件进行部署https://forgeplus.trustie.net/projects/jasder/gitea-binary
**配置gitea服务步骤**
#### 配置gitea服务步骤
1. 部署gitea服务并注册root账户
2. 修改forge平台的 config/configuration.yml中的gitea服务指向地址
@ -77,93 +44,75 @@ gitea:
base_url: '/api/v1'
```
#### 6. 安装redis环境
### 4. 安装redis环境
**请自行搜索各平台如何安装部署redis环境**
#### 7. 安装imagemagick插件
- Mac OS X
### 5. 创建数据库
```bash
brew install imagemagick ghostscript
rails db:create
```
- Linux
```bash
sudo apt-get install -y imagemagick
```
#### 8. 创建数据库
**开发环境为development 生成环境为production**
```bash
rails db:create RAILS_ENV=development
```
#### 9. 导入数据表结构
### 6. 导入数据表结构
```bash
bundle exec rake sync_table_structure:import_csv
```
#### 10. 执行migrate迁移文件
### 7. 执行migrate迁移文件
**开发环境为development 生成环境为production**
```bash
rails db:migrate RAILS_ENV=development
```
#### 11. clone前端代码
**将前端代码克隆到public/react目录下目录结构应该是: public/react/build**
```bash
git clone -b standalone https://git.trustie.net/jasder/build.git
```
#### 12. 启动redis(此处已mac系统为例)
### 8. 启动redis(此处已mac系统为例)
```bash
redis-server&
```
#### 13. 启动sidekiq
### 9. 启动sidekiq
**开发环境为development 生成环境为production**
```bash
bundle exec sidekiq -C config/sidekiq.yml -e production -d
```
#### 14. 启动rails服务
### 10. 启动rails服务
```bash
rails s
```
#### 15. 浏览器访问
### 11. 浏览器访问
在浏览器中输入如下地址访问:
```bash
http://localhost:3000/
```
#### 16. 其他说明
通过页面注册都第一个用户为平台管理员用户
## 页面展示
- 代码库
![](docs/figs/code.png?raw=true)
![](docs/figs/code.png)
- 任务管理
![](docs/figs/issue_manage.png?raw=true)
![](docs/figs/issue_manage.png)
- 任务查看
![](docs/figs/issue_view.png?raw=true)
![](docs/figs/issue_view.png)
- 任务指派
![](docs/figs/issue_assign2.png?raw=true)
![](docs/figs/issue_assign2.png)
- 里程碑
![](docs/figs/milestone.png?raw=true)
![](docs/figs/milestone.png)
### API
- [API文档](https://forgeplus.trustie.net/docs/api)
- [API](api_document.md)
- [API](showdoc.com.cn)
账号forgeplus@admin.com 密码forge123

View File

@ -1,3 +1,4 @@
---
# API文档
@ -18,6 +19,7 @@
### API接口
---
#### 用户注册(通过其他平台)
```
@ -284,6 +286,7 @@ http://localhost:3000/api/licenses/ | jq
|licenses|array |返回数据|
|-- id |int |id |
|-- name |string|开源许可证名称|
|-- is_secret |string|是否为特殊许可证|
返回值
@ -292,23 +295,33 @@ http://localhost:3000/api/licenses/ | jq
"licenses": [
{
"id": 57,
"name": "AFL-1.2"
"name": "AFL-1.2",
"is_secret": false
},
{
"id": 76,
"name": "AFL-3.0"
"name": "AFL-3.0",
"is_secret": false
},
{
"id": 214,
"name": "AFL-1.1"
"name": "AFL-1.1",
"is_secret": false
},
{
"id": 326,
"name": "AFL-2.1"
"name": "AFL-2.1",
"is_secret": false
},
{
"id": 350,
"name": "AFL-2.0"
"name": "AFL-2.0",
"is_secret": false
},
{
"id": 359,
"name": "PHengLEI",
"is_secret": true
}
]
}
@ -554,6 +567,8 @@ curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq
|project_category_id |int|项目类别id|
|project_language_id |int|项目语言id|
|private |boolean|项目是否私有, true为私有false: 公开 |
|is_secret |boolean|项目是否为特殊协议项目, truefalse: 否 |
返回值
@ -566,7 +581,8 @@ curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq
"project_description": "my first project mirror_demo",
"project_category_id": 1,
"project_language_id": 2,
"private": false
"private": false,
"is_secret": true
}
```
---
@ -1146,6 +1162,7 @@ http://localhost:3000/api/projects | jq
|forked_count |int|被fork的数量|
|praises_count |int|star数量|
|is_public |boolean|是否公开, true:公开false:未公开|
|is_secret |boolean|是否为特殊许可证项目, true:是false:否|
|mirror_url |string|镜像url|
|last_update_time|int|最后更新时间为UNIX格式的时间戳|
|author |object|项目创建者|
@ -1156,6 +1173,10 @@ http://localhost:3000/api/projects | jq
|language |object|项目语言|
|-- id |int|项目语言id|
|-- name |string|项目语言名称|
|user_apply_signatures |object|用户创建的特殊许可申请|
|-- id |int|用户创建的特殊许可申请id|
|-- status |int|用户创建的特殊许可申请审核状态, 'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
返回值
@ -1171,6 +1192,7 @@ http://localhost:3000/api/projects | jq
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"is_secret": true,
"mirror_url": null,
"last_update_time": 1577697461,
"author": {
@ -1184,7 +1206,13 @@ http://localhost:3000/api/projects | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[
{
"id": 1,
"status": "waiting"
}
]
},
{
"id": 2,
@ -1194,6 +1222,7 @@ http://localhost:3000/api/projects | jq
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"is_secret": false,
"mirror_url": null,
"last_update_time": 1577697403,
"author": {
@ -1207,7 +1236,8 @@ http://localhost:3000/api/projects | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[]
},
{
"id": 3,
@ -1217,6 +1247,7 @@ http://localhost:3000/api/projects | jq
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"is_secret": true,
"mirror_url": null,
"last_update_time": 1577415173,
"author": {
@ -1230,7 +1261,8 @@ http://localhost:3000/api/projects | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[]
},
{
"id": 5,
@ -1240,6 +1272,7 @@ http://localhost:3000/api/projects | jq
"praises_count": 0,
"forked_count": 0,
"is_public": false,
"is_secret": true,
"mirror_url": "https://gitea.com/CasperVector/slew.git",
"last_update_time": 1577346228,
"author": {
@ -1253,7 +1286,8 @@ http://localhost:3000/api/projects | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[]
},
{
"id": 7,
@ -1263,6 +1297,7 @@ http://localhost:3000/api/projects | jq
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"is_secret": true,
"mirror_url": null,
"last_update_time": 1577341572,
"author": {
@ -1276,7 +1311,8 @@ http://localhost:3000/api/projects | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[]
}
]
}
@ -4828,133 +4864,8 @@ curl --location --request DELETE 'http://localhost:3000/api/ci/templates/10'
------
#### 参数列表查询
```
GET /api/ci/secrets/secrets?owner={owner}&repo={repo}
```
*示例*
```bash
curl --location --request GET 'http://localhost:3000/api/ci/secrets?owner=test&repo=test'
```
*请求参数说明:*
| 参数名 | 必选 | 类型 | 说明 |
| ------ | ---- | ------ | ---------- |
| owner | 是 | string | 仓库所有人 |
| repo | 是 | string | 仓库名 |
*返回参数说明:*
| 参数名 | 类型 | 说明 |
| ------ | ------ | ------ |
| name | string | 参数名 |
| data | string | 参数值 |
| repo | string | 仓库 |
返回值
```json
[
{
"id": 1,
"name": "test",
"data": "test",
"repo": "test"
}
]
```
------
#### 参数新增/更新
```
POST /api/ci/secrets?owner={owner}&repo={repo}
```
*示例*
```bash
curl --location --request POST 'http://localhost:3000/api/ci/secrets?owner=test&repo=test' \
--data-raw ' {
"name": "ip",
"data": "1.1.1.1",
"id": 21
}'
```
*请求参数说明:*
| 参数名 | 必选 | 类型 | 说明 |
| ------ | ---- | ------ | ------------ |
| owner | 是 | string | 仓库拥有者 |
| repo | 是 | string | 仓库名 |
| name | 是 | string | 参数名 |
| data | 是 | string | 参数值 |
| id | 否 | int | id更新时传 |
*返回参数说明:*
| 参数名 | 类型 | 说明 |
| ------- | ------ | ------------ |
| status | int | 状态码 0成功 |
| message | string | 消息 |
返回值
```json
{
"status": 0,
"message": "success"
}
```
------
#### 参数删除
```
DELETE /api/ci/secrets/{id}?name={name}&owner={owner}&repo={repo}
```
*示例*
```bash
curl --location --request DELETE 'http://localhost:3000/api/ci/secrets/1?name=p1&owner=victor&repo=trustieTest' \
```
*请求参数说明:*
| 参数名 | 必选 | 类型 | 说明 |
| ------ | ---- | ------ | ------ |
| name | 是 | string | 参数名 |
| id | 是 | int | 参数id |
*返回参数说明:*
| 参数名 | 类型 | 说明 |
| ------- | ------ | ------------ |
| status | int | 状态码 0成功 |
| message | string | 返回消息 |
返回值
```json
{
"status": 0,
"message": "success"
}
```
------
#### 解除CI服务器绑定
```
@ -5016,6 +4927,7 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|forked_count |int|被fork的数量|
|praises_count |int|star数量|
|is_public |boolean|是否公开, true:公开false:未公开|
|is_secret |boolean|是否为特殊许可证项目, true:是false:否|
|mirror_url |string|镜像url|
|last_update_time|int|最后更新时间为UNIX格式的时间戳|
|author |object|项目创建者|
@ -5026,7 +4938,9 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|language |object|项目语言|
|-- id |int|项目语言id|
|-- name |string|项目语言名称|
|user_apply_signatures |object|用户创建的特殊许可申请|
|-- id |int|用户创建的特殊许可申请id|
|-- status |int|用户创建的特殊许可申请审核状态, 'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
返回值
```json
@ -5041,6 +4955,7 @@ http://localhost:3000/api/users/Jason/projects.json | jq
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"is_secret": false,
"mirror_url": null,
"last_update_time": 1577697461,
"author": {
@ -5054,9 +4969,163 @@ http://localhost:3000/api/users/Jason/projects.json | jq
"language": {
"id": 2,
"name": "C"
}
},
"user_apply_signatures":[
{
"id": 1,
"status": "waiting"
}
]
}
]
}
```
---
#### 特殊许可证项目申请列表
```
GET /api/apply_signatures
```
*示例*
```bash
curl -X GET \
-d "project_id=36" \
-d "page=1" \
-d "limit=5" \
-d "search=16895620" \
-d "status=waiting" \
http://localhost:3000/api/apply_signatures | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
|-|-|-|-|
|project_id |是|int |项目id |
|page |否|string |页数,第几页 |
|limit |否|string |每页多少条数据默认15条 |
|search |否|string |用户名、登录名匹配搜索 |
|status |否|string |状态匹配搜索,'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过 |
*返回参数说明:*
|参数名|类型|说明|
|-|-|-|
|total_count |int |返回记录总条数 |
|apply_signatures |array|特殊许可证项目申请信息|
|-- id |int|特殊许可证项目申请id|
|-- status |int|特殊许可证项目申请状态,'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|user |object|用户|
|-- id |int|用户id|
|-- name |string|用户名称|
|-- login |string|用户登录名/标识|
|-- image_url |string|用户头像|
|-- email |string|用户邮箱|
|-- is_owner |boolean|是否是项目的拥有者true:是, false:不是|
|attachment |object|上传附件|
|--filename |string|附件名称|
|--path |string|附件地址|
返回值
```json
{
"total_count": 1,
"apply_signatures": [
{
"id": 18,
"status": "passed",
"user": {
"id": 3,
"name": "16895620",
"login": "16895620",
"image_url": "avatars/User/boy.jpg",
"email": "2456233122@qq.com",
"is_owner": false
},
"attachment": {
"filename": "PHengLEI软件开源协议.docx",
"path": "/api/attachments/23"
}
}
]
}
```
---
#### 特殊许可证项目用户创建申请
```
POST /api/apply_signatures
```
*示例*
```bash
curl -X POST \
-d "project_id=8" \
-d "attachment_id=4" \
http://localhost:3000/api/apply_signatures.json | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
|-|-|-|-|
|project_id |是|int |项目id |
|attachment_id |是|int |上传的文件id |
*返回参数说明:*
|参数名|类型|说明|
|-|-|-|
|id |int|特殊许可证项目用户创建申请的id|
|attachment |object|上传的文件|
|--filename |string|上传的文件的文件名|
返回值
```json
{
"id": 5,
"attachment": {
"filename": "timg.jpeg"
}
}
```
---
#### 特殊许可证项目申请修改
```
PATCH /api/apply_signatures/:id
```
*示例*
```bash
curl -X POST \
-d "id=18" \
-d "status=passed" \
-d "project_id=36" \
http://localhost:3000/api/apply_signatures/18 | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
|-|-|-|-|
|id |是|int |特殊许可证项目申请id |
|status |是|string |特殊许可证项目申请状态 'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|project_id |是|int |项目id|
*返回参数说明:*
|参数名|类型|说明|
|-|-|-|
|status |int |0:添加成功, -1: 更改失败, 1: 表示已经是该状态了 |
|message |string|返回信息说明|
返回值
```json
{
"status": 0,
"message": "success"
}
```
---

View File

@ -242,9 +242,7 @@ class AccountsController < ApplicationController
end
def set_autologin_cookie(user)
token = Token.get_or_create_permanent_login_token(user, "autologin")
sync_user_token_to_trustie(user.login, token.value)
token = Token.get_or_create_permanent_login_token(user, autologin_cookie_name)
cookie_options = {
:value => token.value,
:expires => 1.month.from_now,

View File

@ -0,0 +1,32 @@
class Admins::ApplySignaturesController < Admins::BaseController
def index
sort_by = params[:sort_by] ||= 'created_on'
sort_direction = params[:sort_direction] ||= 'desc'
@apply_signatures = paginate ApplySignature.waiting.includes(:attachments)
end
def update
ActiveRecord::Base.transaction do
begin
apply_signature = ApplySignature.find_by!(id: params[:id])
apply_signature.update_attributes!(apply_signatures_params)
if apply_signature.status == "passed"
Projects::AddMemberInteractor.call(apply_signature.project.owner, apply_signature.project, apply_signature.user, "read", true)
end
redirect_to admins_apply_signatures_path
flash[:success] = "更新成功"
rescue => e
raise ActiveRecord::Rollback
redirect_to admins_apply_signatures_path
flash[:danger] = "更新失败"
end
end
end
private
def apply_signatures_params
params.permit(:status)
end
end

View File

@ -0,0 +1,36 @@
class Admins::PhengleiUsersController < Admins::BaseController
before_action :phenglei_project, only: [:index]
def index
if params[:keyword].present?
@phenglei_users = PhengleiUser.ransack(phone_cont: params[:keyword]).result
else
@phenglei_users = PhengleiUser
end
@phenglei_users = @phenglei_users.page(page).per(per_page)
end
def new
@phenglei_user = PhengleiUser.new
end
def create
@phenglei_user = PhengleiUser.new(phenglei_user_params)
if @phenglei_user.save
redirect_to admins_phenglei_users_path
flash[:success] = "创建成功"
else
redirect_to admins_phenglei_users_path
flash[:error] = "创建失败"
end
end
private
def phenglei_project
@phenglei_project = Project.find_by_id(EduSetting.get("sync_phenglei_user_project"))
end
def phenglei_user_params
params.require(:phenglei_user).permit(:phone)
end
end

View File

@ -1,4 +1,5 @@
class Admins::ProjectsController < Admins::BaseController
before_action :load_project, only: [:sync_phenglei_user]
def index
sort_by = params[:sort_by] ||= 'created_on'
@ -6,7 +7,7 @@ class Admins::ProjectsController < Admins::BaseController
search = params[:search].to_s.strip
projects = Project.where("name like ?", "%#{search}%").order("#{sort_by} #{sort_direction}")
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score, :license)
end
def destroy
@ -22,4 +23,20 @@ class Admins::ProjectsController < Admins::BaseController
redirect_to admins_projects_path
flash[:danger] = "删除失败"
end
def sync_phenglei_user
if @project.is_secret
SyncPhengleiUserJob.perform_later(@project.id)
redirect_to admins_phenglei_users_path
flash[:success] = "已开启后台同步任务"
else
redirect_to admins_phenglei_users_path
flash[:danger] = "非风雷协议项目"
end
end
private
def load_project
@project = Project.find_by!(id: params[:id])
end
end

View File

@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
OPENKEY = "79e33abd4b6588941ab7622aed1e67e8"
helper_method :current_user, :base_url
helper_method :current_user
# 所有请求必须合法签名
def check_sign
@ -374,7 +374,7 @@ class ApplicationController < ActionController::Base
# auto-login feature starts a new session
user = nil
Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ")
user = User.try_to_autologin(cookies[autologin_cookie_name])
user = User.try_to_autologin(cookies[autologin_cookie_name], autologin_cookie_name)
# start_user_session(user) if user # TODO 解决sso退出不同步的问题
user
end
@ -770,11 +770,6 @@ class ApplicationController < ActionController::Base
@repository ||= load_project&.repository
end
def base_url
request.base_url
end
private
def object_not_found
uid_logger("Missing template or cant't find record, responding with 404")

View File

@ -0,0 +1,75 @@
class ApplySignaturesController < ApplicationController
include ApplicationHelper
before_action :find_project, only: [:index, :create, :update]
before_action :require_owner, only: [:update]
before_action :find_apply_signature, only: [:update]
def index
search = params[:search].to_s.downcase
@apply_signatures = @project.apply_signatures.with_status(status).includes(user: :user_extension)
@apply_signatures = @apply_signatures.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
@apply_signatures = kaminari_paginate(@apply_signatures)
end
def template_file
license = License.find_by_name("PHengLEI")
file = license.attachments.take
normal_status(-1, "文件不存在") if file.blank?
send_file(absolute_path(local_path(file)), filename: file.title,stream:false, type: file.content_type.presence || 'application/octet-stream')
end
def create
ActiveRecord::Base.transaction do
begin
@signature = current_user.apply_signatures.find_or_create_by!(project_id: params[:project_id])
@signature.status = 0
@signature.attachments = Attachment.none
@attachment = Attachment.find_by_id(params[:attachment_id])
@attachment.container = @signature
@signature.save!
@attachment.save!
rescue Exception => e
tip_exception("#{e}")
raise ActiveRecord::Rollback
end
render_json
end
end
def update
@apply_signature.update_attributes!(apply_signature_params)
if @apply_signature.status == "passed"
Projects::AddMemberInteractor.call(@apply_signature.project.owner, @apply_signature.project, @apply_signature.user, "read", true)
else
Projects::DeleteMemberInteractor.call(@apply_signature.project.owner, @apply_signature.project, @apply_signature.user)
end
render_ok
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def find_project
@project = Project.find_by_id(params[:project_id])
normal_status(-1, "项目不存在") unless @project.present?
end
def find_apply_signature
@apply_signature = ApplySignature.find_by_id(params[:id])
normal_status(-1, "特殊许可申请不存在") unless @apply_signature.present?
normal_status(1, "已经是该状态了") if @apply_signature.status == params[:status]
end
def apply_signature_params
params.permit(:status)
end
def status
params.fetch(:status, "all")
end
def require_owner
normal_status(403, "") unless @project.owner?(current_user)
end
end

View File

@ -42,6 +42,7 @@ class AttachmentsController < ApplicationController
# 2. 上传到云
begin
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
dun_check_file = upload_file.dup
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
raise "未上传文件" unless upload_file
@ -79,8 +80,16 @@ class AttachmentsController < ApplicationController
@attachment.digest = digest
@attachment.author_id = current_user.id
@attachment.disk_directory = month_folder
@attachment.cloud_url = remote_path
@attachment.save!
# @attachment.cloud_url = remote_path
# @attachment.save!
if @attachment.save!
check_result = Attachment.check_image_able(dun_check_file)
if check_result[:status].to_i == -1
@attachment.destroy
raise "上传失败,#{check_result[:message]}"
# return render json: {status: -1, message: "上传失败,#{check_result[:message]}" }
end
end
else
logger.info "文件已存在id = #{@attachment.id}, filename = #{@attachment.filename}"
end

View File

@ -1,53 +0,0 @@
class Ci::SecretsController < Ci::BaseController
before_action :load_repo
# 参数列表
def index
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], nil).secrets
@secrets = result
end
#新增、更新参数
def create
options = {
name: params[:name],
data: params[:data]
}
id = params[:id]
if id
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).update_secret
if result["id"]
render_ok
else
render_error(result["message"])
end
else
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret
if result["id"]
render_ok
else
render_error(result["message"])
end
end
end
#删除参数
def destroy
name = params[:name]
if !name.blank?
Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret
render_ok
else
render_error("参数名不能为空")
end
rescue Exception => ex
render_ok
end
def ci_drone_url
user = User.find_by(login: params[:owner])
user&.ci_cloud_account.drone_url
end
end

View File

@ -8,6 +8,9 @@ module LaboratoryHelper
helper_method :default_setting
helper_method :default_yun_session
helper_method :default_course_links
helper_method :manager_main_site_url
helper_method :main_web_site_url
helper_method :current_main_site_url
end
def current_laboratory
@ -32,18 +35,29 @@ module LaboratoryHelper
end
def default_course_links
# my_projects: "/users/#{current_user.try(:login)}/projects",
# my_projects: "https://www.trustie.net/users/#{current_user.try(:login)}/user_projectlist",
{
new_syllabuses: "https://www.trustie.net/syllabuses/new",
new_course: "https://www.trustie.net/courses/new",
edit_account: "https://www.trustie.net/my/account",
my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
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/",
tiding_url: "https://www.trustie.net/users/#{current_user.try(:login)}/user_messages",
register_url: "https://www.trustie.net/login?login=false"
# new_syllabuses: "https://www.trustie.net/syllabuses/new",
# new_course: "https://www.trustie.net/courses/new",
# edit_account: "https://www.trustie.net/my/account",
# my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
# 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/",
tiding_url: "#{main_web_site_url}/users/#{current_user.try(:login)}/user_tidings",
register_url: "#{main_web_site_url}/user_join"
}
end
def manager_main_site_url
{name: '管理', link: "#{main_web_site_url}/managements"}
end
def main_web_site_url
EduSetting.get('host_main_site')
end
def current_main_site_url
EduSetting.get('host_name')
end
end

View File

@ -6,14 +6,12 @@ module LoginHelper
end
def autologin_cookie_name
edu_setting('autologin_cookie_name').presence || 'autologin'
edu_setting('autologin_cookie_name').presence || 'autologin_forge_military'
end
def set_autologin_cookie(user)
token = Token.get_or_create_permanent_login_token(user, "autologin")
sync_user_token_to_trustie(user.login, token.value)
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
Rails.logger.info("set_cookie_user_id is=======> #{user.id}")
token = Token.get_or_create_permanent_login_token(user, autologin_cookie_name)
cookie_options = {
:value => token.value,
:expires => 1.month.from_now,

View File

@ -3,8 +3,11 @@ module RegisterHelper
def autologin_register(username, email, password, platform= 'forge')
result = {message: nil, user: nil}
email = email.blank? ? "#{username}@example.org" : email
user = User.find_by(login: username)
user ||= User.new(admin: false, login: username, mail: email, type: "User")
user = User.new(admin: false, login: username, mail: email, type: "User")
user.password = password
user.platform = platform
user.activate
@ -18,7 +21,7 @@ module RegisterHelper
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
if user.save!
UserExtension.create!(user_id: user.id)
UserExtension.create!(user_id: user.id) if user.user_extension.blank?
result[:user] = {id: user.id, token: user.gitea_token}
end
else

View File

@ -14,6 +14,6 @@ module Repository::LanguagesPercentagable
hash.transform_values { |v|
ActionController::Base.helpers
.number_to_percentage((v * 100.0 / total_byte_size), precision: 1)
}.select{|k,v| v != "0.0%"}
}
end
end

View File

@ -6,13 +6,11 @@ class IssuesController < ApplicationController
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]
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))
issues = @project.issues.issue_issue.issue_index_includes
issues = issues.where(is_private: false) unless @user_admin_or_member
@ -97,7 +95,8 @@ class IssuesController < ApplicationController
end
def new
@issue_chosen = get_associated_data(@project)
# @all_branches = get_branches
@issue_chosen = issue_left_chosen(@project, nil)
end
def create
@ -133,15 +132,10 @@ class IssuesController < ApplicationController
tiding_type: 'issue', status: 0)
end
#为悬赏任务时, 扣除当前用户的积分
if params[:issue_type].to_s == "2"
post_to_chain("minus", params[:token].to_i, current_user.try(:login))
end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
render json: {status: 0, message: "创建成", id: @issue.id}
else
normal_status(-1, "创建失败")
normal_status(-1, @issue.errors.messages.values[0][0])
end
end
@ -150,13 +144,12 @@ class IssuesController < ApplicationController
def edit
# @issue_chosen = issue_left_chosen(@project, @issue.id)
@cannot_edit_tags = @issue.issue_type=="2" && @issue.status_id == 5 #悬赏任务已解决且关闭的状态下,不能修改
@issue_attachments = @issue.attachments
end
def update
last_token = @issue.token
last_status_id = @issue.status_id
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
return normal_status(-1, "您没有权限修改token") if @issue.will_save_change_to_token? && @issue.user_id != current_user&.id
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|
@ -164,22 +157,23 @@ class IssuesController < ApplicationController
end
end
issue_files = params[:attachment_ids]
change_files = false
issue_file_ids = []
if @issue.update_attributes(issue_params)
issue_files = params[:attachment_ids]
change_files = false
issue_file_ids = []
if issue_files.present?
change_files = true
issue_files.each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
unless attachment.blank?
attachment.container = @issue
attachment.author_id = current_user.id
attachment.description = ""
attachment.save
if issue_files.present?
change_files = true
issue_files.each do |id|
attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id)
unless attachment.blank?
attachment.container = @issue
attachment.author_id = current_user.id
attachment.description = ""
attachment.save
end
end
end
end
# if params[:issue_tag_ids].present?
# issue_current_tags = @issue&.issue_tags&.select(:id)&.pluck(:id)
@ -195,35 +189,15 @@ class IssuesController < ApplicationController
# end
# end
if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id)
normal_status(-1, "不允许修改为关闭状态")
else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
if @issue.update_attributes(issue_params)
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project!
if @issue.issue_type.to_s == "2" && last_status_id != 5
if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))
else
post_to_chain("add", @issue.token, @issue.user.try(:login))
end
end
end
if @issue.issue_type.to_s == "2" && @issue.status_id != 5 && @issue.saved_change_to_attribute("token")
#表示修改token值
change_token = last_token - @issue.token
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)
normal_status(0, "更新成功")
else
normal_status(-1, "更新失败")
if params[:status_id].to_i == 5
@issue.issue_times.update_all(end_time: Time.now)
#@issue.update_closed_issues_count_in_project!
end
@issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id)
normal_status(0, "更新成功")
else
normal_status(-1, @issue.errors.messages.values[0][0])
end
end
@ -244,32 +218,17 @@ class IssuesController < ApplicationController
end
def destroy
begin
issue_type = @issue.issue_type
status_id = @issue.status_id
token = @issue.token
login = @issue.user.try(:login)
if @issue.destroy
if issue_type == "2" && status_id != 5
post_to_chain("add", token, login)
end
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
end
rescue => exception
Rails.logger.info("#########_______exception.message_________##########{exception.message}")
normal_status(-1, "删除失败")
if @issue.destroy
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
end
end
def clean
#批量删除,暂时只能删除未悬赏的
issue_ids = params[:ids]
if issue_ids.present?
if Issue.where(id: issue_ids, issue_type: "1").destroy_all
if Issue.where(id: issue_ids).destroy_all
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
@ -461,32 +420,4 @@ class IssuesController < ApplicationController
project_id: @project.id
}
end
def post_to_chain(type, amount,login)
change_params = {
type: type,
chain_params: {
amount: amount,
reponame: @project.try(:identifier),
username: login
}
}
PostChainJob.perform_later(change_params)
end
def check_token_enough
if params[:issue_type].to_s == "2" && (@issue.blank? || (@issue.present? && @issue.author_id == current_user.try(:id)))
return normal_status(-1, "悬赏的奖金必须大于0") if params[:token].to_i == 0
query_params = {
type: "query",
chain_params: {
reponame: @project.try(:identifier),
username: current_user.try(:login)
}
}
response = Gitea::Chain::ChainGetService.new(query_params).call
return normal_status(-1, "获取token失败请稍后重试") if response.status != 200
return normal_status(-1, "您的token值不足") if JSON.parse(response.body)["balance"].to_i < params[:token].to_i
end
end
end

View File

@ -46,7 +46,7 @@ class JournalsController < ApplicationController
render :json => { status: 0, message: "评论成功", id: journal.id}
# normal_status(0, "评论成功")
else
normal_status(-1, "评论失败")
normal_status(-1, journal.errors.messages.values[0][0])
end
end
end
@ -70,7 +70,7 @@ class JournalsController < ApplicationController
if @journal.update_attribute(:notes, content)
normal_status(0, "更新成功")
else
normal_status(-1, "更新失败")
normal_status(-1, @journal.errors.messages.values[0][0])
end
else
normal_status(-1, "评论的内容不能为空")

View File

@ -18,7 +18,7 @@ class MembersController < ApplicationController
scope = @project.members.includes(:roles, user: :user_extension)
search = params[:search].to_s.downcase
role = params[:role].to_s
scope = scope.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
scope = scope.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
scope = scope.joins(:roles).where("roles.name LIKE ?", "%#{role}%") if role.present?
@total_count = scope.size
@ -47,7 +47,7 @@ class MembersController < ApplicationController
end
def member_exists?
@project.members.exists?(params[:user_id])
@project.member?(params[:user_id])
end
def operate!
@ -59,6 +59,6 @@ class MembersController < ApplicationController
end
def check_member_not_exists!
return render_result(1, "user_id为#{params[:user_id]}的用户还不是项目成员") unless @project.member?(params[:user_id])
return render_result(1, "user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
end
end

View File

@ -8,7 +8,7 @@ class Oauth::EducoderController < Oauth::BaseController
::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate!
open_user= OpenUsers::Educoder.find_by(uid: login) || OpenUsers::Educoder.find_by(uid: mail)
open_user= OpenUsers::Educoder.find_by(uid: login)
if open_user.present? && open_user.user.present? && open_user.user.email_binded?
Rails.logger.info "######## open_user exist and open_user.user exsit and email is binded ok"

View File

@ -21,7 +21,7 @@ class Organizations::BaseController < ApplicationController
end
def team_not_found_condition
!current_user&.admin? && @team.team_users.where(user_id: current_user.id).blank? && !@organization.is_owner?(current_user.id)
@team.team_users.where(user_id: current_user.id).blank? && !@organization.is_owner?(current_user.id)
end
def user_mark
@ -31,4 +31,4 @@ class Organizations::BaseController < ApplicationController
def project_mark
params[:repo_name] || params[:id]
end
end
end

View File

@ -25,7 +25,6 @@ class Organizations::OrganizationsController < Organizations::BaseController
def create
ActiveRecord::Base.transaction do
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?
end
@ -37,10 +36,8 @@ class Organizations::OrganizationsController < Organizations::BaseController
def update
ActiveRecord::Base.transaction do
login = @organization.login
@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))
@organization.update!(login: organization_params[:name]) if organization_params[:name].present?
@organization.organization_extension.update_attributes!(organization_params.except(:name))
Gitea::Organization::UpdateService.call(@organization.gitea_token, login, @organization.reload)
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
end
@ -85,7 +82,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
def organization_params
params.permit(:name, :description, :website, :location,
:repo_admin_change_team_access, :visibility,
:max_repo_creation, :nickname)
:max_repo_creation)
end
def password

View File

@ -33,10 +33,7 @@ class Organizations::TeamsController < Organizations::BaseController
end
def create
ActiveRecord::Base.transaction do
Organizations::CreateTeamForm.new(team_params).validate!
@team = Organizations::Teams::CreateService.call(current_user, @organization, team_params)
end
@team = Organizations::Teams::CreateService.call(current_user, @organization, team_params)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
@ -63,7 +60,7 @@ class Organizations::TeamsController < Organizations::BaseController
private
def team_params
params.permit(:name, :nickname, :description, :authorize, :includes_all_project, :can_create_org_project, :unit_types => [])
params.permit(:name, :description, :authorize, :includes_all_project, :can_create_org_project, :unit_types => [])
end
def load_organization

View File

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

View File

@ -1,24 +0,0 @@
class Projects::ProjectUnitsController < Projects::BaseController
def index
@project_units = @project.project_units
end
def create
if current_user.admin? || @project.manager?(current_user)
ActiveRecord::Base.transaction do
ProjectUnit.update_by_unit_types!(@project, unit_types)
render_ok
end
else
render_forbidden('你没有权限操作')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def unit_types
params.fetch(:unit_types, [])
end
end

View File

@ -2,35 +2,19 @@ class ProjectsController < ApplicationController
include ApplicationHelper
include OperateProjectAbilityAble
include ProjectsHelper
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 :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about]
before_action :load_project, except: %i[index group_type_list migrate create recommend]
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
def menu_list
menu = []
menu.append(menu_hash_by_name("home"))
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls")
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)
render json: menu
end
def index
scope = 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, :apply_signatures, :members, :owner)
category_id = params[:category_id]
@total_count =
@total_count = @projects.total_count
if category_id.blank?
ps = ProjectStatistic.first
ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
@ -60,48 +44,34 @@ class ProjectsController < ApplicationController
end
def branches
return @branches = [] unless @project.forge?
result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
@branches = result.is_a?(Hash) && result.key?(:status) ? [] : result
@branches = @project.forge? ? Gitea::Repository::Branches::ListService.new(@owner, @project.identifier).call : []
end
def group_type_list
project_statics = ProjectStatistic.first
@project_statics_list = [
{
project_type: 'common',
name: '开源托管项目',
projects_count: project_statics&.common_projects_count || 0
},
{
project_type: 'mirror',
name: '开源镜像项目',
projects_count: project_statics&.mirror_projects_count || 0
}
]
# projects = Project.no_anomory_projects.visible
# @project_group_list = projects.group(:project_type).size
# if current_user&.logged?
# projects = Project.list_user_projects(current_user.id)
# else
# projects = Project.visible
# end
projects = Project.no_anomory_projects.secret_and_visible
language_lists = projects.joins(:project_language).group("project_languages.name", "project_languages.id").size.keys.sort.to_h
@project_group_list = language_lists.delete_if { |k, v| k.blank? }
end
def update
ActiveRecord::Base.transaction do
# Projects::CreateForm.new(project_params).validate!
private = params[:private] || false
new_project_params = project_params.except(:private).merge(is_public: !private)
@project.update_attributes!(new_project_params)
private = params[:private]
gitea_params = {
private: private,
default_branch: @project.default_branch,
website: @project.website
default_branch: params[:default_branch]
}
if [true, false].include? private
new_project_params = project_params.except(:private).merge(is_public: !private)
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
@project.repository.update_column(:hidden, private)
end
@project.update_attributes!(new_project_params)
end
rescue Exception => e
uid_logger_error(e.message)
@ -112,7 +82,7 @@ class ProjectsController < ApplicationController
end
def destroy
if current_user.admin? || @project.manager?(current_user)
if current_user.admin? || @project.owner?(current_user)
ActiveRecord::Base.transaction do
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
@project.destroy!
@ -168,7 +138,6 @@ class ProjectsController < ApplicationController
end
if @project_detail.save!
attachment_ids = Array(params[:attachment_ids])
logger.info "=============> #{Array(params[:attachment_ids])}"
@attachments = Attachment.where(id: attachment_ids)
@attachments.update_all(
container_id: @project_detail.id,
@ -183,7 +152,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,
:project_category_id, :project_language_id, :license_id, :ignore_id, :private)
end

View File

@ -8,7 +8,6 @@ class PullRequestsController < ApplicationController
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))
@ -105,8 +104,10 @@ class PullRequestsController < ApplicationController
normal_status(-1, "PullRequest更新失败")
end
else
normal_status(-1, "PullRequest更新失败")
normal_status(-1, @pull_request.errors.messages.values[0][0])
end
else
normal_status(-1, @issue.errors.messages.values[0][0])
end
rescue => e
normal_status(-1, e.message)
@ -140,7 +141,7 @@ class PullRequestsController < ApplicationController
end
def pr_merge
return render_forbidden("你没有权限操作.") unless current_user.project_manager?(@project)
return render_forbidden("你没有权限操作.") if @project.reporter?(current_user)
if params[:do].blank?
normal_status(-1, "请选择合并方式")

View File

@ -7,29 +7,10 @@ class RepositoriesController < ApplicationController
before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit]
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]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]
def files
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
render json: result
end
# 新版项目详情
def detail
@user = current_user
@result = Repositories::DetailService.call(@owner, @repository, @user)
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@fork_project_user = @fork_project.owner
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show
@user = current_user
@repo = @project.repository
@ -103,13 +84,7 @@ class RepositoriesController < ApplicationController
end
def tags
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
end
def contributors
@contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
@tags = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
end
def edit
@ -212,7 +187,7 @@ class RepositoriesController < ApplicationController
end
def get_ref
@ref = params[:ref] || @project&.default_branch
@ref = params[:ref] || "master"
end
def get_latest_commit

View File

@ -1,57 +1,4 @@
class SettingsController < ApplicationController
def show
@old_projects_url = nil
get_add_menu
get_common_menu
get_personal_menu
end
private
def get_add_menu
@add = []
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
hash = {}
site.each {|k, v|
hash.merge!("#{k}": get_site_url(k, v))
}
@add << hash
end
end
def get_common_menu
@common = {}
Site.common.select(:url, :key).each do |site|
next if site["url"].to_s.include?("current_user") && !User.current.logged?
@common.merge!("#{site["key"]}": append_http(reset_site_url(site["url"])))
end
end
def get_personal_menu
@personal = []
if User.current.logged?
Site.personal.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
hash = {}
site.each {|k, v|
hash.merge!("#{k}": get_site_url(k, v))
}
@personal << hash
end
end
end
def get_site_url(key, value)
key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value)
end
def reset_site_url(url)
return url unless url.to_s.include?("current_user")
split_arr = url.split('current_user')
split_arr.length > 1 ? split_arr.join(current_user&.login) : (split_arr << current_user&.login).join('')
end
def append_http(url)
url.to_s.start_with?("http") ? url : [request.protocol, request.host_with_port, url].join('')
end
end

View File

@ -309,12 +309,12 @@ class SyncForgeController < ApplicationController
# end
# end
# def check_token
# sync_params = params[:sync_params]
# unless sync_params[:token] && sync_params[:token] == get_token
# render json: {message: "token_errors"}
# end
# end
# # def check_token
# # sync_params = params[:sync_params]
# # unless sync_params[:token] && sync_params[:token] == get_token
# # render json: {message: "token_errors"}
# # end
# # end
# def get_token
# "34c82f51e0b699d9d16d70fd6497c9b1e4821d6ea3e872558a6537a091076b8e"

View File

@ -2,9 +2,9 @@ class UsersController < ApplicationController
include ApplicationHelper
include Ci::DbConnectable
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me list sync_user_info]
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users]
before_action :require_login, only: %i[me list]
before_action :connect_to_ci_db, only: [:get_user_info]
skip_before_action :check_sign, only: [:attachment_show]
@ -56,9 +56,6 @@ class UsersController < ApplicationController
@watchers = paginate(watchers)
end
def hovercard
end
def update
@user = User.find params[:id]
@user.update!(user_params)
@ -158,8 +155,7 @@ class UsersController < ApplicationController
# 其他平台登录后必须将token同步到forge平台实现sso登录功能
def sync_token
return render_error('未找相关用户!') unless @user
token = Token.get_or_create_permanent_login_token(@user, 'autologin')
token = Token.get_or_create_permanent_login_token(@user, autologin_cookie_name)
token.update_column(:value, params[:token])
render_ok
end
@ -236,26 +232,6 @@ class UsersController < ApplicationController
render_ok
end
def sync_user_info
user = User.find_by_login params[:login]
return render_forbidden unless user === current_user
sync_params = {
email: params[:email],
password: params[:password]
}
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate!
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO)
render_ok
else
render_error(interactor.error)
end
end
private
def load_user
@user = User.find_by_login(params[:id]) || User.find_by(id: params[:id])

View File

@ -8,7 +8,7 @@ class VersionReleasesController < ApplicationController
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)
@forge_releases = @repository.version_releases.select(:id,:version_gid).includes(:attachments)
end
def new

View File

@ -5,7 +5,6 @@ class VersionsController < ApplicationController
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))
order_name = params[:order_name] || "created_on"
order_type = params[:order_type] || "desc"
@ -84,7 +83,7 @@ class VersionsController < ApplicationController
if version.save
normal_status(0, "里程碑创建成功")
else
normal_status(-1, "里程碑创建失败")
normal_status(-1, version.errors.messages.values[0][0])
end
end
@ -122,7 +121,7 @@ class VersionsController < ApplicationController
if @version.update_attributes(tag_params)
normal_status(0, "里程碑更新成功")
else
normal_status(-1, "里程碑更新失败")
normal_status(-1, version.errors.messages.values[0][0])
end
end
else

View File

@ -168,55 +168,6 @@ Remember — a happy kitten is an authenticated kitten!
</aside>
## 项目导航
获取项目导航信息
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/menu_list | jq
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/menu_list')
```
### HTTP 请求
`GET api/:owner/:repo/menu_list`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是| |string |用户登录名
repo |是| |string |项目标识identifier
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
menu_name |string|导航名称, home:主页,code:代码库,issues:易修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置
> 返回的JSON示例:
```json
[
{
"menu_name": "home"
},
{
"menu_name": "code"
},
{
"menu_name": "pulls"
},
{
"menu_name": "activity"
}
]
```
## 项目主页
获取项目主页信息
@ -261,84 +212,6 @@ attachments |array|附件
Remember — a happy kitten is an authenticated kitten!
</aside>
## 项目模块信息
项目模块信息
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/project_units.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/project_units')
```
### HTTP 请求
`GET /api/yystopf/ceshi/project_units`
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|type |string|模块名称 |
> 返回的JSON示例:
```json
[
{
"type": "code"
},
{
"type": "pulls"
},
{
"type": "issues"
}
]
```
## 更改项目模块展示
更改项目模块展示
> 示例:
```shell
curl -X POST \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-d "{ \"unit_typs\": [\"code\", \"pulls\"]}" \
http://localhost:3000/api/yystopf/ceshi/project_units.json
```
```javascript
await octokit.request('POST /api/yystopf/ceshi/project_units')
```
### HTTP 请求
`POST /api/yystopf/ceshi/project_units`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:易修,pulls:合并请求,devops:工作流,versions:里程碑 |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|status |int|返回状态, 0: 表示操作成功 |
|message |string|返回信息说明|
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
## 创建项目
创建项目

View File

@ -97,182 +97,6 @@ await octokit.request('GET /api/jasder/jasder_test/simple.json')
}
```
## 仓库详情(新版)
仓库详情
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/ceshi/detail.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/detail.json')
```
### HTTP 请求
`GET /api/:owner/:repo/detail`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|content |string |仓库简介 |
|website |string |仓库网址 |
|readme |string |readme文件
|identifier |string |项目标识 |
|name |string |项目名称 |
|issues_count |int |项目issue数量|
|pull_requests_count |int |项目合并请求数量|
|project_identifier |int |项目标识|
|praises_count |int |项目点赞数量|
|forked_count |int |项目复刻数量|
|watchers_count |int |项目关注数量|
|versions_count |int |项目里程碑数量|
|version_releases_count |int |项目发行版数量|
|version_releasesed_count |int |项目发行版已发行数量|
|permission |string |项目权限|
|mirror_url |string |镜像地址|
|mirror |bool |是否为镜像项目|
|type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目|
|open_devops |int |是否开启devops|
|watched |bool |是否关注|
|praised |bool |是否点赞|
|status |int |项目状态|
|forked_from_project_id |int |fork项目id|
|fork_info |object |fork项目信息|
|size |string |仓库大小|
|ssh_url |string |项目ssh地址|
|clone_url |string |项目克隆地址|
|default_branch |string |仓库默认分支|
|empty |bool |仓库是否为空|
|full_name |string |仓库全称|
|private |bool |仓库是否为私有项目|
|license_name |string |许可证名称|
|release_versions.list.name |string |项目issue数量|
|release_versions.list.tag_name |string |发行版标签名称|
|release_versions.list.created_at |string |发行版创建时间|
|release_versions.total_count |int |发行版数量|
|branches.list.name |string |分支名称|
|branches.total_count |int |分支数量|
|tags.list.name |string |标签名称|
|tags.total_count |int |标签数量|
|contributors.list.contributions|int |贡献数量|
|contributors.list.login |string |贡献者登录名|
|contributors.list.name |string |贡献者用户名称|
|contributors.list.image_url |string |贡献者头像|
|languages |object |项目语言占比|
> 返回的JSON示例:
```json
{
"content": "仓库简介",
"website": "仓库网址",
"readme": {
"type": "file",
"encoding": "base64",
"size": 9,
"name": "README.md",
"path": "README.md",
"content": "# ceshi\n\n",
"sha": ""
},
"identifier": "ceshi",
"name": "测试项目",
"project_id": 2,
"repo_id": 2,
"issues_count": 0,
"pull_requests_count": 0,
"project_identifier": "ceshi",
"praises_count": 0,
"forked_count": 0,
"watchers_count": 0,
"versions_count": 0,
"version_releases_count": 0,
"version_releasesed_count": 0,
"permission": "Reporter",
"mirror_url": null,
"mirror": false,
"type": 0,
"open_devops": false,
"watched": false,
"praised": false,
"status": 1,
"forked_from_project_id": 1,
"fork_info": {
"fork_form_name": "测试项目",
"fork_project_user_login": "ceshi_org",
"fork_project_identifier": "ceshi",
"fork_project_user_name": "ceshi_org"
},
"size": "25.0 KB",
"ssh_url": "virus@localhost:yystopf/ceshi.git",
"clone_url": "http://localhost:10080/yystopf/ceshi.git",
"default_branch": "master",
"empty": false,
"full_name": "yystopf/ceshi",
"private": false,
"license_name": "gnu-javamail-exception",
"release_versions": {
"list": [
{
"id": 2,
"name": "vvvv",
"tag_name": "v1.1",
"created_at": "2019-07-18 10:16"
}
],
"total_count": 1
},
"branches": {
"list": [
{
"name": "master"
}
],
"total_count": 1
},
"tags": {
"list": [
{
"name": "v1.1"
},
{
"name": "v1.0"
}
],
"total_count": 2
},
"contributors": {
"list": [
{
"contributions": 1,
"gid": 2,
"login": "yystopf",
"type": "User",
"name": "yystopf",
"image_url": "avatars/User/b"
}
],
"total_count": 1
},
"languages": {
"HTML": "50.9%",
"Ruby": "25.6%",
"JavaScript": "21.4%",
"CSS": "1.3%",
"CoffeeScript": "0.7%",
"Shell": "0.1%"
}
}
```
## 编辑仓库信息
编辑仓库信息
@ -639,78 +463,6 @@ await octokit.request('GET /api/jasder/jasder_test/collaborators.json')
Success Data.
</aside>
## 获取仓库所有文件
获取仓库所有文件
> 示例:
```shell
curl -X GET \
-d "ref=develop" \
http://localhost:3000/api/yystopf/ceshi/files.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/files.json')
```
### HTTP 请求
`GET /api/:owner/:repo/files`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
|search |否| |string |文件搜索关键词 |
|ref |是| |string |分支名,默认为仓库默认分支 |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|name |string |文件名称|
|path |string |文件路径|
|sha |string |文件标识|
|type |string |文件类型|
|size |int |文件大小|
|url |string |文件地址|
> 返回的JSON示例:
```json
[
{
"name": ".gitignore",
"path": ".gitignore",
"sha": "f83922d01ae60f6e637a1a2b9f08871b4f87dfc8",
"type": "file",
"size": 63,
"url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/.gitignore?ref=master",
"html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/.gitignore"
},
{
"name": "LICENSE",
"path": "LICENSE",
"sha": "8f3b9ab0d08afd3a624d822e3971a2f42b3bc2b9",
"type": "file",
"size": 341,
"url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/LICENSE?ref=master",
"html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/LICENSE"
},
{
"name": "README.md",
"path": "README.md",
"sha": "1bc8a60ac6ddc876ebc4b60fc68991435bfad93e",
"type": "file",
"size": 9,
"url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/README.md?ref=master",
"html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/README.md"
}
]
```
## 获取仓库代码目录
获取仓库代码目录

View File

@ -1,13 +1,24 @@
class Contents::CreateForm < BaseForm
attr_accessor :filepath, :branch, :new_branch
attr_accessor :filepath, :branch, :new_branch, :content
validates :filepath, presence: true
validate :check_branch
validate :dun_content_check
def check_branch
raise "branch和new_branch必须存在一个 " if branch.blank? && new_branch.blank?
# raise "branch和new_branch只能存在一个" if !branch.blank? && !new_branch.blank?
end
def dun_content_check
if content.present?
check_result = DunCheck::TextCheck.new({title: "", content: content}).call
if check_result[:status].to_i == -1
raise "内容含有:#{check_result[:extra_params][:infos]},请修改"
end
end
end
end

View File

@ -1,8 +0,0 @@
class Organizations::CreateForm < BaseForm
NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname
validates :name, :nickname, :visibility, presence: true
validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
end

View File

@ -1,8 +0,0 @@
class Organizations::CreateTeamForm < BaseForm
NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
attr_accessor :name, :nickname, :description, :authorize, :includes_all_project, :can_create_org_project, :unit_types
validates :name, :nickname, :authorize, presence: true
validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
end

View File

@ -1,9 +0,0 @@
class Users::UpdateInfoForm
include ActiveModel::Model
attr_accessor :email, :password, :login
validates :email, presence: true, format: { with: CustomRegexp::EMAIL }
validates :password, presence: true
validates :login, presence: true
end

View File

@ -35,6 +35,12 @@ module ApplicationHelper
course.course_modules.find_by(module_type: "graduation").try(:id)
end
# 是否关注
# from_user_id为被关注的用户
def follow?(from_user_id, user_id)
Watcher.where(watchable_type: 'Principal', watchable_id: from_user_id, user_id: user_id).exists?
end
# git用户
# git用户命名规则login+"@educoder.net"
def git_username(email)
@ -138,12 +144,17 @@ module ApplicationHelper
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}"
File.join(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
str = source.user_extension.try(:gender).to_i == 0 ? "boy.jpg" : "girl.jpg"
File.join(relative_path, "#{source.class}", str)
elsif source.class.to_s == 'Subject'
File.join("images","educoder", "index", "subject", "subject#{rand(17)}.jpg")
elsif source.class.to_s == 'Shixun'
File.join("images","educoder", "index", "shixun", "shixun#{rand(23)}.jpg")
end
end

View File

@ -1,9 +1,4 @@
module ProjectsHelper
def menu_hash_by_name(name)
{
menu_name: name
}
end
def render_zh_project_type(project_type)
case project_type
@ -55,7 +50,10 @@ 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),
is_secret: project.is_secret,
is_member: project.member?(user.id),
user_apply_signatures: project.apply_signatures.with_user_id(user.id).collect{|s| {id: s.id, status: s.status}}
}).compact
render json: tmp_json
@ -90,4 +88,8 @@ module ProjectsHelper
def render_educoder_avatar_url(project_educoder)
[Rails.application.config_for(:configuration)['educoder']['cdn_url'], project_educoder&.image_url].join('/')
end
def render_avatar_url(owner)
['images', url_to_avatar(owner)].join('/')
end
end

View File

@ -1,6 +1,7 @@
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
return "Owner" if user === project.owner
project.get_premission(user)
end
@ -27,43 +28,39 @@ module RepositoriesHelper
def render_commit_author(author_json)
return nil if author_json.blank?
find_user_by_login author_json['name']
find_user_by_login author_json['login']
end
def readme_render_decode64_content(str, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(c_regex)
ss_src = content.to_s.scan(src_regex)
total_images = ss + ss_src
if total_images.length > 0
total_images.each do |s|
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
if remove_title.length > 0
r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
end
if r_content.include?("?")
new_r_content = r_content + "&raw=true"
else
new_r_content = r_content + "?raw=true"
end
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
new_r_content = "#{path}" + new_r_content
end
content = content.gsub(/#{r_content}/, new_r_content)
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(c_regex)
ss_src = content.to_s.scan(src_regex)
total_images = ss + ss_src
if total_images.length > 0
total_images.each do |s|
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
if remove_title.length > 0
r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
end
if r_content.include?("?")
new_r_content = r_content + "&raw=true"
else
new_r_content = r_content + "?raw=true"
end
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
new_r_content = "#{path}" + new_r_content
end
content = content.gsub(/#{r_content}/, new_r_content)
end
return content
rescue
return str
end
return content
end
# unix_time values for example: 1604382982

View File

@ -48,7 +48,8 @@ module Gitea
{
filepath: @params[:filepath],
branch: @params[:branch],
new_branch: @params[:new_branch]
new_branch: @params[:new_branch],
content: @params[:content]
}
end

View File

@ -1,18 +1,19 @@
module Projects
class AddMemberInteractor
def self.call(owner, project, collaborator, permission="write")
interactor = new(owner, project, collaborator, permission)
def self.call(owner, project, collaborator, permission="write", is_apply_signature=false)
interactor = new(owner, project, collaborator, permission, is_apply_signature)
interactor.run
interactor
end
attr_reader :error, :result
def initialize(owner, project, collaborator, permission)
@owner = owner
@project = project
@collaborator = collaborator
@permission = permission
def initialize(owner, project, collaborator, permission, is_apply_signature)
@owner = owner
@project = project
@collaborator = collaborator
@permission = permission
@is_apply_signature = is_apply_signature
end
def success?
@ -23,7 +24,7 @@ module Projects
ActiveRecord::Base.transaction do
gitea_result = Gitea::Repository::Members::AddService.new(owner, project.identifier, collaborator.login, permission).call
if gitea_result.status == 204
project.add_member!(collaborator.id)
project.add_member!(collaborator.id, set_member_role, is_apply_signature)
end
fail!(nil)
end
@ -32,11 +33,20 @@ module Projects
end
private
attr_reader :owner, :project, :collaborator, :permission
attr_reader :owner, :project, :collaborator, :permission, :is_apply_signature
def fail!(error)
@error = error
end
def set_member_role
@role ||=
case @permission
when "write" then "Developer"
when "read" then "Reporter"
else "Developer"
end
end
end
end

View File

@ -0,0 +1,48 @@
class SyncForgeProjectJob < ApplicationJob
queue_as :default
def perform(sync_parmas)
# sync_parmas.permit!
Rails.logger.info("=======begin to sync forge projects, and sync_parmas: #{sync_parmas}")
get_rand_user = rand_user
project_params = sync_parmas[:project]
repository_params = sync_parmas[:repository]
project_socre_params = sync_parmas[:project_socre]
begin
unless Project.select(:identifier).exists?(identifier: project_params[:identifier])
project_params = project_params.merge({user_id: get_rand_user.id })
project = Project.new(project_params)
if project.save
repository_params = {
hidden: false,
identifier: repository_params[:identifier],
mirror_url: repository_params[:url].to_s.gsub("https://gitea.", "https://git."),
user_id: get_rand_user.id,
login: get_rand_user.login,
password: "",
is_mirror: false
}
Repositories::MigrateService.new(get_rand_user, project, repository_params).call
project_score = ProjectScore.new(project_socre_params.merge({project_id: project.id}))
project_score.save
end
end
Rails.logger.info("=======end to sync forge projects")
rescue => e
Rails.logger.info("=======sync forge projects has errors: #{e}")
raise ActiveRecord::Rollback
end
end
private
def rand_user
user_ids = User.select(:id, :type, :gitea_token, :gitea_uid).where("gitea_token is not null and gitea_uid is not null and type = ?", "User").pluck(:id)
range_user_id = user_ids[rand(user_ids.length-1)]
rand_sync_user = User.find_by_id(range_user_id) #生成随机用户
unless rand_sync_user.present?
rand_user
end
rand_sync_user
end
end

View File

@ -5,7 +5,7 @@ class SyncMirroredRepositoryJob < ApplicationJob
repo = Repository.find_by(id: repo_id)
current_user = User.find_by(id: user_id)
return if repo.blank? || current_user.blank?
result = Gitea::Repository::SyncMirroredService.new(repo.owner.login, repo.identifier, token: current_user.gitea_token).call
repo&.mirror.set_status! if result[:status] === 200
result = Gitea::Repository::SyncMirroredService.new(repo.user.login, repo.identifier, token: current_user.gitea_token).call
repo&.mirror&.set_status! if result[:status] == 200 && repo.mirror.present?
end
end

View File

@ -0,0 +1,36 @@
class SyncPhengleiUserJob < ApplicationJob
queue_as :default
def perform(project_id=nil)
project_id ||= EduSetting.get("sync_phenglei_user_project")
project = Project.find_by_id(project_id)
return if project.nil?
member_count, success_count, error_count, not_exsit_count = 0, 0, 0, 0
Rails.logger.info("======begin to sync phenglei user to project#{project.owner.login + "/" + project.identifier}")
PhengleiUser.find_each do |i|
puts "======开始处理#{i.phone}"
user = User.find_by(phone: i.phone)
if user.present?
if project.member?(user.id)
puts "======#{i.phone}用户已经是外围贡献者了"
member_count += 1
else
interactor = Projects::AddMemberInteractor.call(project.owner, project, user, "read", true)
if interactor.error.nil?
puts "========用户#{i.phone}成功添加为项目的外围贡献者======="
success_count += 1
else
puts "========用户#{i.phone}添加失败"
error_count += 1
end
end
else
puts "=====#{i.phone}用户不存在"
not_exsit_count += 1
next
end
end
Rails.logger.info("======已存在外围贡献者数量#{member_count}, 成功添加用户数量#{success_count}, 添加失败用户数量#{error_count}, 找不到用户数量#{not_exsit_count}")
Rails.logger.info("======end to sync phenglei user to project#{project.owner.login + "/" + project.identifier}")
end
end

View File

@ -85,24 +85,4 @@ class Ci::Drone::API < Ci::Drone::Request
post(endpoint, "/api/users", {login: options[:login], email: options[:email], avatar_url:options[:avatar_url],active:true, drone_token: options[:token]})
end
# Creates a secret.
def create_secret
post(endpoint, "/api/repos/#{owner}/#{repo}/secrets", {name: options[:name], data: options[:data], pull_request:true, drone_token: drone_token})
end
# Update a secret.
def update_secret
patch(endpoint, "/api/repos/#{owner}/#{repo}/secrets/#{options[:name]}", { data: options[:data], pull_request:true, drone_token: drone_token})
end
# list of secrets.
def secrets
get(endpoint, "/api/repos/#{owner}/#{repo}/secrets", drone_token: drone_token)
end
# delete secret.
def delete_secret
delete(endpoint, "/api/repos/#{owner}/#{repo}/secrets/#{options[:name]}", drone_token: drone_token)
end
end

View File

@ -0,0 +1,167 @@
class DunCheck::ImageCheck
#检测结果0通过1嫌疑2不通过
# include ActionView::Helpers::LoopTextsHelper
require 'uri'
require 'net/http'
def initialize(image_params)
@image_params = image_params
end
def call
begin
Rails.logger.info("==========@image_params===========#{@image_params}")
dun_params = check_dun_params(@image_params)
api_url = EduSetting.get("dun_image_api")
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.hostname, uri.port)
if api_url.include?("https://")
http.use_ssl = true
end
dun_params_str = URI.encode_www_form(dun_params)
header = {'content-type':'application/x-www-form-urlencoded'}
response = http.post(uri.path, dun_params_str, header)
response_body = JSON.parse(response.body)
if response_body["code"].to_i == 200
response_body_result = response_body["antispam"]
response_lables = response_body_result[0]["labels"]
return_sub_lable = ""
if response_lables.present?
return_sub_lable = get_sub_labels(response_lables)
end
render_status = response_body_result[0]["action"].to_i == 0 ? 1 : -1
tip_status(render_status, return_sub_lable.present? ? "图片含有: #{return_sub_lable}" : response_body["msg"] )
else
tip_status(-1, response_body["msg"])
end
rescue Exception => ex
Rails.logger.info "*** transaction abored!"
Rails.logger.info "*** errors: #{ex.message}"
tip_status(-1, "检测失败")
end
end
private
def check_dun_params(image_params)
dun_public_params = DunCheck::PublicParams.new("image")
check_params = {
version: "v4",
images: image_params.to_json
}
check_params.merge!(dun_public_params.call)
dun_params = dun_public_params.generate_sign(check_params)
return dun_params
end
def tip_status(status, message, msg_params={})
return {status: status, message: message, extra_params: msg_params}
end
def get_sub_labels(labels)
_sub_labels = []
labels.each do |label|
error_label = label["subLabels"].present? ? label["subLabels"][0]["subLabel"] : ""
if error_label.present?
_sub_labels.push(sub_lables[:"#{error_label.to_s}"])
end
end
return _sub_labels.present? ? _sub_labels.join(",") : ""
end
def sub_lables
{
"10000": "色情",
"10001": "女下体",
"10002": "女胸",
"10003": "男下体",
"10004": "性行为",
"10005": "臀部",
"10006": "口交",
"10007": "卡通色情",
"10008": "色情人物",
"10009": "儿童色情",
"11000": "性感低俗",
"11001": "亲吻",
"11002": "腿部特写",
"11003": "非漏点赤膊",
"11004": "胸部",
"100001": "色情文字-色情其他",
"100002": "色情文字-色情传播",
"100003": "色情文字-色情性器官",
"100004": "色情文字-色情挑逗",
"100005": "色情文字-色情低俗段子",
"100006": "色情文字-色情性行为",
"100007": "色情文字-色情舆情事件",
"100008": "色情文字-色情交友类",
"20000": "广告",
"20001": "广告带文字",
"200009": "广告文字-商业推广",
"200010": "广告文字-广告法",
"200011": "刷量行为",
"200012": "广告其他",
"260052": "广告文字-广告法-涉医疗用语",
"260053": "广告文字-广告法-迷信用语",
"260054": "广告文字-广告法-需要凭证",
"260055": "广告文字-广告法-限时性用语",
"260056": "广告文字-广告法-涉嫌诱导消费者",
"260057": "广告文字-广告法-涉嫌欺诈消费者",
"260058": "广告文字-广告法-法律风险较高",
"260059": "广告文字-广告法-极限词",
"21000": "二维码",
"30000": "暴恐",
"30001": "暴恐图集",
"30002": "暴恐旗帜",
"30003": "暴恐人物",
"30004": "暴恐标识",
"30005": "暴恐场景",
"300016": "暴恐文字-暴恐其他",
"40000": "违禁",
"40001": "违禁图集",
"40002": "违禁品",
"40003": "特殊标识",
"40004": "血腥模型",
"40005": "公职服饰",
"40006": "不文明",
"40007": "违禁人物",
"40008": "违禁场景",
"40009": "火焰",
"40010": "骷髅",
"40011": "货币",
"40012": "毒品",
"400017": "违禁文字-违禁其他",
"600018": "违禁文字-谩骂其他",
"50000": "涉政",
"50001": "涉政图集",
"50002": "中国地图",
"50003": "涉政人物",
"50004": "涉政旗帜",
"50005": "涉政标识",
"50006": "涉政场景",
"500013": "涉政文字-涉政其他",
"500014": "涉政文字-敏感专项",
"500015": "涉政文字-严格涉政",
"500039": "涉政文字-时事报道",
"500040": "涉政文字-领导人相关",
"500041": "涉政文字-英雄烈士相关",
"500042": "涉政文字-邪教迷信",
"500043": "涉政文字-落马官员相关",
"500044": "涉政文字-热点舆情",
"500045": "涉政文字-涉政综合",
"90000": "其他",
"90002": "自定义用户名单",
"90003": "自定义IP名单",
"900020": "文字违规-其他"
}
end
end

View File

@ -0,0 +1,31 @@
class DunCheck::PublicParams
def initialize(type)
@type = type
end
def call
public_params = {
secretId: EduSetting.get("dun_secret_id"),
businessId: EduSetting.get("dun_#{@type}_businessId"),
timestamp: DateTime.current.strftime('%Q').to_i,
nonce: rand(10 ** 11).to_i
}
return public_params
end
def generate_sign(params)
secretkey = EduSetting.get("dun_secrect_key")
sort_params = params.sort.to_h
sign_str = ""
sort_params.each do |k,v|
sign_str += "#{k.to_s}#{v.to_s}"
end
sign_str += secretkey
md5_sign = Digest::MD5.hexdigest(sign_str.to_s.force_encoding("UTF-8"))
return sort_params.merge!(signature: md5_sign)
end
end

View File

@ -0,0 +1,164 @@
class DunCheck::TextCheck
# include DunCheck::PublicParams
#text_params = {
# content: "ccc", #内容
# ip: "xxx", #用户ip
# account: "xxx", #登录login
# nickname: "xxx", #用户姓名
# title: "xxx", #帖子的标题
# }
#检测结果0通过1嫌疑2不通过
# include ActionView::Helpers::LoopTextsHelper
require 'uri'
require 'net/http'
def initialize(text_params)
@text_params = text_params
end
def call
new_text_params = @text_params
text_long_array = []
check_content = new_text_params[:content]
format_text(check_content,text_long_array)
(1..text_long_array.size).each do |i|
new_text_params.merge!(content: text_long_array[i-1])
check_result = check_text(new_text_params)
if check_result[:status].to_i == -1
return check_result
break
else
if i == text_long_array.size
return check_result
else
next
end
end
end
end
def check_text(text_params)
begin
dun_params = check_dun_params(text_params)
# api_url = Redmine::Configuration['dun']['text_api']
api_url = EduSetting.get("dun_text_api")
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.hostname, uri.port)
if api_url.include?("https://")
http.use_ssl = true
end
dun_params_str = URI.encode_www_form(dun_params)
header = {'content-type':'application/x-www-form-urlencoded'}
response = http.post(uri.path, dun_params_str, header)
response_body = eval(response.body)
Rails.logger.info("======response========#{response_body}")
if response_body[:code].to_i == 200
response_body_result = response_body[:result]
response_body_labels = response_body_result[:labels].present? ? response_body_result[:labels][0] : []
extra_params = {
action: response_body_result[:action],
taskId: response_body_result[:taskId],
infos: response_body_labels.present? ? sub_lables[:"#{response_body_labels[:subLabels][0][:subLabel]}"] : ""
}
render_status = response_body_result[:action].to_i == 0 ? 1 : -1
tip_status(render_status, response_body[:msg], extra_params)
else
tip_status(-1, response_body[:msg])
end
rescue Exception => ex
Rails.logger.info "*** transaction abored!"
Rails.logger.info "*** errors: #{ex.message}"
tip_status(-1, "检测失败")
end
end
private
def check_dun_params(text_params)
dun_public_params = DunCheck::PublicParams.new("text")
rand_data_id = random_dataId
check_params = {
dataId: rand_data_id,
version: "v3.1",
callback: rand_data_id
}.merge(text_params)
check_params.merge!(dun_public_params.call)
dun_params = dun_public_params.generate_sign(check_params)
return dun_params
end
def format_text(text_long, text_long_array)
slice_content = text_long.slice(0..4998)
last_slice_content = text_long.slice(4999..-1)
text_long_array.push(slice_content)
if last_slice_content.present?
if last_slice_content.length > 4999
format_text(last_slice_content, text_long_array)
else
text_long_array.push(last_slice_content)
end
end
end
def random_dataId
Digest::MD5.hexdigest(rand(100000000).to_s)
end
def check_labels
# 100色情200广告260广告法300暴恐400违禁500涉政600谩骂700灌水
%w(100 200 260 300 400 500 600 700).join(",")
end
def tip_status(status, message, msg_params={})
return {status: status, message: message, extra_params: msg_params}
end
def sub_lables
{
"100001": "色情其他",
"100002": "色情传播",
"100003": "色情性器官",
"100004": "色情挑逗",
"100005": "色情低俗段子",
"100006": "色情性行为",
"100007": "色情舆情事件",
"100008": "色情交友类",
"200009": "商业推广",
"200010": "广告法",
"200011": "刷量行为",
"200012": "广告其他",
"260052": "广告法-涉医疗用语(非药品禁止宣传药效)",
"260053": "广告法-迷信用语",
"260054": "广告法-需要凭证(可以写但需要凭证证明)",
"260055": "广告法-限时性用语(可以写但必须有具体时间)",
"260056": "广告法-涉嫌诱导消费者",
"260057": "广告法-涉嫌欺诈消费者",
"260058": "广告法-法律风险较高",
"260059": "广告法-极限词(用语绝对化)",
"300016": "暴恐其他",
"400017": "违禁其他",
"400021": "违禁网监要求",
"500013": "涉政其他",
"500014": "敏感专项",
"500015": "严格涉政",
"500039": "时事报道",
"500040": "领导人相关",
"500041": "英雄烈士相关",
"500042": "邪教迷信",
"500043": "落马官员相关",
"500044": "热点舆情",
"500045": "涉政综合",
"600018": "谩骂其他",
"700019": "灌水其他",
"900020": "其他",
}
end
end

View File

@ -0,0 +1,30 @@
# == Schema Information
#
# Table name: apply_signatures
#
# id :integer not null, primary key
# user_id :integer
# project_id :integer
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_apply_signatures_on_project_id (project_id)
# index_apply_signatures_on_user_id (user_id)
#
class ApplySignature < ApplicationRecord
belongs_to :user
belongs_to :project
has_many :attachments, as: :container, dependent: :destroy
scope :with_user_id, -> (user_id) {where(user_id: user_id)}
scope :with_status, -> (status) {where(status: status) if status.present? && status != "all"}
validates :project_id, uniqueness: {scope: :user_id}
enum status: {unpassed: -1, waiting: 0, passed: 1}
end

View File

@ -17,7 +17,7 @@
# disk_directory :string(255)
# attachtype :integer default("1")
# is_public :integer default("1")
# copy_from :string(255)
# copy_from :integer
# quotes :integer default("0")
# is_publish :integer default("1")
# publish_time :datetime
@ -26,15 +26,15 @@
# 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_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)
#
class Attachment < ApplicationRecord
@ -42,7 +42,7 @@ class Attachment < ApplicationRecord
include Publicable
include Publishable
include Lockable
include DunCheckImageAble
belongs_to :container, polymorphic: true, optional: true
belongs_to :author, class_name: "User", foreign_key: :author_id
# belongs_to :course, foreign_key: :container_id, optional: true

View File

@ -1,21 +1,3 @@
# == Schema Information
#
# Table name: chart_rules
#
# id :integer not null, primary key
# rule_type :string(255)
# content :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# competition_id :integer
# competition_stage_id :integer
#
# Indexes
#
# index_chart_rules_on_competition_id (competition_id)
# index_chart_rules_on_competition_stage_id (competition_stage_id)
#
class ChartRule < ApplicationRecord
validates :content, length: { maximum: 1000, too_long: "不能超过1000个字符" }

View File

@ -1,22 +1,3 @@
# == Schema Information
#
# Table name: stages
#
# id :integer not null
# subject_id :integer
# name :string(255)
# description :text(65535)
# user_id :integer
# position :integer
# created_at :datetime not null
# updated_at :datetime not null
# shixuns_count :integer default("0")
#
# Indexes
#
# index_stages_on_subject_id (subject_id)
#
class Ci::Stage < Ci::RemoteBase
self.primary_key = 'stage_id'

View File

@ -39,14 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
#
# Indexes
#
@ -54,9 +53,8 @@
# 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) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#

View File

View File

@ -0,0 +1,50 @@
module DunCheckAble
extend ActiveSupport::Concern
included do
validate :check_text_able
end
def check_text_able
dun_check_params = get_model
if dun_check_params[:is_change]
dun_check_params.delete(:is_change)
check_result = DunCheck::TextCheck.new(dun_check_params).call
if check_result[:status].to_i == -1
errors.add(:base, "内容含有:#{check_result[:extra_params][:infos]},请修改")
# raise ActiveRecord::RecordInvalid.new(self)
end
end
end
def get_model
dun_model = self.class.name
case dun_model
when "Issue"
check_params = {
title: self.subject,
content: self.description,
is_change: (self.subject_changed? || self.description_changed?) && self.subject.present? && self.description.present?
}
when "PullRequest"
check_params = {
title: "",
content: self.body,
is_change: self.body_changed? && self.body.present?
}
when "Journal"
check_params = {
title: "",
content: self.notes,
is_change: self.notes_changed? && self.notes.present?
}
when "Version"
check_params = {
title: self.name,
content: self.description,
is_change: (self.name_changed? || self.description_changed?) && self.name.present? && self.description.present?
}
end
return check_params
end
end

View File

@ -0,0 +1,33 @@
module DunCheckImageAble
extend ActiveSupport::Concern
included do
def self.check_image_able(file)
original_filename = file.original_filename
file_extention = original_filename.split(".").last
check_include = %w(jpg png bmp gif webp tiff jpeg)
if file_extention && check_include.include?(file_extention)
base64_file = Base64.encode64(file.open.read.force_encoding(Encoding::UTF_8))
check_params = [
{
name: original_filename,
type: 2,
data: base64_file,
}
]
check_result = DunCheck::ImageCheck.new(check_params).call
if check_result[:status].to_i == -1
return {status: -1, message: check_result[:message]}
else
return {status: 1}
end
else
return {status: 1}
end
end
end
end

View File

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

View File

@ -7,6 +7,7 @@ module ProjectAbility
def can_read_project?(project)
return true if self.admin?
return true if project.is_secret
return false if !project.is_public? && !project.member?(self.id)
true
end

View File

@ -11,8 +11,8 @@ module ProjectOperable
has_many :team_projects, dependent: :destroy
end
def add_member!(user_id, role_name='Developer')
member = members.create!(user_id: user_id)
def add_member!(user_id, role_name='Developer', is_apply_signature=false)
member = members.create!(user_id: user_id, is_apply_signature: is_apply_signature)
set_developer_role(member, role_name)
end
@ -89,7 +89,4 @@ module ProjectOperable
member.member_roles.create!(role: role)
end
def has_menu_permission(unit_type)
self.project_units.where(unit_type: unit_type).exists?
end
end

View File

@ -6,7 +6,6 @@ module Watchable
has_many :watcher_users, through: :watchers, source: :user, validate: false
scope :watched_by, -> (user_id) { includes(:watchers).where(watchers: { user_id: user_id }) }
scope :following, -> (user_id) { watched_by(user_id) }
end
def watched?(watchable)
@ -22,24 +21,6 @@ module Watchable
obj.destroy! if obj.present?
end
# 我正在关注的、我追随的
def following
User.following(self.id)
end
def following_count
following.size
end
# 关注我的、我的粉丝、我的追随者
def followers
watcher_users
end
def followers_count
followers.size
end
module ClassMethods
end
end

View File

@ -1,38 +1,3 @@
# == Schema Information
#
# Table name: discusses
#
# id :integer not null, primary key
# user_id :integer
# dis_type :string(255)
# dis_id :integer
# content :text(65535)
# parent_id :integer
# root_id :integer
# praise_count :integer
# created_at :datetime not null
# updated_at :datetime not null
# challenge_id :integer
# reward :integer
# hidden :boolean default("0")
# last_reply_id :integer
# position :integer
# praises_count :integer default("0")
# sticky :boolean default("0")
# course_sticky :boolean default("0")
# course_hidden :boolean default("0")
# copy_message_id :integer
#
# Indexes
#
# index_discusses_on_challenge_id (challenge_id)
# index_discusses_on_copy_message_id (copy_message_id)
# index_discusses_on_course_hidden (course_hidden)
# index_discusses_on_course_sticky (course_sticky)
# index_discusses_on_dis_id_and_dis_type (dis_id,dis_type)
# index_discusses_on_user_id (user_id)
#
class Discuss < ApplicationRecord
default_scope { order(created_at: :desc) }

View File

@ -1,24 +1,5 @@
# == Schema Information
#
# Table name: forge_activities
#
# id :integer not null, primary key
# user_id :integer
# project_id :integer
# forge_act_id :integer
# forge_act_type :string(255)
# org_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# forge_act_index (project_id,forge_act_id,created_at,forge_act_type)
# index_forge_activities_on_forge_act_id (forge_act_id)
#
class ForgeActivity < ApplicationRecord
belongs_to :user
belongs_to :project
belongs_to :forge_act, polymorphic: true
end
end

View File

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: helps
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# about_us :text(65535)
# agreement :text(65535)
# status :text(65535)
# help_center :text(65535)
# join_us :text(65535)
#
class Help < ApplicationRecord
end
end

View File

@ -50,6 +50,7 @@
class Issue < ApplicationRecord
#issue_type 1为普通2为悬赏
include DunCheckAble
belongs_to :project, :counter_cache => true
belongs_to :tracker,optional: true
has_many :project_trends, as: :trend, dependent: :destroy

View File

@ -22,6 +22,7 @@
#
class Journal < ApplicationRecord
include DunCheckAble
belongs_to :user
belongs_to :issue, foreign_key: :journalized_id, :touch => true
has_many :journal_details, :dependent => :delete_all

View File

@ -10,7 +10,6 @@
# sync_course :boolean default("0")
# sync_subject :boolean default("0")
# sync_shixun :boolean default("0")
# is_local :boolean default("0")
#
# Indexes
#
@ -42,9 +41,10 @@ class Laboratory < ApplicationRecord
delegate :name, :navbar, :footer, :login_logo_url, :nav_logo_url, :tab_logo_url, :default_navbar, to: :laboratory_setting
# TODO 域名申请后更改
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' ? "39.105.176.215" : '39.105.176.215'
identifier ? "#{identifier}#{suffix}" : ''
end

View File

@ -7,8 +7,11 @@
# content :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# is_secret :boolean default("0")
#
class License < ApplicationRecord
include Projectable
has_many :attachments, as: :container, dependent: :destroy
end

View File

@ -1,27 +1,3 @@
# == Schema Information
#
# Table name: live_links
#
# id :integer not null, primary key
# course_id :integer
# user_id :integer
# url :string(255)
# description :text(65535)
# on_status :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
# course_name :string(255)
# platform :string(255)
# live_time :datetime
# duration :integer
# position :integer
#
# Indexes
#
# index_live_links_on_course_id (course_id)
# index_live_links_on_user_id (user_id)
#
class LiveLink < ApplicationRecord
# belongs_to :course
belongs_to :user

View File

@ -11,6 +11,7 @@
# course_group_id :integer default("0")
# is_collect :integer default("1")
# graduation_group_id :integer default("0")
# is_apply_signature :boolean default("0")
#
# Indexes
#

View File

@ -1,18 +1,3 @@
# == Schema Information
#
# Table name: message_details
#
# id :integer not null, primary key
# content :text(4294967295)
# message_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_message_details_on_message_id (message_id)
#
class MessageDetail < ApplicationRecord
# belongs_to :message, :touch => true
validates :content, length: { maximum: 10000, too_long: "内容不能超过10000个字符" }

View File

@ -39,14 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
#
# Indexes
#
@ -54,9 +53,8 @@
# 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) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#
@ -80,8 +78,8 @@ class Organization < Owner
scope :with_visibility, ->(visibility) { joins(:organization_extension).where(organization_extensions: {visibility: visibility}) if visibility.present? }
def self.build(name, nickname, gitea_token=nil)
self.create!(login: name, nickname: nickname, gitea_token: gitea_token)
def self.build(name, gitea_token=nil)
self.create!(login: name, gitea_token: gitea_token)
end
def can_create_project?(user_id)
@ -115,9 +113,7 @@ class Organization < Owner
end
def real_name
name = lastname + firstname
name = name.blank? ? (nickname.blank? ? login : nickname) : name
name.gsub(/\s+/, '').strip #6.11 -hs
login
end
def show_real_name

View File

@ -0,0 +1,18 @@
# == Schema Information
#
# Table name: phenglei_users
#
# id :integer not null, primary key
# phone :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class PhengleiUser < ApplicationRecord
validates :phone, uniqueness: true
def register
User.find_by(phone: self.phone)
end
end

View File

@ -37,6 +37,8 @@
# 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")
@ -50,11 +52,6 @@
# open_devops_count :integer default("0")
# recommend :boolean default("0")
# platform :integer default("0")
# license_id :integer
# ignore_id :integer
# default_branch :string(255) default("master")
# website :string(255)
# lesson_url :string(255)
#
# Indexes
#
@ -71,6 +68,7 @@
# index_projects_on_updated_on (updated_on)
#
class Project < ApplicationRecord
include Matchable
include Publicable
@ -110,16 +108,17 @@ class Project < ApplicationRecord
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
has_one :project_detail, dependent: :destroy
has_many :apply_signatures, dependent: :destroy
has_many :team_projects, dependent: :destroy
has_many :project_units, dependent: :destroy
after_save :check_project_members
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)}
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) }
delegate :content, to: :project_detail, allow_nil: true
delegate :name, to: :license, prefix: true, allow_nil: true
scope :secret_and_visible, -> {left_outer_joins(:license).where("licenses.is_secret = TRUE OR projects.is_public = TRUE")}
delegate :is_secret, to: :license, allow_nil: true
def self.search_project(search)
@ -158,7 +157,6 @@ class Project < ApplicationRecord
#创建项目管理员
def check_project_members
return if owner.is_a?(Organization)
unless members.present? && members.exists?(user_id: self.user_id)
member_params = {
user_id: self.user_id,
@ -240,12 +238,10 @@ class Project < ApplicationRecord
end
def get_premission user
return "Owner" if owner?(user)
return "Manager" if manager?(user)
return "Developer" if develper?(user)
return "Reporter" if reporter?(user)
permission = "Reporter"
member = members.find_by(user: user)
return ""
member&.roles&.last&.name || permission
end
def fork_project

View File

@ -8,10 +8,23 @@
# projects_count :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
#
# Indexes
#
# index_project_categories_on_ancestry (ancestry)
#
class ProjectCategory < ApplicationRecord
include Projectable
has_ancestry
def self.descendants
where.not(ancestry: [nil, ""])
end
def self.get_children(target_id)
where(ancestry: target_id).pluck(:id,:name)
end
end

View File

@ -1,35 +0,0 @@
# == Schema Information
#
# Table name: project_units
#
# id :integer not null, primary key
# project_id :integer
# unit_type :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_project_units_on_project_id (project_id)
#
class ProjectUnit < ApplicationRecord
belongs_to :project
enum unit_type: {code: 1, issues: 2, pulls: 3, devops: 4, versions: 5, resources: 6}
validates :unit_type, uniqueness: { scope: :project_id}
def self.init_types(project_id)
ProjectUnit::unit_types.each do |_, v|
self.create!(project_id: project_id, unit_type: v)
end
end
def self.update_by_unit_types!(project, types)
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
end
end

View File

@ -24,6 +24,7 @@
#
class PullRequest < ApplicationRecord
include DunCheckAble
#status 0 默认未合并, 1表示合并, 2表示请求拒绝(或已关闭)
OPEN = 0
MERGED = 1

View File

@ -25,6 +25,7 @@
#
# Indexes
#
# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id)
#
@ -40,8 +41,6 @@ class Repository < ApplicationRecord
validates :identifier, presence: true
delegate :default_branch, to: :project, allow_nil: true
def to_param
self.identifier.parameterize
end

View File

@ -1,39 +1,3 @@
# == Schema Information
#
# Table name: schools
#
# id :integer not null, primary key
# name :string(255)
# province :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# logo_link :string(255)
# pinyin :string(255)
# school_type :integer default("0")
# city :string(255)
# address :string(255)
# auto_users_trial :boolean default("0")
# shool_code :string(255)
# authorization_time :datetime
# ec_auth :integer default("0")
# identifier :string(255)
# is_online :boolean default("0")
# video_name :string(255)
# video_desc :string(255)
# course_link :string(255)
# course_name :string(255)
# partner_id :integer
# customer_id :integer
# school_property_id :integer
#
# Indexes
#
# index_schools_on_customer_id (customer_id)
# index_schools_on_identifier (identifier)
# index_schools_on_partner_id (partner_id)
# index_schools_on_school_property_id (school_property_id)
#
class School < ApplicationRecord
has_many :departments, dependent: :destroy

View File

@ -1,72 +0,0 @@
# == Schema Information
#
# Table name: sites
#
# id :integer not null, primary key
# name :string(255)
# url :string(255)
# key :string(255)
# site_type :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Site < ApplicationRecord
# add: 添加类链接
# personal: 个人名下类链接,
# common: 普通链接
enum site_type: { add: 0, personal: 1, common: 2 }
def self.set_default_menu
set_add_menu!
set_personal_menu!
set_common_menu!
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_r', url: '/organize/new'}]
adds.each { |ele|
Site.find_or_create_by(key: ele[:key]) do |site|
site.name = ele[:name]
site.url = ele[:url]
site.site_type = Site.site_types[:add]
end
}
end
def self.set_personal_menu!
personals = [
{name: '个人中心', key: 'my_page', url: '/users/current_user'},
{name: '我的组织', key: 'my_organizes', url: '/users/current_user/organizes'}
]
personals.each { |ele|
Site.find_or_create_by(key: ele[:key]) do |site|
site.name = ele[:name]
site.url = ele[:url]
site.site_type = Site.site_types[:personal]
end
}
end
def self.set_common_menu!
commons = [
{name: '通知', key: 'notice', url: '/users/current_user/user_messages'},
{name: '找回密码', key: 'lost_password', url: '/account/lost_password'},
{name: '注册', key: 'register', url: '/login?login=false'}
]
commons.each { |ele|
Site.find_or_create_by(key: ele[:key]) do |site|
site.name = ele[:name]
site.url = ele[:url]
site.site_type = Site.site_types[:common]
end
}
end
end

View File

@ -14,7 +14,6 @@
# gtid :integer
# created_at :datetime not null
# updated_at :datetime not null
# nickname :string(255)
#
# Indexes
#

View File

@ -70,7 +70,7 @@ class Token < ActiveRecord::Base
# Delete all expired tokens
def self.destroy_expired
Token.delete_all ["action NOT IN (?) AND created_on < ?", ['feeds', 'api', 'autologin'], Time.now - @@validity_time]
Token.delete_all ["action NOT IN (?) AND created_on < ?", ['feeds', 'api', 'autologin', 'autologin_forge_military'], Time.now - @@validity_time]
end
# Returns the active user who owns the key for the given action

View File

@ -1,87 +1,4 @@
# == Schema Information
#
# Table name: courses
#
# id :integer not null, primary key
# tea_id :integer
# name :string(255)
# state :integer
# code :string(255)
# time :integer
# extra :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# location :string(255)
# term :string(255)
# string :string(255)
# password :string(255)
# setup_time :string(255)
# endup_time :string(255)
# class_period :integer default("0")
# school_id :integer
# description :text(65535)
# status :integer default("1")
# attachmenttype :integer default("2")
# lft :integer
# rgt :integer
# is_public :integer default("1")
# inherit_members :integer default("1")
# open_student :integer default("0")
# outline :integer default("0")
# publish_resource :integer default("0")
# is_delete :integer default("0")
# end_time :integer
# end_term :string(255)
# is_excellent :integer default("0")
# excellent_option :integer default("0")
# is_copy :integer default("0")
# visits :integer default("0")
# syllabus_id :integer
# invite_code :string(255)
# qrcode :string(255)
# qrcode_expiretime :integer default("0")
# invite_code_halt :integer default("0")
# os_allow :integer default("0")
# credit :float(24)
# is_end :boolean default("0")
# end_date :date
# choose_group_allow :boolean default("0")
# homepage_show :boolean default("0")
# course_list_id :integer
# members_count :integer default("0")
# homework_commons_count :integer default("0")
# show_unit :boolean default("0")
# teacher_list :string(255) default("老师")
# student_list :string(255) default("学生")
# is_hidden :boolean default("0")
# course_members_count :integer default("0")
# course_groups_count :integer default("0")
# authentication :boolean default("0")
# professional_certification :boolean default("0")
# graduation_topics_count :integer default("0")
# graduation_tasks_count :integer default("0")
# polls_count :integer default("0")
# exercises_count :integer default("0")
# start_date :date
# subject_id :integer default("0")
# excellent :boolean default("0")
# email_notify :boolean default("0")
# sticky :boolean default("0")
# sticky_time :datetime
# laboratory_id :integer
# mooc_course_id :integer
#
# Indexes
#
# index_courses_on_invite_code (invite_code) UNIQUE
# index_courses_on_laboratory_id (laboratory_id)
# index_courses_on_mooc_course_id (mooc_course_id)
# index_courses_on_school_id_and_is_delete (school_id,is_delete)
# index_courses_on_subject_id (subject_id)
# index_courses_on_tea_id (tea_id)
#
class Trustie::Course < Trustie::Database
has_many :course_groups, class_name: "Trustie::CourseGroup"
has_many :homework_commons, class_name: "Trustie::HomeworkCommon"
end
end

View File

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: course_groups
#
# id :integer not null, primary key
# name :string(255)
# course_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# members_count :integer
# invite_code :string(255)
# position :integer default("0")
# course_members_count :integer default("0")
# invite_code_halt :boolean default("0")
# invite_code_set :integer default("0")
#
# Indexes
#
# index_course_groups_on_course_id (course_id)
# index_course_groups_on_invite_code (invite_code) UNIQUE
#
class Trustie::CourseGroup < Trustie::Database
belongs_to :course, class_name: "Trustie::Course"
end
end

View File

@ -1,54 +1,3 @@
# == Schema Information
#
# Table name: homework_commons
#
# id :integer not null, primary key
# name :string(255)
# user_id :integer
# description :text(65535)
# publish_time :datetime
# end_time :datetime
# homework_type :integer default("1")
# late_penalty :string(255) default("0")
# course_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# teacher_priority :integer default("1")
# anonymous_comment :boolean default("0")
# quotes :integer default("0")
# is_open :integer default("0")
# simi_time :datetime
# score_open :boolean default("0")
# anonymous_appeal :boolean default("0")
# homework_bank_id :integer
# is_update :boolean default("0")
# is_public :boolean default("0")
# reference_answer :text(65535)
# answer_public :boolean default("0")
# archive_time :datetime
# allow_late :boolean default("0")
# late_time :datetime
# work_public :boolean default("0")
# explanation :text(65535)
# unified_setting :boolean default("1")
# comment_public :boolean default("1")
# course_homework_category_id :integer
# work_efficiency :boolean default("0")
# eff_score :float(24) default("0")
# max_efficiency :float(24) default("0")
# course_second_category_id :integer default("0")
# calculation_time :datetime
# position :integer default("0")
# total_score :float(24) default("100")
# category_position :integer default("0")
#
# Indexes
#
# index_homework_commons_on_course_id_and_id (course_id,id)
# index_homework_commons_on_course_second_category_id (course_second_category_id)
# index_homework_commons_on_homework_bank_id (homework_bank_id)
#
class Trustie::HomeworkCommon < Trustie::Database
belongs_to :course, class_name: "Trustie::Course"
end
end

View File

@ -39,14 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
#
# Indexes
#
@ -54,9 +53,8 @@
# 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) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#
@ -68,7 +66,6 @@ class User < Owner
include Likeable
include BaseModel
include Droneable
include User::Avatar
# include Searchable::Dependents::User
# devops step
@ -137,6 +134,10 @@ class User < Owner
has_many :attachments,foreign_key: :author_id, :dependent => :destroy
# 关注
# has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注
# has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户
has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', dependent: :destroy
# 认证
@ -155,6 +156,7 @@ class User < Owner
# has_many :libraries, dependent: :destroy
has_many :project_trends, dependent: :destroy
has_many :oauths , dependent: :destroy
has_many :apply_signatures, dependent: :destroy
has_many :organization_users, dependent: :destroy
has_many :organizations, through: :organization_users
@ -162,7 +164,7 @@ class User < Owner
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
scope :like, lambda { |keywords|
where("LOWER(concat(lastname, firstname, login, mail)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
where("LOWER(concat(nickname, lastname, firstname, login, mail)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
}
scope :simple_select, -> {select(:id, :login, :lastname,:firstname, :nickname, :gitea_uid, :type)}
@ -188,13 +190,9 @@ class User < Owner
validate :validate_sensitive_string
validate :validate_password_length
def name
login
end
# 删除自动登录的token一旦退出下次会提示需要登录
def delete_autologin_token(value)
Token.where(:user_id => id, :action => 'autologin', :value => value).delete_all
Token.where(:user_id => id, :action => autologin_name, :value => value).delete_all
end
def delete_session_token(value)
@ -206,7 +204,7 @@ class User < Owner
end
def project_manager?(project)
project.manager?(self) || self.admin?
project.managers.exists?(user: self) || self.admin?
end
# 学号
@ -580,8 +578,8 @@ class User < Owner
end
# Returns the user who matches the given autologin +key+ or nil
def self.try_to_autologin(key)
user = Token.find_active_user('autologin', key)
def self.try_to_autologin(key,type)
user = Token.find_active_user(type, key)
user.update(last_login_on: Time.now) if user
user
end
@ -745,6 +743,10 @@ class User < Owner
raise("昵称包含敏感词汇,请重新输入") if nickname && !HarmoniousDictionary.clean?(nickname)
end
def autologin_name
EduSetting.get('autologin_cookie_name') || "autologin_forge_military"
end
def set_laboratory
return unless new_record?

View File

@ -1,43 +0,0 @@
require 'letter_avatar/has_avatar'
require 'chinese_pinyin'
class User
module Avatar
extend ActiveSupport::Concern
include LetterAvatar::HasAvatar
def username
self.lastname.blank? ? self.login : Pinyin.t(self.lastname)
end
def get_letter_avatar_url(size = :lg)
avatar_path(self.username, size).split('public/')&.last
end
def self.get_letter_avatar_url(name)
return "" if name.blank?
avatar = LetterAvatar.generate Pinyin.t(name), 120
avatar.split('public/')&.last
end
def avatar_path(username, size)
LetterAvatar.generate username, avatar_size(size)
end
# 返回头像尺寸
# xs: 22px
# sm: 32px
# md: 48px
# lg: 120px
def avatar_size(size)
case size
when :xs then 22
when :sm then 32
when :md then 48
when :lg then 120
else size
end
end
end
end

View File

@ -12,9 +12,7 @@
#
# Indexes
#
# 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)
# index_user_actions_on_ip (ip)
#
class UserAction < ApplicationRecord

View File

@ -10,13 +10,10 @@
# 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)
# index_user_agents_on_user_id (user_id)
# index_user_agents_on_ip (ip) UNIQUE
#
class UserAgent < ApplicationRecord

View File

@ -22,9 +22,6 @@
# school_id :integer
# description :string(255) default("")
# department_id :integer
# honor :text(65535)
# edu_background :integer
# edu_entry_year :integer
#
# Indexes
#

View File

@ -24,6 +24,7 @@
#
class Version < ApplicationRecord
include DunCheckAble
belongs_to :project, counter_cache: true
has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id"
belongs_to :user, optional: true

View File

@ -25,7 +25,7 @@ class Ci::Builds::ListQuery < ApplicationQuery
scope
end
builds = builds.by_branch(params[:branch]) if params[:branch]
builds = scope.by_branch(params[:branch]) if params[:branch]
custom_sort(builds, params[:sort_by], params[:sort_direction])
end

View File

@ -51,7 +51,7 @@ class Projects::ListMyQuery < ApplicationQuery
q = projects.ransack(name_or_identifier_cont: params[:search])
scope = q.result.includes(:project_category, :project_language,:owner, :repository)
scope = q.result.includes(:project_category, :project_language,:owner, :repository, :members)
sort = params[:sort_by] || "updated_on"
sort_direction = params[:sort_direction] || "desc"

View File

@ -10,12 +10,12 @@ class Projects::ListQuery < ApplicationQuery
end
def call
q = Project.visible.by_name_or_identifier(params[:search])
q = Project.secret_and_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])
.with_project_language(params[:language_id]).order(order_index: :desc)
sort = params[:sort_by] || "updated_on"
sort_direction = params[:sort_direction] || "desc"

View File

@ -1,22 +0,0 @@
class Gitea::Repository::Contributors::GetService < Gitea::ClientService
attr_reader :owner, :repo_name
def initialize(owner, repo_name)
@owner = owner
@repo_name = repo_name
end
def call
response = get(url, params)
render_status(response)
end
private
def params
Hash.new.merge(token: owner.gitea_token)
end
def url
"/repos/#{owner.login}/#{repo_name}/contributors"
end
end

View File

@ -1,25 +0,0 @@
class Gitea::Repository::Files::GetService < Gitea::ClientService
attr_reader :owner, :repo_name, :ref, :q, :token
def initialize(owner, repo_name, ref, q=nil, token=nil)
@owner = owner
@repo_name = repo_name
@ref = ref
@q = q
@token = token
end
def call
response = get(url, params)
render_status(response)
end
private
def params
Hash.new.merge(token: token, ref: ref, q: q)
end
def url
"/repos/#{owner.login}/#{repo_name}/find"
end
end

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