Compare commits

..

61 Commits

Author SHA1 Message Date
young 1aaef7315b Readme相关内容更新 2021-12-09 13:39:51 +08:00
young e64dba2166 Update README.md 2021-12-09 13:34:33 +08:00
young e0941cb3ff Update README.md 2021-12-09 13:33:26 +08:00
young 6d84867e8a Update README.md 2021-12-09 13:32:26 +08:00
young 3af96e25c2 Update README.md 2021-12-09 13:31:27 +08:00
young bb017fee1d Update README.md 2021-12-09 13:22:28 +08:00
young 33158de968 Update README.md 2021-12-09 13:21:00 +08:00
young 0ea82fb6c7 Update README.md 2021-12-09 13:19:50 +08:00
young 78499d59e4 Update README.md 2021-12-09 13:18:45 +08:00
young b530683794 Update README.md 2021-12-09 13:16:34 +08:00
young e1753be346 Update README.md 2021-12-09 13:15:34 +08:00
young 9c9b71ba82 Update README.md 2021-12-09 13:13:05 +08:00
young 8542f585a1 Update README.md 2021-12-09 13:09:12 +08:00
young cae6d3c8dd Update README.md 2021-12-09 13:07:33 +08:00
young 9f262ed66c Update README.md 2021-12-09 13:04:14 +08:00
young 2aa908ee52 Update README.md 2021-12-09 13:03:29 +08:00
young cc837516a8 Update README.md 2021-12-09 13:00:40 +08:00
young c32e1ac332 Update README.md 2021-12-09 12:48:54 +08:00
young c6f6d4b964 Update README.md 2021-12-09 12:45:28 +08:00
young 08eccdcfb4 Update README.md 2021-12-09 12:43:08 +08:00
young 4a6c481126 Update README.md 2021-12-09 12:39:13 +08:00
young 2297477806 Update README.md 2021-12-09 12:33:05 +08:00
young 7bc167250f Update README.md 2021-12-09 12:32:07 +08:00
young afcb8c4ba5 Update README.md 2021-12-09 12:30:37 +08:00
young 028c38dc0d Update README.md 2021-12-09 12:29:27 +08:00
young 4a3d5b94fb Update README.md 2021-12-09 12:28:25 +08:00
young 07767c3c15 Update README.md 2021-12-08 20:21:55 +08:00
xiaoxiaoqiong b733f22cd6 前端build文件 2021-12-08 15:07:53 +08:00
xiaoxiaoqiong c62065af12 Merge branch 'pre_trustie_server' into standalone 2021-12-08 15:01:10 +08:00
xxq250 a7f719c8bb Merge pull request 'Readme相关内容更新' (#279) from young/forgeplus:standalone into standalone 2021-12-07 17:07:49 +08:00
xiaoxiaoqiong d4ee468435 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 17:03:02 +08:00
xiaoxiaoqiong 3480e15c48 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 16:49:21 +08:00
xiaoxiaoqiong 2116af759d Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 16:40:18 +08:00
xiaoxiaoqiong 3501ff6bd4 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 16:34:29 +08:00
xiaoxiaoqiong 8f70d4f604 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 16:32:33 +08:00
xiaoxiaoqiong d4663e410d Merge branch 'standalone_develop' into pre_trustie_server 2021-12-07 16:27:52 +08:00
young 4144128cd1 Update README.md 2021-12-06 11:16:52 +08:00
young e1636bc665 Update README.md 2021-12-06 11:14:57 +08:00
young 4404d947fd Update README.md 2021-12-06 11:12:10 +08:00
young 66e01e9902 Update README.md 2021-12-06 10:59:49 +08:00
young 1502816374 Update README.md 2021-12-06 10:59:19 +08:00
young a1a866a308 Update README.md 2021-12-06 10:58:25 +08:00
Yang Zhang 79696ce7fc add pictures in readme 2021-12-06 10:55:05 +08:00
Yang Zhang 6badf203fb update readme 2021-12-06 10:48:48 +08:00
xiaoxiaoqiong eac97c6698 关闭项目精选筛选 2021-12-01 17:45:02 +08:00
xiaoxiaoqiong 34bcf9ed57 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-01 17:21:54 +08:00
xiaoxiaoqiong cd4ba9c1d9 Merge branch 'standalone_develop' into pre_trustie_server 2021-12-01 10:05:37 +08:00
xiaoxiaoqiong f12b10fa23 merge 测试环境standalone_develop 2021-12-01 10:05:00 +08:00
yystopf 72ec7bc213 fix: change email default rule 2021-11-19 10:57:25 +08:00
jasder 7a37a32eee Merge branch 'standalone' of https://git.trustie.net/Gitlink/forgeplus into standalone 2021-11-14 21:15:39 +08:00
jasder 16bfd3b2e3 Merge branch 'standalone_develop' into standalone 2021-11-14 21:15:18 +08:00
jasder cc3de099fe Merge pull request '修复readme文件中的错别字' (#247) from starlee/forgeplus:standalone into standalone 2021-11-14 20:36:07 +08:00
starlee 8bfe421eaa fix a typo in README 2021-11-12 09:06:15 +08:00
jasder 7b5452fdcc Merge pull request 'FIX 合并测试版分支代码' (#229) from dev_trustie_server into trustie_server 2021-10-29 15:10:01 +08:00
jasder b40cbfbfbb FIX conflict 2021-10-29 15:07:01 +08:00
jasder 5d68b051db Merge branch 'develop' into standalone 2021-10-25 17:25:08 +08:00
jasder f2bee32eec Merge pull request 'ADD hompage' (#219) from jasder/forgeplus:standalone into standalone 2021-10-22 14:55:08 +08:00
jasder 21de628c11 FIX 集成平台首页功能 2021-10-22 14:53:09 +08:00
jasder 0fc00da95f Merge pull request 'fix css、icon bug' (#218) from jasder/forgeplus:standalone into standalone 2021-10-22 14:19:45 +08:00
jasder a7caca7210 Merge pull request 'FIX 提交前端页面代码' (#217) from jasder/forgeplus:standalone into standalone 2021-10-22 11:56:14 +08:00
jasder 6782380ff7 Merge pull request 'fix merge remote standalone branch' (#216) from jasder/forgeplus:standalone into standalone 2021-10-22 11:19:57 +08:00
836 changed files with 1616 additions and 3274 deletions

View File

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

143
README.md
View File

@ -1,17 +1,30 @@
Trustie (确实)是一个以大众化协同开发、开放式资源共享、持续性可信评估为核心机理,面向高校创新实践的在线协作平台。
# GitLink - CCF开源创新服务平台
## 特性
GitLink确实开源是中国计算机学会CCF官方指定的开源创新服务平台旨在以“为开源创新服务”为使命以“成为开源创新的汇聚地”为愿景秉承“创新、开放、协作、共享”的价值观致力于为大规模开源开放协同创新助力赋能打造创新成果孵化和新工科人才培养的开源创新生态
- 软件创作与生产深度融合的软件开发环境体系结构 软件自由创作和工程生产的高效衔接,适于软件开发中群体智慧的有效汇聚。
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/gitlink.png?raw=true" width=80% />
</center>
## 特色功能
- 构件化协同开发环境的可扩展运行框架多样化工具的集成和联动,形成了强动态扩展能力的平台框架。
- **分布式协作开发**基于Git打造分布式代码托管环境提供免费公、私有代码仓库支持在线文件编辑、代码分支管理、协作贡献统计、代码仓库复刻Fork、贡献合并请求PR、群智贡献审阅等功能让您的项目在这里健康、快速的成长
- “互联网即资源库”的全新软件复用模式 成长式软件资源管理系统,实现了分散资源的知识融合、资源的可持续增长和有效复用。
- **一站式过程管理**提供易修Issue、里程碑、通知提醒、标签归档等多样化任务管理工具支持各类开发任务的发布、指派与跟踪同时提供在线Wiki文档、组织多粒度管理等功能为您搭建一站式的项目过程管理环境让您的团队协作更高效、过程更透明
## 部署
- **高效流水线运维**融合DevOps思想提供轻量级的工作流引擎Engine打通编码、测试、构建、部署等开发运维环节支持自定义配置、代码静态扫描、构建自动触发、容器镜像托管等功能同时支持接入第三方运维工具让您的代码更加快速、可靠地形成高质量的产品
- **多层次代码分析**提供软件软代码和芯片RTL代码的溯源分析、文件级和组件级许可证识别及风险分析、输入性开源漏洞检测和加固建议支持分析结果的多层次可视化展示帮助您实施有效开源治理厘清代码引用链发现并消除漏洞感染链为安全合规的开源引用保驾护航
- **多维度用户画像**:实时采集和分析平台中的各类开源资源数据,搭建多维度用户画像评估系统,提供开发活动统计、贡献度日历、用户能力建模、角色与专业定位分析等功能,让您在个人主页展示开发动态与创新能力!
## 第三方组件
### Depends Versions
## 部署流程
### 依赖库
* Ruby 2.4.5
@ -23,22 +36,19 @@ Trustie (确实)是一个以大众化协同开发、开放式资源共享、
* imagemagick
### Steps
### 步骤
#### 1. 克隆稳定版本
1克隆稳定版本
```
git clone -b standalone https://git.trustie.net/jasder/forgeplus.git
```
#### 2. 安装依赖包
2安装依赖包
```bash
cd forgeplus && bundle install
```
#### 3. 配置初始化文件
进入项目根目录执行一下命令:
3配置初始化文件进入项目根目录执行以下命令
```bash
cp config/configuration.yml.example config/configuration.yml
cp config/database.yml.example config/database.yml
@ -46,11 +56,7 @@ touch config/redis.yml
touch config/elasticsearch.yml
```
#### 4. 配置数据库
数据库配置信息请查看/config/database.yml文件
项目默认采用mysql数据库, 如需更改,请自行修改配置信息,
默认配置如下:
4配置数据库数据库配置信息请查看/config/database.yml文件项目默认采用mysql数据库, 如需更改,请自行修改配置信息,默认配置如下
```bash
default: &default
adapter: mysql2
@ -60,14 +66,13 @@ default: &default
password: 123456
```
#### 5. 配置gitea服务(可选)
**如需要部署自己的gitea平台请参考gitea官方平台https://docs.gitea.io/zh-cn/install-from-binary/**
5配置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/Trustie/gitea-binary**
**配置gitea服务步骤**
1. 部署gitea服务并注册root账户
2. 修改forge平台的 config/configuration.yml中的gitea服务指向地址
- 配置gitea服务步骤
-- 部署gitea服务并注册root账户
-- 修改forge平台的 config/configuration.yml中的gitea服务指向地址
```ruby
gitea:
@ -77,10 +82,9 @@ gitea:
base_url: '/api/v1'
```
#### 6. 安装redis环境
**请自行搜索各平台如何安装部署redis环境**
6安装redis环境请自行搜索各平台如何安装部署redis环境
#### 7. 安装imagemagick插件
7安装imagemagick插件
- Mac OS X
```bash
brew install imagemagick ghostscript
@ -91,88 +95,95 @@ gitea:
sudo apt-get install -y imagemagick
```
#### 8. 创建数据库
**开发环境为development 生成环境为production**
8创建数据库开发环境为development 生成环境为production
```bash
rails db:create RAILS_ENV=development
```
#### 9. 导入数据表结构
9导入数据表结构
```bash
bundle exec rake sync_table_structure:import_csv
```
#### 10. 执行migrate迁移文件
**开发环境为development 生成环境为production**
10执行migrate迁移文件开发环境为development 生成环境为production
```bash
rails db:migrate RAILS_ENV=development
```
#### 11. clone前端代码
**将前端代码克隆到public/react目录下目录结构应该是: public/react/build**
11clone前端代码将前端代码克隆到public/react目录下目录结构应该是: public/react/build
```bash
git clone -b standalone https://git.trustie.net/jasder/build.git
```
#### 12. 启动redis(此处已mac系统为例)
12启动redis(此处以macOS系统为例)
```bash
redis-server&
```
#### 13. 启动sidekiq
**开发环境为development 生成环境为production**
13启动sidekiq开发环境为development 生成环境为production
```bash
bundle exec sidekiq -C config/sidekiq.yml -e production -d
```
#### 14. 启动rails服务
14启动rails服务
```bash
rails s
```
#### 15. 浏览器访问
在浏览器中输入如下地址访问:
15浏览器访问在浏览器中输入如下地址访问
```bash
http://localhost:3000/
```
#### 16. 其他说明
通过页面注册都第一个用户为平台管理员用户
16其他说明通过页面注册以第一个用户为平台管理员用户
## 页面展示
- 代码库
![](docs/figs/code.png?raw=true)
- 项目列表
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/project_list.png?raw=true" width=50% />
</center>
- 代码仓库
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/repo.png?raw=true" width=50% />
</center>
- 任务管理
![](docs/figs/issue_manage.png?raw=true)
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/issues.png?raw=true" width=50% />
</center>
- 合并请求
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/PR.png?raw=true" width=50% />
</center>
- 引擎配置
<center>
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/standalone/docs/figs/engine.png?raw=true" width=50% />
</center>
- 任务查看
![](docs/figs/issue_view.png?raw=true)
- 任务指派
![](docs/figs/issue_assign2.png?raw=true)
- 里程碑
![](docs/figs/milestone.png?raw=true)
### API
- [API文档](https://forgeplus.trustie.net/docs/api)
- [API](showdoc.com.cn)
账号forgeplus@admin.com 密码forge123
## 贡献代码
我们期待您向GitLink提交贡献在您贡献时请遵循以下流程
1. Fork 项目
2. 创建本地分支(git checkout -b my-new-feature)
3. 提交更改 (git commit -am 'Add some feature')
4. 推送到分支 (git push origin my-new-feature)
5. 向源项目的 **develop** 分支发起 Pull Request
## License
#### 指导文档
- [API文档](https://www.gitlink.org.cn/docs/api)
- [Git常用命令](https://git-scm.com/)
## 许可证协议

View File

@ -7,7 +7,6 @@ class AccountsController < ApplicationController
# 其他平台同步注册的用户
def remote_register
Register::RemoteForm.new(remote_register_params).validate!
username = params[:username]&.gsub(/\s+/, "")
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
email = params[:email]&.gsub(/\s+/, "")
@ -376,9 +375,5 @@ class AccountsController < ApplicationController
phone_or_mail = strip(reset_password_params[:login])
User.where("phone = :search OR mail = :search", search: phone_or_mail).last
end
def remote_register_params
params.permit(:username, :email, :password, :platform)
end
end

View File

@ -1,138 +0,0 @@
#coding=utf-8
class ClaimsController < ApplicationController
# skip_before_action :verify_authenticity_token
protect_from_forgery with: :null_session
before_action :require_login, except: [:index]
before_action :set_issue
def index
@user_claimed = 0
@claims = @issue.claims.claim_includes.order("created_at desc")
@claims.each do |claim|
if claim.user_id == current_user.id
@user_claimed = 1
break
end
end
render file: 'app/views/claims/list.json.jbuilder'
end
def create
@claim = Claim.find_by_sql(["select id from claims where issue_id=? and user_id=?",params[:issue_id], current_user.id])
if @claim.present?
return normal_status(-1,"您已经声明过该易修")
end
ActiveRecord::Base.transaction do
@claim = Claim.new(parse_issue_params(params))
if @claim.save
@claims = @issue.claims.claim_includes.order("created_at desc")
@user_claimed = 1
journal_params = {
journalized_id: params[:issue_id],
journalized_type: "Issue",
user_id: current_user.id ,
notes: "新建声明: #{params[:claim_note]}",
}
journal = Journal.new(journal_params)
if journal.save
render file: 'app/views/claims/list.json.jbuilder'
else
normal_status(-1,"新建声明关联评论操作失败")
end
else
normal_status(-1,"新建声明操作失败")
end
end
end
def update
@claim = Claim.find_by_id(params[:claim_id])
if @claim.blank?
return normal_status(-1,"易修不存在")
end
if @claim.user_id != current_user.id
return normal_status(-1,"你不能更新别人的声明")
end
ActiveRecord::Base.transaction do
if @claim.update_attribute(:note,params[:claim_note])
@claims = @issue.claims.claim_includes.order("created_at desc")
@user_claimed = 1
journal_params = {
journalized_id: params[:issue_id],
journalized_type: "Issue",
user_id: current_user.id ,
notes: "更新声明: #{params[:claim_note]}",
}
journal = Journal.new(journal_params)
if journal.save
render file: 'app/views/claims/list.json.jbuilder'
else
normal_status(-1,"新建声明关联评论操作失败")
end
else
normal_status(-1,"声明更新操作失败")
end
end
end
def destroy
@claim = Claim.find_by_sql(["select id from claims where issue_id=? and user_id=?",params[:issue_id], current_user.id])
if @claim.blank?
normal_status(-1,"您未曾声明过该易修")
else
@claim = @claim[0]
# 判断current user是否是claimer
ActiveRecord::Base.transaction do
if @claim.destroy
@claims = @issue.claims.claim_includes.order("created_at desc")
@user_claimed = 0
journal_params = {
journalized_id: params[:issue_id],
journalized_type: "Issue",
user_id: current_user.id ,
notes: "取消声明",
}
journal = Journal.new(journal_params)
if journal.save
render file: 'app/views/claims/list.json.jbuilder'
else
normal_status(-1,"新建声明关联评论操作失败")
end
else
normal_status(-1,"取消声明操作失败")
end
end
end
end
private
def parse_issue_params(params)
{
issue_id: params[:issue_id],
user_id: current_user.id,
note: params[:claim_note],
}
end
def set_issue
@issue = Issue.find_by_id(params[:issue_id])
unless @issue.present?
normal_status(-1, "易修不存在")
end
end
end

View File

@ -42,14 +42,12 @@ class CompareController < ApplicationController
end
def load_compare_params
# @base = Addressable::URI.unescape(params[:base])
@base = Base64.decode64(params[:base])
@base = Addressable::URI.unescape(params[:base])
@head = params[:head].include?('.json') ? params[:head][0..-6] : params[:head]
# @head = Addressable::URI.unescape(@head)
@head = Base64.decode64(@head)
end
def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, CGI.escape(base), CGI.escape(head), current_user.gitea_token)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token)
end
end

View File

@ -486,8 +486,7 @@ class IssuesController < ApplicationController
end
def operate_issue_permission
@issue = Issue.find_by_id(params[:id]) unless @issue.present?
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || (@project.is_public && @issue.nil?) || (@project.is_public && @issue.present? && @issue.author_id == current_user.id))
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || @project.is_public?)
end
def export_issues(issues)

View File

@ -28,7 +28,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
def create
ActiveRecord::Base.transaction do
tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name])
Organizations::CreateForm.new(organization_params.merge(original_name: "")).validate!
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
@ -39,7 +39,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
def update
ActiveRecord::Base.transaction do
Organizations::CreateForm.new(organization_params.merge(original_name: @organization.login)).validate!
Organizations::CreateForm.new(organization_params).validate!
login = @organization.login
@organization.login = organization_params[:name] if organization_params[:name].present?
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?

View File

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

View File

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

View File

@ -16,13 +16,13 @@ class ProjectsController < ApplicationController
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") && @project.forge?
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge?
menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls")
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki")
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops")
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources")
menu.append(menu_hash_by_name("activity"))
menu.append(menu_hash_by_name("settings")) if (current_user.admin? || @project.manager?(current_user)) && @project.forge?
menu.append(menu_hash_by_name("settings")) if current_user.admin? || @project.manager?(current_user)
render json: menu
end

View File

@ -56,7 +56,7 @@ class PullRequestsController < ApplicationController
end
def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
ActiveRecord::Base.transaction do
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success
@ -89,7 +89,6 @@ class PullRequestsController < ApplicationController
else
ActiveRecord::Base.transaction do
begin
return normal_status(-1, "title不能超过255个字符") if params[:title].length > 255
merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?

View File

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

View File

@ -1,852 +0,0 @@
# Projects
## 申请加入项目
申请加入项目
> 示例:
```shell
curl -X POST http://localhost:3000/api/applied_projects.json
```
```javascript
await octokit.request('POST /api/appliedr_projects.json')
```
### HTTP 请求
`POST /api/applied_projects.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|applied_project.code |是| |string |邀请码 |
|applied_project.role |否| |string |项目权限reporter: 报告者, developer: 开发者manager管理员 |
> 请求的JSON示例
```json
{
"applied_project": {
"code": "1una34",
"role": "developer"
}
}
```
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |申请id |
|status |string |申请状态canceled:取消,common:正在申请, accept:已接受,refuse:已拒绝|
|time_ago |string |项目申请创建的时间 |
|project.id |int |申请项目的id |
|project.identifier |string |申请项目的标识 |
|project.name |string |申请项目的名称 |
|project.description |string |申请项目的描述 |
|project.is_public |bool |申请项目是否公开 |
|project.owner.id |bool |申请项目拥有者id |
|project.owner.type |string |申请项目拥有者类型 |
|project.owner.name |string |申请项目拥有者昵称 |
|project.owner.login |string |申请项目拥有者标识 |
|project.owner.image_url |string |申请项目拥有者头像 |
|user.id |int |申请创建者的id |
|user.type |string |申请创建者的类型 |
|user.name |string |申请创建者的名称 |
|user.login |string |申请创建者的标识 |
|user.image_url |string |申请创建者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 74,
"identifier": "hehuisssjssjjsjs",
"name": "hehuisssjssjjsjs",
"description": "wwww",
"is_public": false,
"owner": {
"id": 10,
"type": "User",
"name": "testforge1",
"login": "testforge1",
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
}
},
"user": {
"id": 6,
"type": "User",
"name": "何慧",
"login": "yystopf",
"image_url": "images/avatars/User/6?t=1622513134"
},
"id": 7,
"status": "common",
"created_at": "2021-06-09 16:41",
"time_ago": "1分钟前"
}
```
## 获取项目列表
获取项目列表,也可以更加相关条件过滤搜素
> 示例:
```shell
curl -X GET \
-d "page=1" \
-d "limit=5" \
http://localhost:3000/api/projects | jq
```
```javascript
await octokit.request('GET /api/projects')
```
### HTTP 请求
`GET api/projects`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
page | false | 1 | string | 页数,第几页
limit | false | 15 | string | 每页多少条数据默认15条
sort_by | false | | string | 排序类型, 取值updated_on、created_on、forked_count、praises_count; updated_on: 更新时间排序created_on: 创建时间排序forked_count: fork数据排序praises_count: 点赞数量排序默认为updated_on更新时间排序
sort_direction| false | | string | 排序方式,取值为: desc、asc; desc: 降序排序, asc: 升序排序, 默认为desc
search | false | | string | 按照项目名称搜索
category_id | false | | int | 项目类别id
language_id | false | | int | 项目语言id
project_type | false | | string | 项目类型, 取值为common、mirror; common:开源托管项目, mirror:开源镜像项目
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
total_count | int | 项目总条数
id | string | 项目id
name | string | 项目名称
description | string | 项目简介
visits | int | 流量数
forked_count | int | 被fork的数量
praises_count | int | star数量
is_public | boolean | 是否公开, true:公开false:未公开
mirror_url | string | 镜像url
last_update_time| int | 最后更新时间为UNIX格式的时间戳
author | object | 项目创建者
-- name | string | 用户名,也是用户标识
category | object | 项目类别
-- id | int | 项目类型id
-- name | string | 项目类型名称
language | object | 项目语言
-- id | int | 项目语言id
-- name | string | 项目语言名称
> 返回的JSON示例:
```json
{
"total_count": 3096,
"projects": [
{
"id": 1400794,
"repo_id": 1402452,
"identifier": "cscw_2021_sponsor",
"name": "Sponsor机制下的开源贡献",
"description": "CSCW 2021 sponsor机制研究",
"visits": 5,
"praises_count": 0,
"forked_count": 0,
"is_public": true,
"mirror_url": null,
"type": 0,
"last_update_time": 1611971671,
"time_ago": "2天前",
"forked_from_project_id": null,
"open_devops": false,
"platform": "forge",
"author": {
"name": "张迅晖",
"login": "Nigel",
"image_url": "images/avatars/User/3675?t=1611832880"
},
"category": {
"id": 13,
"name": "云计算和大数据"
},
"language": {
"id": 34,
"name": "Python3.6"
}
}
]
}
```
<aside class="success">
Remember — a happy kitten is an authenticated kitten!
</aside>
## 推荐项目
获取推荐项目列表
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/projects/recommend | jq
```
```javascript
await octokit.request('GET /api/projects/recommend.json')
```
### HTTP 请求
`GET api/projects/recommend`
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
total_count |int |项目总条数
id |string |项目id
name |string|项目名称
description |string|项目简介
visits |int|流量数
forked_count |int|被fork的数量
praises_count |int|star数量
is_public |boolean|是否公开, true:公开false:未公开
mirror_url |string|镜像url
last_update_time|int|最后更新时间为UNIX格式的时间戳
author |object|项目创建者
-- name |string|用户名,也是用户标识
category |object|项目类别
-- id |int|项目类型id
-- name |string|项目类型名称
language |object|项目语言
-- id |int|项目语言id
-- name |string|项目语言名称
> 返回的JSON示例:
```json
[
{
"id": 20,
"repo_id": 2,
"identifier": "PNAekinmH",
"name": "FNILL",
"visits": 13567,
"author": {
"name": "王一达",
"login": "wangyida",
"image_url": "avatars/User/b"
},
"category": {
"id": 8,
"name": "其他"
}
}
]
```
<aside class="success">
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"
}
]
```
## 项目主页
获取项目主页信息
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/jasder/forgeplus/about | jq
```
```javascript
await octokit.request('GET /api/jasder/forgeplus/about')
```
### HTTP 请求
`GET api/:owner/:repo/about`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是| |string |用户登录名
repo |是| |string |项目标识identifier
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
identifier |string|project's identifier
content |string|主页内容
attachments |array|附件
> 返回的JSON示例:
```json
{
"content": "",
"identifier": "forgeplus",
attachments: []
}
```
<aside class="success">
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"
}
```
## 创建项目
创建项目
> 示例:
```shell
curl -X POST \
-d "user_id=36401" \
-d "name=hnfl_demo" \
-d "description=my first project" \
-d "repository_name=hnfl_demo" \
-d "project_category_id=1" \
-d "project_language_id=2" \
-d "ignore_id=2" \
-d "license_id=1" \
http://localhost:3000/api/projects.json
```
```javascript
await octokit.request('GET /api/projects.json')
```
### HTTP 请求
`POST api/projects`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|user_id |是| |int |用户id或者组织id |
|name |是| |string |项目名称 |
|description |是| |string |项目描述 |
|repository_name |是| |string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
|project_category_id|是| |int |项目类别id |
|project_language_id|是| |int |项目语言id |
|ignore_id |否| |int |gitignore相关id |
|license_id |否| |int |开源许可证id |
|private |否| |boolean|项目是否私有, true为私有false: 公开,默认为公开 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|name |string|项目名称|
> 返回的JSON示例:
```json
{
"id": 3240,
"name": "好项目"
}
```
## 创建镜像项目
创建镜像项目
> 示例:
```shell
curl -X POST \
-d "user_id=36408" \
-d "clone_addr=https://gitea.com/mx8090alex/golden.git" \
-d "name=golden_mirror1" \
-d "description=golden_mirror" \
-d "project_category_id=1" \
-d "project_language_id=2" \
http://localhost:3000/api/projects/migrate.json
```
```javascript
await octokit.request('GET /api/projects/migrate.json')
```
### HTTP 请求
`POST api/projects/migrate.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|user_id |是| |int |用户id或者组织id |
|name |是| |string |项目名称 |
|clone_addr |是| |string |镜像项目clone地址 |
|description |否| |string |项目描述 |
|repository_name |是| |string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 |
|project_category_id|是| |int |项目类别id |
|project_language_id|是| |int |项目语言id |
|is_mirror |否| |boolean|是否设置为镜像, true false默认为否 |
|auth_username |否| |string|镜像源仓库的登录用户名 |
|auth_password |否| |string|镜像源仓库的登录秘密 |
|private |否| |boolean|项目是否私有, true为私有false: 非私有,默认为公开 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|name |string|项目名称|
> 返回的JSON示例:
```json
{
"id": 3241,
"name": "这是一个镜像项目"
}
```
## 同步镜像
手动同步镜像
> 示例:
```shell
curl -X POST http://localhost:3000/api/repositories/1244/sync_mirror.json
```
```javascript
await octokit.request('POST /api/repositories/1244/sync_mirror.json')
```
### HTTP 请求
`POST api/repositories/:id/sync_mirror.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|id |是| |int |仓库id |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|status |int |状态码, 0:标识请求成功 |
|message |string|服务端返回的信息说明|
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
## Fork项目
fork项目
> 示例:
```shell
curl -X POST http://localhost:3000/api/jasder/forgeplus/forks.json
```
```javascript
await octokit.request('POST /api/jaser/jasder_test/forks.json')
```
### HTTP 请求
`POST api/:owner/:repo/forks.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |项目id |
|identifier |string|项目标识|
> 返回的JSON示例:
```json
{
"id": 3290,
"identifier": "newadm"
}
```
## 用户管理的组织列表
用户管理的组织列表
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizations.json | jq
```
```javascript
await octokit.request('GET /api/:owner/:repo/applied_transfer_projects/organizations')
```
### HTTP 请求
`GET api/:owner/:repo/applied_transfer_projects/organizations`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是| |string |用户登录名
repo |是| |string |项目标识identifier
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
name |string|组织标识
nickname |string|组织名称
description|string|组织描述
avatar_url|string组织头像
> 返回的JSON示例:
```json
{
"total_count": 3,
"organizations": [
{
"id": 9,
"name": "ceshi_org",
"nickname": "测试组织",
"description": "测试组织",
"avatar_url": "images/avatars/Organization/9?t=1612706073"
},
{
"id": 51,
"name": "ceshi",
"nickname": "测试组织哈哈哈",
"description": "23212312",
"avatar_url": "images/avatars/Organization/51?t=1618800723"
},
{
"id": 52,
"name": "ceshi1",
"nickname": "身份卡手动阀",
"description": "1231手动阀是的",
"avatar_url": "images/avatars/Organization/52?t=1618805056"
}
]
}
```
## 迁移项目
迁移项目edit接口is_transfering为true表示正在迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects.json
```
```javascript
await octokit.request('POST /api/:owner/:repo/applied_transfer_projects.json')
```
### HTTP 请求
`POST /api/:owner/:repo/applied_transfer_projects.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
|owner_name|是| |string |迁移对象标识 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |项目id |
|status |string |项目迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |string |项目迁移创建的时间 |
|project.id |int |迁移项目的id |
|project.identifier |string |迁移项目的标识 |
|project.name |string |迁移项目的名称 |
|project.description |string |迁移项目的描述 |
|project.is_public |bool |迁移项目是否公开 |
|project.owner.id |bool |迁移项目拥有者id |
|project.owner.type |string |迁移项目拥有者类型 |
|project.owner.name |string |迁移项目拥有者昵称 |
|project.owner.login |string |迁移项目拥有者标识 |
|project.owner.image_url |string |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 9,
"type": "Organization",
"name": "测试组织",
"login": "ceshi_org",
"image_url": "images/avatars/Organization/9?t=1612706073"
},
"id": 4,
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "1分钟前"
}
```
## 取消迁移项目
迁移项目edit接口is_transfering为true表示正在迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/cancel.json
```
```javascript
await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.json')
```
### HTTP 请求
`POST /api/:owner/:repo/applied_transfer_projects/cancel.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |迁移id |
|status |string |迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |string |迁移创建的时间 |
|project.id |int |迁移项目的id |
|project.identifier |string |迁移项目的标识 |
|project.name |string |迁移项目的名称 |
|project.description |string |迁移项目的描述 |
|project.is_public |bool |迁移项目是否公开 |
|project.owner.id |bool |迁移项目拥有者id |
|project.owner.type |string |迁移项目拥有者类型 |
|project.owner.name |string |迁移项目拥有者昵称 |
|project.owner.login |string |迁移项目拥有者标识 |
|project.owner.image_url |string |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 9,
"type": "Organization",
"name": "测试组织",
"login": "ceshi_org",
"image_url": "images/avatars/Organization/9?t=1612706073"
},
"id": 4,
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "1分钟前"
}
```

View File

@ -1240,11 +1240,11 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
@ -1337,11 +1337,11 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
@ -1440,11 +1440,11 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|issue|修已打开、已关闭、已重新打开或编辑|
|issue_assign|修被指派|
|issue_label|修标签被更新或删除|
|issue_milestone|修被收入里程碑|
|issue_comment|修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|

View File

@ -90,13 +90,13 @@ await octokit.request('GET /api/users/:login/messages.json')
#### 消息来源source字段说明
类型|说明
--------- | -----------
|IssueAssigned | 有新指派给我的修 |
|IssueAssignerExpire | 我负责的修截止日期到达最后一天 |
|IssueAtme | 在修中@我 |
|IssueChanged | 我创建或负责的修状态变更 |
|IssueCreatorExpire | 我创建的修截止日期到达最后一天 |
|IssueDeleted | 我创建或负责的修删除 |
|IssueJournal | 我创建或负责的修有新的评论 |
|IssueAssigned | 有新指派给我的修 |
|IssueAssignerExpire | 我负责的修截止日期到达最后一天 |
|IssueAtme | 在修中@我 |
|IssueChanged | 我创建或负责的修状态变更 |
|IssueCreatorExpire | 我创建的修截止日期到达最后一天 |
|IssueDeleted | 我创建或负责的修删除 |
|IssueJournal | 我创建或负责的修有新的评论 |
|LoginIpTip | 登录异常提示 |
|OrganizationJoined | 账号被拉入组织 |
|OrganizationLeft | 账号被移出组织 |
@ -104,7 +104,7 @@ await octokit.request('GET /api/users/:login/messages.json')
|ProjectDeleted | 我关注的仓库被删除 |
|ProjectFollowed | 我管理的仓库被关注 |
|ProjectForked | 我管理的仓库被复刻 |
|ProjectIssue | 我管理/关注的仓库有新的修 |
|ProjectIssue | 我管理/关注的仓库有新的修 |
|ProjectJoined | 账号被拉入项目 |
|ProjectLeft | 账号被移出项目 |
|ProjectMemberJoined | 我管理的仓库有成员加入 |
@ -250,7 +250,7 @@ await octokit.request('POST /api/users/:login/messages.json')
--------- | ----------- | -----------
|type | string | 消息类型 |
|receivers_login | array | 需要发送消息的用户名数组|
|atmeable_type | string | atme消息对象是从哪里@我的比如评论Journal、Issue、合并请求PullRequest |
|atmeable_type | string | atme消息对象是从哪里@我的比如评论Journal、Issue、合并请求PullRequest |
|atmeable_id | integer | atme消息对象id |
> 请求的JSON示例:
@ -469,7 +469,7 @@ await octokit.request('GET /api/template_message_settings.json')
"total_settings_count": 4,
"settings": [
{
"name": "修被指派",
"name": "修被指派",
"key": "IssueAssigned",
"notification_disabled": true,
"email_disabled": false
@ -488,7 +488,7 @@ await octokit.request('GET /api/template_message_settings.json')
"total_settings_count": 4,
"settings": [
{
"name": "有新的修",
"name": "有新的修",
"key": "Issue",
"notification_disabled": true,
"email_disabled": false
@ -875,7 +875,7 @@ await octokit.request('GET /api/users/:login/statistics/activity.json')
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|dates |array |时间 |
|issues_count |array |修数量|
|issues_count |array |修数量|
|pull_requests_count |array |合并请求数量|
|commtis_count |array |贡献数量|
@ -1084,7 +1084,7 @@ await octokit.request('GET /api/users/:login/project_trends.json')
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|total_count |int |所选时间内的总动态数 |
|project_trends.trend_type |string|动态类型IssueVersionRelease版本发布PullRequest合并请求|
|project_trends.trend_type |string|动态类型IssueVersionRelease版本发布PullRequest合并请求|
|project_trends.action_type |string|操作类型|
|project_trends.trend_id |integer|动态id|
|project_trends.user_name |string|用户名称|

View File

@ -1,6 +1,6 @@
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, :original_name
attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname
validates :name, :nickname, :visibility, presence: true
validates :name, :nickname, length: { maximum: 100 }
@ -9,7 +9,7 @@ class Organizations::CreateForm < BaseForm
validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
validate do
check_name(name) unless name.blank? || name == original_name
check_name(name) unless name.blank?
end
def check_name(name)

View File

@ -1,16 +0,0 @@
module Register
class RemoteForm < Register::BaseForm
# login 登陆方式,支持邮箱、登陆、手机号等
attr_accessor :username, :email, :password, :platform
validates :username, :email, :password, presence: true
validate :check!
def check!
Rails.logger.info "Register::RemoteForm params: username: #{username}; email: #{email}; password: #{password}; platform: #{platform}"
check_login(username)
check_mail(email)
check_password(password)
end
end
end

View File

@ -4,5 +4,5 @@ class Users::LoginForm
attr_accessor :password, :login
validates :login, presence: true
validates :password, presence: true, length: { minimum: 6, maximum: 16 }, format: { with: CustomRegexp::LOGIN_PASSWORD, message: "6~16位支持字母数字和符号" }
validates :password, presence: true, length: { minimum: 8, maximum: 16 }, format: { with: CustomRegexp::PASSWORD, message: "8~16位支持字母数字和符号" }
end

View File

@ -45,7 +45,7 @@ module RepositoriesHelper
end
end
def readme_render_decode64_content(str, owner, repo, ref)
def readme_render_decode64_content(str, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
@ -63,16 +63,13 @@ module RepositoriesHelper
if remove_title.length > 0
r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
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
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{r_content}&ref=#{ref}"].join
new_r_content = "#{path}" + new_r_content
end
content = content.gsub(/#{r_content}/, new_r_content)
end
@ -97,7 +94,7 @@ module RepositoriesHelper
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
readme_render_decode64_content(content, owner, repo, ref)
readme_render_decode64_content(content, path)
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)

View File

@ -26,12 +26,8 @@ module TagChosenHelper
end
def render_branches(project)
if project.educoder?
return ['master']
else
branches = Gitea::Repository::Branches::ListService.call(project&.owner, project.identifier)
branches.collect{|i| i["name"] if i.is_a?(Hash)}
end
branches = Gitea::Repository::Branches::ListService.call(project&.owner, project.identifier)
branches.collect{|i| i["name"] if i.is_a?(Hash)}
end
def render_cache_trackers

View File

@ -37,7 +37,6 @@ class SendTemplateMessageJob < ApplicationJob
issue = Issue.find_by_id(issue_id)
return unless operator.present? && issue.present?
# receivers = receivers.where.not(id: operator&.id)
receivers = User.where(id: receivers)
receivers_string, content, notification_url = MessageTemplate::IssueAtme.get_message_content(receivers, operator, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}, 2, operator_id)
when 'IssueChanged'
@ -94,6 +93,18 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'OrganizationRole'
user_id, organization_id, role = args[0], args[1], args[2]
user = User.find_by_id(user_id)
organization = Organization.find_by_id(organization_id)
return unless user.present? && organization.present?
receivers = User.where(id: user.id)
receivers_string, content, notification_url = MessageTemplate::OrganizationRole.get_message_content(receivers, organization, role)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id, role: role})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::OrganizationRole.get_email_message_content(receiver, organization, role)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectIssue'
operator_id, issue_id = args[0], args[1]
operator = User.find_by_id(operator_id)
@ -224,7 +235,6 @@ class SendTemplateMessageJob < ApplicationJob
pull_request = PullRequest.find_by_id(pull_request_id)
return unless operator.present? && pull_request.present?
# receivers = receivers.where.not(id: operator&.id)
receivers = User.where(id: receivers)
receivers_string, content, notification_url = MessageTemplate::PullRequestAtme.get_message_content(receivers, operator, pull_request)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}, 2, operator_id)
when 'PullRequestChanged'
@ -264,32 +274,6 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::PullRequestMerged.get_email_message_content(receiver, operator, pull_request)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'TeamJoined'
user_id, organization_id, team_id = args[0], args[1], args[2]
user = User.find_by_id(user_id)
organization = Organization.find_by_id(organization_id)
team = Team.find_by_id(team_id)
return unless user.present? && organization.present? && team.present?
receivers = User.where(id: user.id)
receivers_string, content, notification_url = MessageTemplate::TeamJoined.get_message_content(receivers, organization, team)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id, team_id: team.id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::TeamJoined.get_email_message_content(receiver, organization, team)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'TeamLeft'
user_id, organization_id, team_id = args[0], args[1], args[2]
user = User.find_by_id(user_id)
organization = Organization.find_by_id(organization_id)
team = Team.find_by_id(team_id)
return unless user.present? && organization.present? && team.present?
receivers = User.where(id: user.id)
receivers_string, content, notification_url = MessageTemplate::TeamLeft.get_message_content(receivers, organization, team)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id, team_id: team.id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::TeamLeft.get_email_message_content(receiver, organization, team)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
end
end
end

View File

@ -5,7 +5,6 @@ module CustomRegexp
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
LOGIN_PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{6,16}\z/
URL = /\Ahttps?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]\z/
IP = /^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/

View File

@ -1,21 +0,0 @@
# == Schema Information
#
# Table name: claims
#
# id :integer not null, primary key
# issue_id :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# note :text(65535)
#
# Indexes
#
# index_claims_on_issue_id (issue_id)
# index_claims_on_user_id (user_id)
#
class Claim < ApplicationRecord
belongs_to :user, foreign_key: :user_id
scope :claim_includes, ->{includes(:user)}
end

View File

@ -21,37 +21,13 @@ module ProjectOperable
end
def add_member!(user_id, role_name='Developer')
if self.owner.is_a?(Organization)
case role_name
when 'Manager'
team = self.owner.teams.admin.take
team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = TeamUser.build(self.user_id, user_id, team.id)
when 'Developer'
team = self.owner.teams.write.take
team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = TeamUser.build(self.user_id, user_id, team.id)
when 'Reporter'
team = self.owner.teams.read.take
team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = TeamUser.build(self.user_id, user_id, team.id)
end
end
member = members.create!(user_id: user_id, team_user_id: team_user&.id)
member = members.create!(user_id: user_id)
set_developer_role(member, role_name)
end
def remove_member!(user_id)
member = members.find_by(user_id: user_id)
member.destroy! if member && self.user_id != user_id
team_user = TeamUser.find_by_id(member&.team_user_id)
team_user.destroy! if team_user
end
def member?(user_id)
@ -71,28 +47,6 @@ module ProjectOperable
def change_member_role!(user_id, role)
member = self.member(user_id)
if self.owner.is_a?(Organization) && member.team_user.present?
case role&.name
when 'Manager'
team = self.owner.teams.admin.take
team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = member.team_user.update(team_id: team&.id)
when 'Developer'
team = self.owner.teams.write.take
team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = member.team_user.update(team_id: team&.id)
when 'Reporter'
team = self.owner.teams.read.take
team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team
TeamProject.build(self.user_id, team.id, self.id)
OrganizationUser.build(self.user_id, user_id)
team_user = member.team_user.update(team_id: team&.id)
end
end
member.member_roles.last.update_attributes!(role: role)
end

View File

@ -64,7 +64,6 @@ class Issue < ApplicationRecord
# has_many :memos
has_many :journals, :as => :journalized, :dependent => :destroy
has_many :journal_details, through: :journals
has_many :claims, :dependent => :destroy
has_many :issue_tags_relates, dependent: :destroy
has_many :issue_tags, through: :issue_tags_relates
has_many :issue_times, dependent: :destroy
@ -155,7 +154,7 @@ class Issue < ApplicationRecord
end
def is_collaborators?
self.assigned_to_id.present? ? self.project.member?(self.assigned_to_id) : false
self.assigned_to_id.present? ? self.project.members.where(user_id: self.assigned_to_id).present? : false
end
def get_issue_tags_name

View File

@ -11,26 +11,23 @@
# course_group_id :integer default("0")
# is_collect :integer default("1")
# graduation_group_id :integer default("0")
# team_user_id :integer
#
# Indexes
#
# index_members_on_course_id (course_id)
# index_members_on_project_id (project_id)
# index_members_on_team_user_id (team_user_id)
# index_members_on_user_id (user_id)
# index_members_on_user_id_and_project_id (user_id,project_id,course_id) UNIQUE
#
class Member < ApplicationRecord
belongs_to :user
# belongs_to :course, optional: true
belongs_to :project, optional: true
belongs_to :team_user, optional: true
has_many :member_roles, dependent: :destroy
has_many :roles, through: :member_roles
validates :user_id, :project_id, presence: true
end
class Member < ApplicationRecord
belongs_to :user
# belongs_to :course, optional: true
belongs_to :project, optional: true
has_many :member_roles, dependent: :destroy
has_many :roles, through: :member_roles
validates :user_id, :project_id, presence: true
end

View File

@ -17,25 +17,27 @@ class MessageTemplate < ApplicationRecord
def self.build_init_data
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个修')
self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个修')
self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_changed.html")
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_deleted.html")
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::LoginIpTip', sys_notice: '您的账号{nickname}于{login_time)在非常用的IP地址{ip}登录,如非本人操作,请立即修改密码', notification_url: '')
email_html = File.read("#{email_template_html_dir}/organization_joined.html")
self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: 'GitLink: 你已加入 {organization} 组织')
email_html = File.read("#{email_template_html_dir}/organization_left.html")
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织')
email_html = File.read("#{email_template_html_dir}/organization_role.html")
self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 <b>{organization}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '')
self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '<b>{nickname}</b> 关注了你管理的仓库', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_issue.html")
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个修')
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个修')
email_html = File.read("#{email_template_html_dir}/project_joined.html")
self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: 你已加入 {repository} 项目')
email_html = File.read("#{email_template_html_dir}/project_left.html")
@ -64,10 +66,6 @@ class MessageTemplate < ApplicationRecord
self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_merged.html")
self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/team_joined.html")
self.create(type: 'MessageTemplate::TeamJoined', sys_notice: '你已被拉入组织 <b>{organization}</b> 的 <b>{team}</b> 团队,拥有<b>{role}</b>权限', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/team_left.html")
self.create(type: 'MessageTemplate::TeamLeft', sys_notice: '你已被移出组织 <b>{organization}</b> 的 <b>{team}</b> 团队', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
end
def self.sys_notice

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 有新指派给我的
# 有新指派给我的
class MessageTemplate::IssueAssigned < MessageTemplate
# MessageTemplate::IssueAssigned.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last)

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 我负责的修截止日期到达最后一天
# 我负责的修截止日期到达最后一天
class MessageTemplate::IssueAssignerExpire < MessageTemplate
# MessageTemplate::IssueAssignerExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 在修中@我
# 在修中@我
class MessageTemplate::IssueAtme < MessageTemplate
# MessageTemplate::IssueAtme.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last)

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 我创建或负责的修状态变更
# 我创建或负责的修状态变更
class MessageTemplate::IssueChanged < MessageTemplate
# MessageTemplate::IssueChanged.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last, {status_id: [1, 2], assigned_to_id: [nil, 203], tracker_id: [4, 3], priority_id: [2, 4], fixed_version_id: [nil, 5], due_date: ['', '2021-09-11'], done_ratio: [0, 40], issue_tags_value: ["", "7"], branch_name: ["", "master"]})
@ -29,7 +29,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
content = MessageTemplate::IssueChanged.sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{title}', issue&.subject)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
change_count = change_params.keys.size
# 修负责人修改
# 修负责人修改
if change_params[:assigned_to_id].present?
assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
@ -44,7 +44,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
end
# 修状态修改
# 修状态修改
if change_params[:status_id].present?
status1 = IssueStatus.find_by_id(change_params[:status_id][0])
status2 = IssueStatus.find_by_id(change_params[:status_id][1])
@ -59,7 +59,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifstatus})(.*)({endstatus})/, '')
end
# 修类型修改
# 修类型修改
if change_params[:tracker_id].present?
tracker1 = Tracker.find_by_id(change_params[:tracker_id][0])
tracker2 = Tracker.find_by_id(change_params[:tracker_id][1])
@ -74,7 +74,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({iftracker})(.*)({endtracker})/, '')
end
# 修里程碑修改
# 修里程碑修改
if change_params[:fixed_version_id].present?
fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
@ -89,7 +89,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
end
# 修标记修改
# 修标记修改
if change_params[:issue_tags_value].present?
issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
@ -106,7 +106,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({iftag})(.*)({endtag})()/, '')
end
# 修优先级修改
# 修优先级修改
if change_params[:priority_id].present?
priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
@ -121,7 +121,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
end
# 修完成度修改
# 修完成度修改
if change_params[:done_ratio].present?
doneratio1 = change_params[:done_ratio][0]
doneratio2 = change_params[:done_ratio][1]
@ -136,7 +136,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '')
end
# 修指定分支修改
# 修指定分支修改
if change_params[:branch_name].present?
branch1 = change_params[:branch_name][0].blank? ? '分支未指定' : change_params[:branch_name][0]
branch2 = change_params[:branch_name][1].blank? ? '分支未指定' : change_params[:branch_name][1]
@ -151,7 +151,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifbranch})(.*)({endbranch})/, '')
end
# 修开始日期修改
# 修开始日期修改
if change_params[:start_date].present?
startdate1 = change_params[:start_date][0].blank? ? "未选择开始日期" : change_params[:start_date][0]
startdate2 = change_params[:start_date][1].blank? ? "未选择开始日期" : change_params[:start_date][1]
@ -166,7 +166,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '')
end
# 修结束日期修改
# 修结束日期修改
if change_params[:due_date].present?
duedate1 = change_params[:due_date][0].blank? ? '未选择结束日期' : change_params[:due_date][0]
duedate2 = change_params[:due_date][1].blank? ? '未选择结束日期' : change_params[:due_date][1]
@ -207,7 +207,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
content.gsub!('{title}', issue&.subject)
content.gsub!('{id}', issue&.id.to_s)
change_count = change_params.keys.size
# 修负责人修改
# 修负责人修改
if change_params[:assigned_to_id].present?
assigner1 = User.find_by_id(change_params[:assigned_to_id][0])
assigner2 = User.find_by_id(change_params[:assigned_to_id][1])
@ -222,7 +222,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifassigner})(.*)({endassigner})/, '')
end
# 修状态修改
# 修状态修改
if change_params[:status_id].present?
status1 = IssueStatus.find_by_id(change_params[:status_id][0])
status2 = IssueStatus.find_by_id(change_params[:status_id][1])
@ -237,7 +237,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifstatus})(.*)({endstatus})/, '')
end
# 修类型修改
# 修类型修改
if change_params[:tracker_id].present?
tracker1 = Tracker.find_by_id(change_params[:tracker_id][0])
tracker2 = Tracker.find_by_id(change_params[:tracker_id][1])
@ -252,7 +252,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({iftracker})(.*)({endtracker})/, '')
end
# 修里程碑修改
# 修里程碑修改
if change_params[:fixed_version_id].present?
fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0])
fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1])
@ -267,7 +267,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '')
end
# 修标记修改
# 修标记修改
if change_params[:issue_tags_value].present?
issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct
issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct
@ -284,7 +284,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({iftag})(.*)({endtag})()/, '')
end
# 修优先级修改
# 修优先级修改
if change_params[:priority_id].present?
priority1 = IssuePriority.find_by_id(change_params[:priority_id][0])
priority2 = IssuePriority.find_by_id(change_params[:priority_id][1])
@ -299,7 +299,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifpriority})(.*)({endpriority})/, '')
end
# 修完成度修改
# 修完成度修改
if change_params[:done_ratio].present?
doneratio1 = change_params[:done_ratio][0]
doneratio2 = change_params[:done_ratio][1]
@ -314,7 +314,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '')
end
# 修指定分支修改
# 修指定分支修改
if change_params[:branch_name].present?
branch1 = change_params[:branch_name][0].blank? ? '分支未指定' : change_params[:branch_name][0]
branch2 = change_params[:branch_name][1].blank? ? '分支未指定' : change_params[:branch_name][1]
@ -329,7 +329,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifbranch})(.*)({endbranch})/, '')
end
# 修开始日期修改
# 修开始日期修改
if change_params[:start_date].present?
startdate1 = change_params[:start_date][0].blank? ? "未选择开始日期" : change_params[:start_date][0]
startdate2 = change_params[:start_date][1].blank? ? "未选择开始日期" : change_params[:start_date][1]
@ -344,7 +344,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else
content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '')
end
# 修结束日期修改
# 修结束日期修改
if change_params[:due_date].present?
duedate1 = change_params[:due_date][0].blank? ? '未选择结束日期' : change_params[:due_date][0]
duedate2 = change_params[:due_date][1].blank? ? '未选择结束日期' : change_params[:due_date][1]

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 我创建的修截止日期到达最后一天
# 我创建的修截止日期到达最后一天
class MessageTemplate::IssueCreatorExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# 我创建或负责的修删除
# 我创建或负责的修删除
class MessageTemplate::IssueDeleted < MessageTemplate
# MessageTemplate::IssueDeleted.get_message_content(User.where(login: 'yystopf'), User.last, "hahah")

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# TODO 我创建或负责的修有新的评论
# TODO 我创建或负责的修有新的评论
class MessageTemplate::IssueJournal < MessageTemplate
# MessageTemplate::IssueJournal.get_message_content(User.where(login: 'yystopf'))

View File

@ -12,7 +12,7 @@
# email_title :string(255)
#
# TODO 我管理/关注的仓库有新的
# TODO 我管理/关注的仓库有新的
class MessageTemplate::ProjectIssue < MessageTemplate
# MessageTemplate::ProjectIssue.get_message_content(User.where(login: 'yystopf'), User.where(login: 'forgetest1'), User.last, Issue.last)

View File

@ -15,7 +15,7 @@
# 我管理的仓库项目设置被更改
class MessageTemplate::ProjectSettingChanged < MessageTemplate
# MessageTemplate::ProjectSettingChanged.get_message_content(User.where(login: 'yystopf'), User.last, Project.last, {description: '测试修改项目简介', category: '大数据', language: 'Ruby', permission: '公有', navbar: '修, 合并请求'})
# MessageTemplate::ProjectSettingChanged.get_message_content(User.where(login: 'yystopf'), User.last, Project.last, {description: '测试修改项目简介', category: '大数据', language: 'Ruby', permission: '公有', navbar: '修, 合并请求'})
def self.get_message_content(receivers, operator, project, change_params)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
@ -135,7 +135,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
unit_types.unshift('主页')
unit_types.append('动态')
navbar = unit_types.join('')
navbar.gsub!('issues', '修')
navbar.gsub!('issues', '修')
navbar.gsub!('pulls', '合并请求')
navbar.gsub!('wiki', 'Wiki')
navbar.gsub!('devops', '工作流')
@ -284,7 +284,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
unit_types.unshift('主页')
unit_types.append('动态')
navbar = unit_types.join('')
navbar.gsub!('issues', '修')
navbar.gsub!('issues', '修')
navbar.gsub!('pulls', '合并请求')
navbar.gsub!('wiki', 'Wiki')
navbar.gsub!('devops', '工作流')

View File

@ -1,58 +0,0 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 账号被拉入组织团队
class MessageTemplate::TeamJoined < MessageTemplate
# MessageTemplate::TeamJoined.get_message_content(User.where(login: 'yystopf'), Organization.last, Organization.last.teams.take)
def self.get_message_content(receivers, organization, team)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Permission"]
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{organization}', organization&.real_name).gsub('{team}', team&.nickname).gsub('{role}', team&.authorize_name)
url = notification_url.gsub('{login}', organization&.login)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::TeamJoined.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, organization, role)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Permission"]
title = email_title
title.gsub!('{organization}', organization&.real_name)
title.gsub!('{team}', team&.nickname)
title.gsub!('{role}', team&.authorize_name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::TeamJoined.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -1,58 +0,0 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 账号被移出组织团队
class MessageTemplate::TeamLeft < MessageTemplate
# MessageTemplate::TeamLeft.get_message_content(User.where(login: 'yystopf'), Organization.last, Organization.last.teams.take)
def self.get_message_content(receivers, organization, team)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["Normal::Permission"]
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{organization}', organization&.real_name).gsub('{team}', team&.nickname).gsub('{role}', team&.authorize_name)
url = notification_url.gsub('{login}', organization&.login)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::TeamLeft.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, organization, team)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::Permission"]
title = email_title
title.gsub!('{organization}', organization&.real_name)
title.gsub!('{team}', team&.nickname)
title.gsub!('{role}', team&.authorize_name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::TeamLeft.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -77,9 +77,6 @@
# index_projects_on_updated_on (updated_on)
#
class Project < ApplicationRecord
include Matchable
include Publicable

View File

@ -56,10 +56,10 @@ class Team < ApplicationRecord
def authorize_name
case self.authorize
when 'read' then '读取'
when 'write' then '写入'
when 'read' then '报告者'
when 'write' then '开发者'
when 'admin' then '管理员'
when 'owner' then '管理员'
when 'owner' then '拥有者'
else
''
end

View File

@ -22,17 +22,9 @@ class TeamUser < ApplicationRecord
belongs_to :team, counter_cache: :num_users
belongs_to :user
has_one :member
validates :user_id, uniqueness: {scope: [:organization_id, :team_id]}
before_destroy :remove_project_member
def self.build(organization_id, user_id, team_id)
self.create!(organization_id: organization_id, user_id: user_id, team_id: team_id)
end
def remove_project_member
member.destroy if member.present?
end
end

View File

@ -25,7 +25,7 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting
end
def self.build_init_data
self.find_or_create_by(name: "修状态变更", key: "IssueChanged")
self.find_or_create_by(name: "修状态变更", key: "IssueChanged")
self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged")
end
end

View File

@ -25,7 +25,7 @@ class TemplateMessageSetting::ManageProject < TemplateMessageSetting
end
def self.build_init_data
self.find_or_create_by(name: "有新的", key: "Issue")
self.find_or_create_by(name: "有新的", key: "Issue")
self.find_or_create_by(name: "有新的合并请求", key: "PullRequest")
self.find_or_create_by(name: "有成员变动", key: "Member")
self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged")

View File

@ -27,7 +27,7 @@ class TemplateMessageSetting::Normal < TemplateMessageSetting
self.find_or_create_by(name: "账号有权限变更", key: "Permission")
self.find_or_create_by(name: "被拉入或移出组织", key: "Organization")
self.find_or_create_by(name: "被拉入或移出项目", key: "Project")
self.find_or_create_by(name: "有新的修指派给我", key: "IssueAssigned")
self.find_or_create_by(name: "有新的修指派给我", key: "IssueAssigned")
self.find_or_create_by(name: "有新的合并请求指派给我", key: "PullRequestAssigned")
end
end

View File

@ -786,7 +786,7 @@ class User < Owner
end
def profile_is_completed?
self.nickname.present? && self.mail.present?
self.nickname.present? && self.gender.present? && self.mail.present? && self.custom_department.present?
end
protected

View File

@ -32,6 +32,6 @@ class AtmeService < ApplicationService
else
return
end
SendTemplateMessageJob.perform_later(message_source, receivers.pluck(:id), user.id, @atmeable.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_now(message_source, receivers, user.id, @atmeable.id) if Site.has_notice_menu?
end
end

View File

@ -16,7 +16,6 @@ class Gitea::Organization::UpdateService < Gitea::ClientService
def request_params
update_params = {
name: org.login,
full_name: org.nickname,
description: org.description,
location: org.location,
repo_admin_change_team_access: org.repo_admin_change_team_access,

View File

@ -55,12 +55,7 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService
when 201 then success(json_parse!(body))
when 403 then error("你没有权限操作!")
when 404 then error("你操作的链接不存在!")
when 422
if @body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*')
error("不合法的分支名称!")
else
error("#{filepath}文件已存在,不能重复创建!")
end
when 422 then error("#{filepath}文件已存在,不能重复创建!")
else error("系统错误!")
end
end

View File

@ -59,8 +59,6 @@ class Notice::Write::ClientService < ApplicationService
req.request :url_encoded
req.headers['Content-Type'] = 'application/json'
req.adapter Faraday.default_adapter
req.options.timeout = 100 # open/read timeout in seconds
req.options.open_timeout = 10 # connection open timeout in seconds
end
end

View File

@ -148,7 +148,6 @@ class PullRequests::CreateService < ApplicationService
def validate!
raise "title参数不能为空" if @params[:title].blank?
raise "title不能超过255个字符" if @params[:title].length > 255
raise "head参数不能为空" if @params[:head].blank?
raise "base参数不能为空" if @params[:base].blank?
raise "fork_project_id参数错误" if is_original && !@project.forked_projects.pluck(:id).include?(@params[:fork_project_id].to_i)

View File

@ -10,12 +10,20 @@ class Repositories::DetailService < ApplicationService
def call
return {
repo: repo_suitable,
contributor: contributor_suitable,
language: language_suitable,
branch_tag_total_count: branch_tag_total_count
}
rescue
return {
repo: {},
branch_tag_total_count: {}
release: [],
branch: [],
branch_type: [],
tag: [],
contributor: [],
language: {},
readme: {}
}
end
@ -27,4 +35,14 @@ class Repositories::DetailService < ApplicationService
def repo_suitable
Gitea::Repository::GetService.call(@owner, @repo.identifier)
end
def contributor_suitable
contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repo.identifier)
contributors.is_a?(Hash) && contributors.key?(:status) ? [] : contributors
end
def language_suitable
result = Gitea::Repository::Languages::ListService.call(@owner.login, @repo.identifier, @user&.gitea_token)
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
end
end

View File

@ -1,7 +0,0 @@
json.user_name claimer.user.try(:show_real_name)
json.user_login claimer.user.try(:login)
json.user_picture url_to_avatar(claimer.user)
json.created_at time_from_now(claimer.created_at)
json.note_body claimer.note
json.claim_id claimer.id
json.visible false

View File

@ -1,7 +0,0 @@
json.partial! "commons/success"
json.currentUserclaimed @user_claimed
json.claimers do
json.array! @claims do |claimer|
json.partial! "claims/claim_item", claimer: claimer
end
end

View File

@ -13,7 +13,6 @@ json.tracker @issue.tracker.try(:name)
json.issue_status @issue.issue_status.try(:name)
json.priority @issue.priority.try(:name)
json.version @issue.version.try(:name)
json.version_id @issue.version.try(:id)
json.issue_tags @issue.get_issue_tags
json.done_ratio @issue.done_ratio.to_s + "%"
json.issue_type @issue.issue_type

View File

@ -3,26 +3,15 @@ owner_common = $redis_cache.hgetall("v2-owner-common:#{project_common["owner_id"
json.id item[0]
json.score item[1]
json.name project_common["name"]
if project_common['identifier'].include?("/")
json.identifier project_common["identifier"].split('/')[1]
json.owner do
json.id nil
json.type 'User'
json.name project_common["identifier"].split('/')[0]
json.login project_common["identifier"].split('/')[0]
json.avatar_url User::Avatar.get_letter_avatar_url(project_common["identifier"].split('/')[0])
end
else
json.identifier project_common["identifier"]
json.owner do
json.id project_common["owner_id"]
json.type owner_common["type"]
json.name owner_common["name"]
json.login owner_common["login"]
json.avatar_url owner_common["avatar_url"]
end
end
json.identifier project_common["identifier"]
json.description project_common["description"]
json.owner do
json.id project_common["owner_id"]
json.type owner_common["type"]
json.name owner_common["name"]
json.login owner_common["login"]
json.avatar_url owner_common["avatar_url"]
end
json.visits project_common["visits"]
json.forks project_common["forks"]
json.watchers project_common["watchers"]

View File

@ -6,13 +6,6 @@ json.user_name trend.user.try(:show_real_name)
json.user_login trend.user.login
json.user_avatar url_to_avatar(trend.user)
json.action_time time_from_now(trend.created_at)
json.project do
json.owner do
json.partial! 'users/user_simple', locals: {user: trend&.project&.owner}
end
json.identifier trend&.project&.identifier
json.description trend&.project&.description
end
if trend.trend_type == "Issue"
json.partial! "issues/simple_issue_item", locals: {issue: trend.trend}

View File

@ -1,27 +1,12 @@
if commit['Status'].present?
json.author do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Author']), name: commit['Author']['Name'] }
end
json.committer do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Committer']), name: commit['Committer']['Name'] }
end
json.timestamp render_unix_time(commit['Committer']['When'])
json.time_from_now time_from_now(commit['Committer']['When'])
json.created_at render_format_time_with_date(commit['Committer']['When'])
json.message commit['CommitMessage']
json.sha commit['Sha']
else
json.author do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['commit']['author']), name: commit['commit']['author']['name'] }
end
json.author do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Author']), name: commit['Author']['Name'] }
end
json.committer do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['commit']['committer']), name: commit['commit']['committer']['name'] }
end
json.timestamp render_unix_time(commit['commit']['committer']['date'])
json.time_from_now time_from_now(commit['commit']['committer']['date'])
json.created_at render_format_time_with_date(commit['commit']['committer']['date'])
json.message commit['commit']['message']
json.sha commit['sha']
end
json.committer do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Committer']), name: commit['Committer']['Name'] }
end
json.timestamp render_unix_time(commit['Committer']['When'])
json.time_from_now time_from_now(commit['Committer']['When'])
json.created_at render_format_time_with_date(commit['Committer']['When'])
json.message commit['CommitMessage']
json.sha commit['Sha']

View File

@ -7,22 +7,11 @@ if @project.educoder?
json.timestamp 0
json.time_from_now commit[0]['time']
end
if commit[0]['author'].present?
json.author do
json.id nil
json.login commit[0]['author']['username']
json.name commit[0]['author']['username']
json.type nil
json.image_url commit[0]['author']['image_url']
end
json.committer do
json.id nil
json.login commit[0]['author']['username']
json.name commit[0]['author']['username']
json.type nil
json.image_url commit[0]['author']['image_url']
end
end
json.author do
{}
# json.partial! '/projects/author', user: render_commit_author(commit['author'])
end
json.committer {}
end
if @project.forge?

View File

@ -32,8 +32,6 @@ end
if @project.educoder?
file_path = params[:filepath].present? ? [params[:filepath], entry['name']].join('/') : entry['name']
file_type = File.extname(entry['name'].to_s)[1..-1]
image_type = image_type?(file_type)
json.name entry['name']
json.sha nil
@ -44,7 +42,7 @@ if @project.educoder?
json.target nil
json.download_url nil
json.direct_download false
json.image_type image_type
json.image_type false
json.is_readme_file false
json.commit do
json.message entry['title']

View File

@ -1,26 +1,6 @@
if @hash_commit.blank? || @project.educoder? #如果有状态值,则表示报错了
if @hash_commit.blank? #如果有状态值,则表示报错了
json.total_count 0
json.commits do
json.array! @commits do |commit|
json.sha commit['id']
json.message commit['title']
json.time_from_now commit['time']
json.author do
json.id nil
json.login commit['author']['username']
json.name commit['author']['username']
json.type nil
json.image_url commit['author']['image_url']
end
json.committer do
json.id nil
json.login commit['author']['username']
json.name commit['author']['username']
json.type nil
json.image_url commit['author']['image_url']
end
end
end
json.commits []
else
json.total_count @hash_commit[:total_count]
json.commits do

View File

@ -1,5 +1,5 @@
total_count = @contributors.size
json.list @contributors.each do |contributor|
json.contributors @contributors.each do |contributor|
json.partial! 'contributor', locals: { contributor: contributor }
end
json.total_count total_count

View File

@ -44,7 +44,7 @@ end
if @result[:repo]
json.size replace_bytes_to_b(number_to_human_size(@result[:repo]['size'].to_i*1024))
json.ssh_url @result[:repo]['ssh_url']
json.clone_url @project.educoder? ? "#{Rails.application.config_for(:configuration)['educoder']['git_site']}/#{@project&.project_educoder&.repo_name}.git" : @result[:repo]['clone_url']
json.clone_url @result[:repo]['clone_url']
json.default_branch @project.educoder? ? "master" : @result[:repo]['default_branch']
json.empty @result[:repo]['empty']
json.full_name @result[:repo]['full_name']
@ -53,13 +53,13 @@ end
json.license_name @project.license_name
json.branches_count @result[:branch_tag_total_count].present? ? (@result[:branch_tag_total_count]['branch_count'] || 0) : 0
json.tags_count @result[:branch_tag_total_count].present? ? (@result[:branch_tag_total_count]['tag_count'] || 0) : 0
# json.contributors do
# total_count = @result[:contributor].size
# json.list @result[:contributor].each do |contributor|
# json.partial! 'contributor', locals: { contributor: contributor }
# end
# json.total_count total_count
# end
# json.languages @result[:language].blank? ? nil : @result[:language]
json.contributors do
total_count = @result[:contributor].size
json.list @result[:contributor].each do |contributor|
json.partial! 'contributor', locals: { contributor: contributor }
end
json.total_count total_count
end
json.languages @result[:language].blank? ? nil : @result[:language]
json.partial! 'author', locals: { user: @project.owner }

View File

@ -7,7 +7,7 @@ if @project.educoder?
end
end
json.commits_count @entries['commit_count']
json.zip_url ''
json.zip_url @entries['git_url']
json.tar_url ''
json.entries do
json.array! @entries['trees'] do |entry|

View File

@ -24,12 +24,8 @@ if @project.educoder?
end
end
json.entries do
if @sub_entries['trees'].is_a?(Array)
json.array! @sub_entries['trees'] do |entry|
json.partial! 'repositories/simple_entry', locals: { entry: entry }
end
elsif @sub_entries['trees'].is_a?(Hash)
json.partial! 'repositories/simple_entry', locals: { entry: @sub_entries['trees'] }
json.array! @sub_entries['trees'] do |entry|
json.partial! 'repositories/simple_entry', locals: { entry: entry }
end
end
end

View File

@ -15,7 +15,7 @@ zh-CN:
'refused': '已拒绝'
'agreed': '已同意'
trend:
Issue: 修(Issue)
Issue: 修(Issue)
PullRequest: 合并请求(PR)
VersionRelease: 版本发布
create: 创建了

View File

@ -9,7 +9,6 @@ Rails.application.routes.draw do
# Serve websocket cable requests in-process
mount ActionCable.server => '/cable'
get 'attachments/entries/get_file', to: 'attachments#get_file'
get 'attachments/download/:id', to: 'attachments#show'
get 'attachments/download/:id/:filename', to: 'attachments#show'
@ -147,16 +146,6 @@ Rails.application.routes.draw do
get :get_children_journals
end
end
resources :claims, only: [:index] do
collection do
post :create
delete :destroy
get :index
put :update
end
end
resources :issue_times, only: [:create] do
collection do
post :end_work

View File

@ -1,11 +0,0 @@
class CreateClaims < ActiveRecord::Migration[5.2]
def change
create_table :claims do |t|
t.integer :issue_id
t.integer :user_id
t.timestamps
t.index :issue_id
t.index :user_id
end
end
end

View File

@ -1,5 +0,0 @@
class AddNoteToClaim < ActiveRecord::Migration[5.2]
def change
add_column :claims, :note, :text
end
end

View File

@ -1,5 +0,0 @@
class AddTeamUserToMembers < ActiveRecord::Migration[5.2]
def change
add_reference :members, :team_user
end
end

2
dir.md
View File

@ -87,7 +87,7 @@ forgeplus
│   │   │   │   └── tags(标签)
│   │   │   ├── user(用户)
│   │   │   └── versions(发行版)
│   │   ├── issues(修)
│   │   ├── issues(修)
│   │   ├── libraries
│   │   ├── oauth
│   │   ├── organizations(组织)

BIN
docs/figs/PR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

BIN
docs/figs/engine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/figs/gitlink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

BIN
docs/figs/issues.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

BIN
docs/figs/project_list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

BIN
docs/figs/repo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -1138,31 +1138,31 @@ Success — a happy kitten is an authenticated kitten!
</thead><tbody>
<tr>
<td>IssueAssigned</td>
<td>有新指派给我的</td>
<td>有新指派给我的</td>
</tr>
<tr>
<td>IssueAssignerExpire</td>
<td>我负责的修截止日期到达最后一天</td>
<td>我负责的修截止日期到达最后一天</td>
</tr>
<tr>
<td>IssueAtme</td>
<td>修中@我</td>
<td>修中@我</td>
</tr>
<tr>
<td>IssueChanged</td>
<td>我创建或负责的修状态变更</td>
<td>我创建或负责的修状态变更</td>
</tr>
<tr>
<td>IssueCreatorExpire</td>
<td>我创建的修截止日期到达最后一天</td>
<td>我创建的修截止日期到达最后一天</td>
</tr>
<tr>
<td>IssueDeleted</td>
<td>我创建或负责的修删除</td>
<td>我创建或负责的修删除</td>
</tr>
<tr>
<td>IssueJournal</td>
<td>我创建或负责的修有新的评论</td>
<td>我创建或负责的修有新的评论</td>
</tr>
<tr>
<td>LoginIpTip</td>
@ -1194,7 +1194,7 @@ Success — a happy kitten is an authenticated kitten!
</tr>
<tr>
<td>ProjectIssue</td>
<td>我管理/关注的仓库有新的</td>
<td>我管理/关注的仓库有新的</td>
</tr>
<tr>
<td>ProjectJoined</td>
@ -1403,7 +1403,7 @@ Success — a happy kitten is an authenticated kitten!
<tr>
<td>atmeable_type</td>
<td>string</td>
<td>atme消息对象是从哪里@我的比如评论Journal、Issue、合并请求PullRequest</td>
<td>atme消息对象是从哪里@我的比如评论Journal、Issue、合并请求PullRequest</td>
</tr>
<tr>
<td>atmeable_id</td>
@ -1706,7 +1706,7 @@ Success — a happy kitten is an authenticated kitten!
</span><span class="nl">"total_settings_count"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
</span><span class="nl">"settings"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"修被指派"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"修被指派"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IssueAssigned"</span><span class="p">,</span><span class="w">
</span><span class="nl">"notification_disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"email_disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
@ -1725,7 +1725,7 @@ Success — a happy kitten is an authenticated kitten!
</span><span class="nl">"total_settings_count"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
</span><span class="nl">"settings"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"有新的修"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"有新的修"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Issue"</span><span class="p">,</span><span class="w">
</span><span class="nl">"notification_disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"email_disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
@ -2245,7 +2245,7 @@ Success — a happy kitten is an authenticated kitten!
<tr>
<td>issues_count</td>
<td>array</td>
<td>修数量</td>
<td>修数量</td>
</tr>
<tr>
<td>pull_requests_count</td>
@ -2493,7 +2493,7 @@ Success — a happy kitten is an authenticated kitten!
<tr>
<td>project_trends.trend_type</td>
<td>string</td>
<td>动态类型IssueVersionRelease版本发布PullRequest合并请求</td>
<td>动态类型IssueVersionRelease版本发布PullRequest合并请求</td>
</tr>
<tr>
<td>project_trends.action_type</td>
@ -4968,7 +4968,7 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
<tr>
<td>menu_name</td>
<td>string</td>
<td>导航名称, home:主页,code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置</td>
<td>导航名称, home:主页,code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置</td>
</tr>
</tbody></table>
@ -5131,7 +5131,7 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json
<td></td>
<td></td>
<td>array</td>
<td>项目模块内容, 支持以下参数:code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑</td>
<td>项目模块内容, 支持以下参数:code:代码库,issues:修,pulls:合并请求,devops:工作流,versions:里程碑</td>
</tr>
</tbody></table>
<h3 id='7447e4874e-2'>返回字段说明:</h3>
@ -8346,23 +8346,23 @@ http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json
</tr>
<tr>
<td>issue</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
</tr>
<tr>
<td>issue_assign</td>
<td>修被指派</td>
<td>修被指派</td>
</tr>
<tr>
<td>issue_label</td>
<td>修标签被更新或删除</td>
<td>修标签被更新或删除</td>
</tr>
<tr>
<td>issue_milestone</td>
<td>修被收入里程碑</td>
<td>修被收入里程碑</td>
</tr>
<tr>
<td>issue_comment</td>
<td>修评论</td>
<td>修评论</td>
</tr>
<tr>
<td>pull_request</td>
@ -8568,23 +8568,23 @@ http://localhost:3000/api/yystopf/ceshi/webhooks.json
</tr>
<tr>
<td>issue</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
</tr>
<tr>
<td>issue_assign</td>
<td>修被指派</td>
<td>修被指派</td>
</tr>
<tr>
<td>issue_label</td>
<td>修标签被更新或删除</td>
<td>修标签被更新或删除</td>
</tr>
<tr>
<td>issue_milestone</td>
<td>修被收入里程碑</td>
<td>修被收入里程碑</td>
</tr>
<tr>
<td>issue_comment</td>
<td>修评论</td>
<td>修评论</td>
</tr>
<tr>
<td>pull_request</td>
@ -8833,23 +8833,23 @@ http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
</tr>
<tr>
<td>issue</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
<td>修已打开、已关闭、已重新打开或编辑</td>
</tr>
<tr>
<td>issue_assign</td>
<td>修被指派</td>
<td>修被指派</td>
</tr>
<tr>
<td>issue_label</td>
<td>修标签被更新或删除</td>
<td>修标签被更新或删除</td>
</tr>
<tr>
<td>issue_milestone</td>
<td>修被收入里程碑</td>
<td>修被收入里程碑</td>
</tr>
<tr>
<td>issue_comment</td>
<td>修评论</td>
<td>修评论</td>
</tr>
<tr>
<td>pull_request</td>

View File

@ -1,6 +1,6 @@
<html>
<head>
<title>有新的修指派给我</title>
<title>有新的修指派给我</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
@ -31,7 +31,7 @@
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>在 {nickname2}/{repository} 指派给你一个修:<a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a><br/>
<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>在 {nickname2}/{repository} 指派给你一个修:<a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a><br/>
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>

View File

@ -1,6 +1,6 @@
<html>
<head>
<title>有新的修指派给我</title>
<title>有新的修指派给我</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
@ -31,7 +31,7 @@
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
在项目 <a href="{baseurl}/{login2}/{identifier}" style="font-weight:bold;color:#3b94d6;">{nickname2}/{repository}</a><a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a> 中:
在项目 <a href="{baseurl}/{login2}/{identifier}" style="font-weight:bold;color:#3b94d6;">{nickname2}/{repository}</a><a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a> 中:
{ifassigner}<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>将负责人从 {assigner1} 修改为 {assigner2}{endassigner}
{ifstatus}<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>将状态从 {status1} 修改为 {status2}{endstatus}
{iftracker}<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>将类型从 {tracker1} 修改为 {tracker2}{endtracker}

View File

@ -1,6 +1,6 @@
<html>
<head>
<title>修状态改变</title>
<title>修状态改变</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
@ -31,7 +31,7 @@
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
<a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{nickname}</a>已将修 {title} 删除
<a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{nickname}</a>已将修 {title} 删除
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>

View File

@ -1,6 +1,6 @@
<html>
<head>
<title>管理的仓库有新的</title>
<title>管理的仓库有新的</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
@ -31,7 +31,7 @@
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>在 {nickname2}/{repository} 新建了一个修:<a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a><br/>
<a href="{baseurl}/{login1}" style="font-weight:bold;color:#3b94d6;">{nickname1}</a>在 {nickname2}/{repository} 新建了一个修:<a href="{baseurl}/{login2}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a><br/>
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>

View File

@ -1,47 +0,0 @@
<html>
<head>
<title>被拉入组织团队</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto;">
<div style="height:50px; width: 578px; background:#3b94d6; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="{baseurl}"><img src="{baseurl}/images/email_logo.png" height="45" ></a>
<p style="color:#fff; float:right; margin-top:15px;">确实开源,协同创新</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
你已被拉入组织 <a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{organization}</a><a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{team}</a> 团队,拥有{role}权限
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background: #eee;border:1px solid #ddd; border-top:none; width: 558px;">
<p style="color:#888; float:left;">如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见<br/>
QQ群1071514693</p>
<p style="color:#888; float:right;font-weight: bold;font-size: 16px;">GitLink团队</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,47 +0,0 @@
<html>
<head>
<title>被移出组织团队</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto;">
<div style="height:50px; width: 578px; background:#3b94d6; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="{baseurl}"><img src="{baseurl}/images/email_logo.png" height="45" ></a>
<p style="color:#fff; float:right; margin-top:15px;">确实开源,协同创新</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
你已被移出组织 <a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{organization}</a><a href="{baseurl}/{login}" style="font-weight:bold;color:#3b94d6;">{team}</a> 团队
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background: #eee;border:1px solid #ddd; border-top:none; width: 558px;">
<p style="color:#888; float:left;">如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见<br/>
QQ群1071514693</p>
<p style="color:#888; float:right;font-weight: bold;font-size: 16px;">GitLink团队</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
</div>
</div>
</body>
</html>

View File

@ -4,304 +4,382 @@
"static/css/1.0ba7a726.chunk.css": "/react/build/static/css/1.0ba7a726.chunk.css",
"./static/js/1.9de07cbc.chunk.js": "/react/build/./static/js/1.9de07cbc.chunk.js",
"./static/js/2.d659edf3.chunk.js": "/react/build/./static/js/2.d659edf3.chunk.js",
"static/css/3.2254a4a8.chunk.css": "/react/build/static/css/3.2254a4a8.chunk.css",
"./static/js/3.c021d738.chunk.js": "/react/build/./static/js/3.c021d738.chunk.js",
"./static/js/4.5d0131e6.chunk.js": "/react/build/./static/js/4.5d0131e6.chunk.js",
"static/css/5.d01698e8.chunk.css": "/react/build/static/css/5.d01698e8.chunk.css",
"./static/js/5.ba9c3134.chunk.js": "/react/build/./static/js/5.ba9c3134.chunk.js",
"static/css/6.bbfdfc43.chunk.css": "/react/build/static/css/6.bbfdfc43.chunk.css",
"./static/js/6.69ca2fc8.chunk.js": "/react/build/./static/js/6.69ca2fc8.chunk.js",
"static/css/7.e821a490.chunk.css": "/react/build/static/css/7.e821a490.chunk.css",
"./static/js/7.a1394f8d.chunk.js": "/react/build/./static/js/7.a1394f8d.chunk.js",
"static/css/8.6e0686d9.chunk.css": "/react/build/static/css/8.6e0686d9.chunk.css",
"./static/js/8.7ad76529.chunk.js": "/react/build/./static/js/8.7ad76529.chunk.js",
"static/css/9.d4345223.chunk.css": "/react/build/static/css/9.d4345223.chunk.css",
"./static/js/9.74545efc.chunk.js": "/react/build/./static/js/9.74545efc.chunk.js",
"static/css/10.1868f004.chunk.css": "/react/build/static/css/10.1868f004.chunk.css",
"./static/js/10.b3f0a06d.chunk.js": "/react/build/./static/js/10.b3f0a06d.chunk.js",
"static/css/11.1c5f3a58.chunk.css": "/react/build/static/css/11.1c5f3a58.chunk.css",
"./static/js/11.5c1d2c2d.chunk.js": "/react/build/./static/js/11.5c1d2c2d.chunk.js",
"static/css/12.ae349a22.chunk.css": "/react/build/static/css/12.ae349a22.chunk.css",
"./static/js/12.732d3701.chunk.js": "/react/build/./static/js/12.732d3701.chunk.js",
"static/css/3.d01698e8.chunk.css": "/react/build/static/css/3.d01698e8.chunk.css",
"./static/js/3.1f347c4c.chunk.js": "/react/build/./static/js/3.1f347c4c.chunk.js",
"static/css/4.2254a4a8.chunk.css": "/react/build/static/css/4.2254a4a8.chunk.css",
"./static/js/4.4d2d662b.chunk.js": "/react/build/./static/js/4.4d2d662b.chunk.js",
"./static/js/5.6f9f87c6.chunk.js": "/react/build/./static/js/5.6f9f87c6.chunk.js",
"static/css/6.8bc7b323.chunk.css": "/react/build/static/css/6.8bc7b323.chunk.css",
"./static/js/6.c04051a2.chunk.js": "/react/build/./static/js/6.c04051a2.chunk.js",
"static/css/7.bbfdfc43.chunk.css": "/react/build/static/css/7.bbfdfc43.chunk.css",
"./static/js/7.8462b447.chunk.js": "/react/build/./static/js/7.8462b447.chunk.js",
"static/css/8.1632b9c8.chunk.css": "/react/build/static/css/8.1632b9c8.chunk.css",
"./static/js/8.882648e1.chunk.js": "/react/build/./static/js/8.882648e1.chunk.js",
"static/css/9.6e0686d9.chunk.css": "/react/build/static/css/9.6e0686d9.chunk.css",
"./static/js/9.fd42b255.chunk.js": "/react/build/./static/js/9.fd42b255.chunk.js",
"static/css/10.d4345223.chunk.css": "/react/build/static/css/10.d4345223.chunk.css",
"./static/js/10.08552af4.chunk.js": "/react/build/./static/js/10.08552af4.chunk.js",
"static/css/11.ae349a22.chunk.css": "/react/build/static/css/11.ae349a22.chunk.css",
"./static/js/11.69f940df.chunk.js": "/react/build/./static/js/11.69f940df.chunk.js",
"static/css/12.1c5f3a58.chunk.css": "/react/build/static/css/12.1c5f3a58.chunk.css",
"./static/js/12.72a62b66.chunk.js": "/react/build/./static/js/12.72a62b66.chunk.js",
"static/css/13.30f998e5.chunk.css": "/react/build/static/css/13.30f998e5.chunk.css",
"./static/js/13.87577dfb.chunk.js": "/react/build/./static/js/13.87577dfb.chunk.js",
"./static/js/13.7de262c1.chunk.js": "/react/build/./static/js/13.7de262c1.chunk.js",
"static/css/14.1e970b46.chunk.css": "/react/build/static/css/14.1e970b46.chunk.css",
"./static/js/14.47d6b04d.chunk.js": "/react/build/./static/js/14.47d6b04d.chunk.js",
"static/css/15.cf56d612.chunk.css": "/react/build/static/css/15.cf56d612.chunk.css",
"./static/js/15.5eff19c4.chunk.js": "/react/build/./static/js/15.5eff19c4.chunk.js",
"static/css/16.d0c774b5.chunk.css": "/react/build/static/css/16.d0c774b5.chunk.css",
"./static/js/16.f5587995.chunk.js": "/react/build/./static/js/16.f5587995.chunk.js",
"static/css/17.7bd7b9f3.chunk.css": "/react/build/static/css/17.7bd7b9f3.chunk.css",
"./static/js/17.deaa743d.chunk.js": "/react/build/./static/js/17.deaa743d.chunk.js",
"static/css/18.012aec0d.chunk.css": "/react/build/static/css/18.012aec0d.chunk.css",
"./static/js/18.e32fb44a.chunk.js": "/react/build/./static/js/18.e32fb44a.chunk.js",
"static/css/19.e5544bad.chunk.css": "/react/build/static/css/19.e5544bad.chunk.css",
"./static/js/19.4fd41f28.chunk.js": "/react/build/./static/js/19.4fd41f28.chunk.js",
"static/css/20.330fa4e3.chunk.css": "/react/build/static/css/20.330fa4e3.chunk.css",
"./static/js/20.ecc2a430.chunk.js": "/react/build/./static/js/20.ecc2a430.chunk.js",
"static/css/21.db9266b0.chunk.css": "/react/build/static/css/21.db9266b0.chunk.css",
"./static/js/21.bb7cd174.chunk.js": "/react/build/./static/js/21.bb7cd174.chunk.js",
"static/css/22.0b7937b6.chunk.css": "/react/build/static/css/22.0b7937b6.chunk.css",
"./static/js/22.b6cf24cd.chunk.js": "/react/build/./static/js/22.b6cf24cd.chunk.js",
"static/css/23.92df39ea.chunk.css": "/react/build/static/css/23.92df39ea.chunk.css",
"./static/js/23.68eb83f5.chunk.js": "/react/build/./static/js/23.68eb83f5.chunk.js",
"./static/js/24.df9a463e.chunk.js": "/react/build/./static/js/24.df9a463e.chunk.js",
"./static/js/25.a529f43e.chunk.js": "/react/build/./static/js/25.a529f43e.chunk.js",
"static/css/26.75aaa133.chunk.css": "/react/build/static/css/26.75aaa133.chunk.css",
"./static/js/26.fa022337.chunk.js": "/react/build/./static/js/26.fa022337.chunk.js",
"static/css/27.9891cdaa.chunk.css": "/react/build/static/css/27.9891cdaa.chunk.css",
"./static/js/27.fc2d3a1f.chunk.js": "/react/build/./static/js/27.fc2d3a1f.chunk.js",
"./static/js/28.ed6116f2.chunk.js": "/react/build/./static/js/28.ed6116f2.chunk.js",
"static/css/29.93537df9.chunk.css": "/react/build/static/css/29.93537df9.chunk.css",
"./static/js/29.d6441045.chunk.js": "/react/build/./static/js/29.d6441045.chunk.js",
"static/css/30.33342a61.chunk.css": "/react/build/static/css/30.33342a61.chunk.css",
"./static/js/30.883ca83b.chunk.js": "/react/build/./static/js/30.883ca83b.chunk.js",
"static/css/31.4ffe335c.chunk.css": "/react/build/static/css/31.4ffe335c.chunk.css",
"./static/js/31.750c280e.chunk.js": "/react/build/./static/js/31.750c280e.chunk.js",
"static/css/32.ed9fcfe7.chunk.css": "/react/build/static/css/32.ed9fcfe7.chunk.css",
"./static/js/32.1e7fc633.chunk.js": "/react/build/./static/js/32.1e7fc633.chunk.js",
"static/css/33.1868f004.chunk.css": "/react/build/static/css/33.1868f004.chunk.css",
"./static/js/33.ea85fea8.chunk.js": "/react/build/./static/js/33.ea85fea8.chunk.js",
"static/css/34.b0c83d65.chunk.css": "/react/build/static/css/34.b0c83d65.chunk.css",
"./static/js/34.cf9cb12d.chunk.js": "/react/build/./static/js/34.cf9cb12d.chunk.js",
"./static/js/35.671a8fbb.chunk.js": "/react/build/./static/js/35.671a8fbb.chunk.js",
"static/css/36.88cc3b5e.chunk.css": "/react/build/static/css/36.88cc3b5e.chunk.css",
"./static/js/36.55c48284.chunk.js": "/react/build/./static/js/36.55c48284.chunk.js",
"static/css/37.88cc3b5e.chunk.css": "/react/build/static/css/37.88cc3b5e.chunk.css",
"./static/js/37.297dfdc5.chunk.js": "/react/build/./static/js/37.297dfdc5.chunk.js",
"static/css/38.88cc3b5e.chunk.css": "/react/build/static/css/38.88cc3b5e.chunk.css",
"./static/js/38.23688a87.chunk.js": "/react/build/./static/js/38.23688a87.chunk.js",
"static/css/39.5c81fe74.chunk.css": "/react/build/static/css/39.5c81fe74.chunk.css",
"./static/js/39.7fd250d3.chunk.js": "/react/build/./static/js/39.7fd250d3.chunk.js",
"./static/js/40.446027b0.chunk.js": "/react/build/./static/js/40.446027b0.chunk.js",
"static/css/41.080d6958.chunk.css": "/react/build/static/css/41.080d6958.chunk.css",
"./static/js/41.107c3622.chunk.js": "/react/build/./static/js/41.107c3622.chunk.js",
"static/css/42.b299cb62.chunk.css": "/react/build/static/css/42.b299cb62.chunk.css",
"./static/js/42.0340c68c.chunk.js": "/react/build/./static/js/42.0340c68c.chunk.js",
"./static/js/43.30765c77.chunk.js": "/react/build/./static/js/43.30765c77.chunk.js",
"./static/js/44.6d29f257.chunk.js": "/react/build/./static/js/44.6d29f257.chunk.js",
"static/css/45.4f215d24.chunk.css": "/react/build/static/css/45.4f215d24.chunk.css",
"./static/js/45.dfb39cec.chunk.js": "/react/build/./static/js/45.dfb39cec.chunk.js",
"static/css/46.05cdcfdb.chunk.css": "/react/build/static/css/46.05cdcfdb.chunk.css",
"./static/js/46.642919a0.chunk.js": "/react/build/./static/js/46.642919a0.chunk.js",
"static/css/47.e8001192.chunk.css": "/react/build/static/css/47.e8001192.chunk.css",
"./static/js/47.f10f966d.chunk.js": "/react/build/./static/js/47.f10f966d.chunk.js",
"static/css/48.0379bdda.chunk.css": "/react/build/static/css/48.0379bdda.chunk.css",
"./static/js/48.9755c57d.chunk.js": "/react/build/./static/js/48.9755c57d.chunk.js",
"static/css/49.535eede4.chunk.css": "/react/build/static/css/49.535eede4.chunk.css",
"./static/js/49.84b70947.chunk.js": "/react/build/./static/js/49.84b70947.chunk.js",
"static/css/50.32ee9943.chunk.css": "/react/build/static/css/50.32ee9943.chunk.css",
"./static/js/50.e0e6fc22.chunk.js": "/react/build/./static/js/50.e0e6fc22.chunk.js",
"static/css/51.67a9b0d6.chunk.css": "/react/build/static/css/51.67a9b0d6.chunk.css",
"./static/js/51.74dc3aee.chunk.js": "/react/build/./static/js/51.74dc3aee.chunk.js",
"static/css/52.75d3df4f.chunk.css": "/react/build/static/css/52.75d3df4f.chunk.css",
"./static/js/52.2db0cda9.chunk.js": "/react/build/./static/js/52.2db0cda9.chunk.js",
"static/css/53.f7d2a825.chunk.css": "/react/build/static/css/53.f7d2a825.chunk.css",
"./static/js/53.6c48cfaf.chunk.js": "/react/build/./static/js/53.6c48cfaf.chunk.js",
"static/css/54.1d3b7a8d.chunk.css": "/react/build/static/css/54.1d3b7a8d.chunk.css",
"./static/js/54.ee1deb94.chunk.js": "/react/build/./static/js/54.ee1deb94.chunk.js",
"static/css/55.55132a20.chunk.css": "/react/build/static/css/55.55132a20.chunk.css",
"./static/js/55.2d70fec6.chunk.js": "/react/build/./static/js/55.2d70fec6.chunk.js",
"static/css/56.1ff4022b.chunk.css": "/react/build/static/css/56.1ff4022b.chunk.css",
"./static/js/56.1d16b6e6.chunk.js": "/react/build/./static/js/56.1d16b6e6.chunk.js",
"static/css/57.f8123c09.chunk.css": "/react/build/static/css/57.f8123c09.chunk.css",
"./static/js/57.d364dbd1.chunk.js": "/react/build/./static/js/57.d364dbd1.chunk.js",
"static/css/58.90f11182.chunk.css": "/react/build/static/css/58.90f11182.chunk.css",
"./static/js/58.32f00509.chunk.js": "/react/build/./static/js/58.32f00509.chunk.js",
"./static/js/59.3ead551c.chunk.js": "/react/build/./static/js/59.3ead551c.chunk.js",
"static/css/60.520bfea6.chunk.css": "/react/build/static/css/60.520bfea6.chunk.css",
"./static/js/60.096696d0.chunk.js": "/react/build/./static/js/60.096696d0.chunk.js",
"static/css/61.a5678b8f.chunk.css": "/react/build/static/css/61.a5678b8f.chunk.css",
"./static/js/61.106f2931.chunk.js": "/react/build/./static/js/61.106f2931.chunk.js",
"static/css/62.9d206204.chunk.css": "/react/build/static/css/62.9d206204.chunk.css",
"./static/js/62.0c2fc9f5.chunk.js": "/react/build/./static/js/62.0c2fc9f5.chunk.js",
"./static/js/63.27779735.chunk.js": "/react/build/./static/js/63.27779735.chunk.js",
"static/css/64.ea97577b.chunk.css": "/react/build/static/css/64.ea97577b.chunk.css",
"./static/js/64.168b2757.chunk.js": "/react/build/./static/js/64.168b2757.chunk.js",
"static/css/65.2cfa3592.chunk.css": "/react/build/static/css/65.2cfa3592.chunk.css",
"./static/js/65.bb731ca7.chunk.js": "/react/build/./static/js/65.bb731ca7.chunk.js",
"static/css/66.b2109eb4.chunk.css": "/react/build/static/css/66.b2109eb4.chunk.css",
"./static/js/66.02a9e4c3.chunk.js": "/react/build/./static/js/66.02a9e4c3.chunk.js",
"static/css/67.b26a06ba.chunk.css": "/react/build/static/css/67.b26a06ba.chunk.css",
"./static/js/67.c06e0c2a.chunk.js": "/react/build/./static/js/67.c06e0c2a.chunk.js",
"static/css/68.61b37499.chunk.css": "/react/build/static/css/68.61b37499.chunk.css",
"./static/js/68.d1c952c6.chunk.js": "/react/build/./static/js/68.d1c952c6.chunk.js",
"static/css/69.61b37499.chunk.css": "/react/build/static/css/69.61b37499.chunk.css",
"./static/js/69.ad0246bd.chunk.js": "/react/build/./static/js/69.ad0246bd.chunk.js",
"static/css/70.802376aa.chunk.css": "/react/build/static/css/70.802376aa.chunk.css",
"./static/js/70.0cefe909.chunk.js": "/react/build/./static/js/70.0cefe909.chunk.js",
"static/css/71.1926e8da.chunk.css": "/react/build/static/css/71.1926e8da.chunk.css",
"./static/js/71.8d37ad43.chunk.js": "/react/build/./static/js/71.8d37ad43.chunk.js",
"static/css/72.72690062.chunk.css": "/react/build/static/css/72.72690062.chunk.css",
"./static/js/72.8066a00e.chunk.js": "/react/build/./static/js/72.8066a00e.chunk.js",
"static/css/73.4054f41b.chunk.css": "/react/build/static/css/73.4054f41b.chunk.css",
"./static/js/73.16a53e3b.chunk.js": "/react/build/./static/js/73.16a53e3b.chunk.js",
"static/css/74.d16cbade.chunk.css": "/react/build/static/css/74.d16cbade.chunk.css",
"./static/js/74.d409058a.chunk.js": "/react/build/./static/js/74.d409058a.chunk.js",
"static/css/75.131374a7.chunk.css": "/react/build/static/css/75.131374a7.chunk.css",
"./static/js/75.fd253f94.chunk.js": "/react/build/./static/js/75.fd253f94.chunk.js",
"static/css/76.c2f5b906.chunk.css": "/react/build/static/css/76.c2f5b906.chunk.css",
"./static/js/76.691766f4.chunk.js": "/react/build/./static/js/76.691766f4.chunk.js",
"static/css/77.fd3fa2e9.chunk.css": "/react/build/static/css/77.fd3fa2e9.chunk.css",
"./static/js/77.b84fec71.chunk.js": "/react/build/./static/js/77.b84fec71.chunk.js",
"static/css/78.f4de1d43.chunk.css": "/react/build/static/css/78.f4de1d43.chunk.css",
"./static/js/78.a8bd2e81.chunk.js": "/react/build/./static/js/78.a8bd2e81.chunk.js",
"./static/js/79.8dcee5cb.chunk.js": "/react/build/./static/js/79.8dcee5cb.chunk.js",
"static/css/80.45444cfc.chunk.css": "/react/build/static/css/80.45444cfc.chunk.css",
"./static/js/80.05713831.chunk.js": "/react/build/./static/js/80.05713831.chunk.js",
"static/css/16.74ea968f.chunk.css": "/react/build/static/css/16.74ea968f.chunk.css",
"./static/js/16.29ac39ca.chunk.js": "/react/build/./static/js/16.29ac39ca.chunk.js",
"static/css/17.d0c774b5.chunk.css": "/react/build/static/css/17.d0c774b5.chunk.css",
"./static/js/17.de7604c0.chunk.js": "/react/build/./static/js/17.de7604c0.chunk.js",
"static/css/18.7bd7b9f3.chunk.css": "/react/build/static/css/18.7bd7b9f3.chunk.css",
"./static/js/18.99b2f967.chunk.js": "/react/build/./static/js/18.99b2f967.chunk.js",
"static/css/19.012aec0d.chunk.css": "/react/build/static/css/19.012aec0d.chunk.css",
"./static/js/19.c80c661b.chunk.js": "/react/build/./static/js/19.c80c661b.chunk.js",
"static/css/20.e5544bad.chunk.css": "/react/build/static/css/20.e5544bad.chunk.css",
"./static/js/20.bfbd5ffe.chunk.js": "/react/build/./static/js/20.bfbd5ffe.chunk.js",
"./static/js/21.6da4d475.chunk.js": "/react/build/./static/js/21.6da4d475.chunk.js",
"static/css/22.330fa4e3.chunk.css": "/react/build/static/css/22.330fa4e3.chunk.css",
"./static/js/22.709de7d8.chunk.js": "/react/build/./static/js/22.709de7d8.chunk.js",
"static/css/23.db9266b0.chunk.css": "/react/build/static/css/23.db9266b0.chunk.css",
"./static/js/23.54c1c605.chunk.js": "/react/build/./static/js/23.54c1c605.chunk.js",
"static/css/24.0b7937b6.chunk.css": "/react/build/static/css/24.0b7937b6.chunk.css",
"./static/js/24.567dac3f.chunk.js": "/react/build/./static/js/24.567dac3f.chunk.js",
"./static/js/25.edd1a409.chunk.js": "/react/build/./static/js/25.edd1a409.chunk.js",
"static/css/26.92df39ea.chunk.css": "/react/build/static/css/26.92df39ea.chunk.css",
"./static/js/26.4ca0a6c7.chunk.js": "/react/build/./static/js/26.4ca0a6c7.chunk.js",
"./static/js/27.a37917ce.chunk.js": "/react/build/./static/js/27.a37917ce.chunk.js",
"static/css/28.75aaa133.chunk.css": "/react/build/static/css/28.75aaa133.chunk.css",
"./static/js/28.25a3467c.chunk.js": "/react/build/./static/js/28.25a3467c.chunk.js",
"static/css/29.646401a4.chunk.css": "/react/build/static/css/29.646401a4.chunk.css",
"./static/js/29.9433bca2.chunk.js": "/react/build/./static/js/29.9433bca2.chunk.js",
"./static/js/30.71048987.chunk.js": "/react/build/./static/js/30.71048987.chunk.js",
"static/css/31.93537df9.chunk.css": "/react/build/static/css/31.93537df9.chunk.css",
"./static/js/31.3aa5d702.chunk.js": "/react/build/./static/js/31.3aa5d702.chunk.js",
"static/css/32.33342a61.chunk.css": "/react/build/static/css/32.33342a61.chunk.css",
"./static/js/32.aa9f51bb.chunk.js": "/react/build/./static/js/32.aa9f51bb.chunk.js",
"static/css/33.3201edcb.chunk.css": "/react/build/static/css/33.3201edcb.chunk.css",
"./static/js/33.be67ceb0.chunk.js": "/react/build/./static/js/33.be67ceb0.chunk.js",
"static/css/34.4dcfd44a.chunk.css": "/react/build/static/css/34.4dcfd44a.chunk.css",
"./static/js/34.b06d630a.chunk.js": "/react/build/./static/js/34.b06d630a.chunk.js",
"static/css/35.a673f3dd.chunk.css": "/react/build/static/css/35.a673f3dd.chunk.css",
"./static/js/35.d6dd0530.chunk.js": "/react/build/./static/js/35.d6dd0530.chunk.js",
"static/css/36.c831b4d8.chunk.css": "/react/build/static/css/36.c831b4d8.chunk.css",
"./static/js/36.6afb23fc.chunk.js": "/react/build/./static/js/36.6afb23fc.chunk.js",
"static/css/37.010bbe87.chunk.css": "/react/build/static/css/37.010bbe87.chunk.css",
"./static/js/37.22d2c30b.chunk.js": "/react/build/./static/js/37.22d2c30b.chunk.js",
"static/css/38.69edc38b.chunk.css": "/react/build/static/css/38.69edc38b.chunk.css",
"./static/js/38.c9830d31.chunk.js": "/react/build/./static/js/38.c9830d31.chunk.js",
"static/css/39.69edc38b.chunk.css": "/react/build/static/css/39.69edc38b.chunk.css",
"./static/js/39.2b68156d.chunk.js": "/react/build/./static/js/39.2b68156d.chunk.js",
"static/css/40.543b24f4.chunk.css": "/react/build/static/css/40.543b24f4.chunk.css",
"./static/js/40.7df4fd1f.chunk.js": "/react/build/./static/js/40.7df4fd1f.chunk.js",
"static/css/41.69edc38b.chunk.css": "/react/build/static/css/41.69edc38b.chunk.css",
"./static/js/41.f8ec75a6.chunk.js": "/react/build/./static/js/41.f8ec75a6.chunk.js",
"static/css/42.69edc38b.chunk.css": "/react/build/static/css/42.69edc38b.chunk.css",
"./static/js/42.72b65f6f.chunk.js": "/react/build/./static/js/42.72b65f6f.chunk.js",
"static/css/43.69edc38b.chunk.css": "/react/build/static/css/43.69edc38b.chunk.css",
"./static/js/43.a85f629f.chunk.js": "/react/build/./static/js/43.a85f629f.chunk.js",
"static/css/44.0fb95ac8.chunk.css": "/react/build/static/css/44.0fb95ac8.chunk.css",
"./static/js/44.9b637cdd.chunk.js": "/react/build/./static/js/44.9b637cdd.chunk.js",
"./static/js/45.c7182e05.chunk.js": "/react/build/./static/js/45.c7182e05.chunk.js",
"static/css/46.88cc3b5e.chunk.css": "/react/build/static/css/46.88cc3b5e.chunk.css",
"./static/js/46.cd44eee7.chunk.js": "/react/build/./static/js/46.cd44eee7.chunk.js",
"static/css/47.88cc3b5e.chunk.css": "/react/build/static/css/47.88cc3b5e.chunk.css",
"./static/js/47.45010480.chunk.js": "/react/build/./static/js/47.45010480.chunk.js",
"static/css/48.88cc3b5e.chunk.css": "/react/build/static/css/48.88cc3b5e.chunk.css",
"./static/js/48.2b0072e9.chunk.js": "/react/build/./static/js/48.2b0072e9.chunk.js",
"static/css/49.5c81fe74.chunk.css": "/react/build/static/css/49.5c81fe74.chunk.css",
"./static/js/49.52f41fd7.chunk.js": "/react/build/./static/js/49.52f41fd7.chunk.js",
"./static/js/50.925643ee.chunk.js": "/react/build/./static/js/50.925643ee.chunk.js",
"static/css/51.080d6958.chunk.css": "/react/build/static/css/51.080d6958.chunk.css",
"./static/js/51.5ee89aa0.chunk.js": "/react/build/./static/js/51.5ee89aa0.chunk.js",
"./static/js/52.d514755b.chunk.js": "/react/build/./static/js/52.d514755b.chunk.js",
"./static/js/53.31e60498.chunk.js": "/react/build/./static/js/53.31e60498.chunk.js",
"static/css/54.c9adf574.chunk.css": "/react/build/static/css/54.c9adf574.chunk.css",
"./static/js/54.5192af32.chunk.js": "/react/build/./static/js/54.5192af32.chunk.js",
"static/css/55.b299cb62.chunk.css": "/react/build/static/css/55.b299cb62.chunk.css",
"./static/js/55.ce4bb066.chunk.js": "/react/build/./static/js/55.ce4bb066.chunk.js",
"static/css/56.4f215d24.chunk.css": "/react/build/static/css/56.4f215d24.chunk.css",
"./static/js/56.c0cb6388.chunk.js": "/react/build/./static/js/56.c0cb6388.chunk.js",
"static/css/57.19d38f88.chunk.css": "/react/build/static/css/57.19d38f88.chunk.css",
"./static/js/57.d3e720bf.chunk.js": "/react/build/./static/js/57.d3e720bf.chunk.js",
"static/css/58.e8001192.chunk.css": "/react/build/static/css/58.e8001192.chunk.css",
"./static/js/58.e2d064c3.chunk.js": "/react/build/./static/js/58.e2d064c3.chunk.js",
"static/css/59.ff2c3b14.chunk.css": "/react/build/static/css/59.ff2c3b14.chunk.css",
"./static/js/59.10c3d9dd.chunk.js": "/react/build/./static/js/59.10c3d9dd.chunk.js",
"static/css/60.c0f62e1a.chunk.css": "/react/build/static/css/60.c0f62e1a.chunk.css",
"./static/js/60.40b41e97.chunk.js": "/react/build/./static/js/60.40b41e97.chunk.js",
"static/css/61.cd48c477.chunk.css": "/react/build/static/css/61.cd48c477.chunk.css",
"./static/js/61.59c84ed6.chunk.js": "/react/build/./static/js/61.59c84ed6.chunk.js",
"static/css/62.1b6ed5c5.chunk.css": "/react/build/static/css/62.1b6ed5c5.chunk.css",
"./static/js/62.ec026a1a.chunk.js": "/react/build/./static/js/62.ec026a1a.chunk.js",
"static/css/63.67a9b0d6.chunk.css": "/react/build/static/css/63.67a9b0d6.chunk.css",
"./static/js/63.eef6a7a2.chunk.js": "/react/build/./static/js/63.eef6a7a2.chunk.js",
"static/css/64.859e5099.chunk.css": "/react/build/static/css/64.859e5099.chunk.css",
"./static/js/64.fcef2b45.chunk.js": "/react/build/./static/js/64.fcef2b45.chunk.js",
"static/css/65.1d3b7a8d.chunk.css": "/react/build/static/css/65.1d3b7a8d.chunk.css",
"./static/js/65.26785650.chunk.js": "/react/build/./static/js/65.26785650.chunk.js",
"static/css/66.1ff4022b.chunk.css": "/react/build/static/css/66.1ff4022b.chunk.css",
"./static/js/66.afc9f09c.chunk.js": "/react/build/./static/js/66.afc9f09c.chunk.js",
"static/css/67.f8123c09.chunk.css": "/react/build/static/css/67.f8123c09.chunk.css",
"./static/js/67.59faa180.chunk.js": "/react/build/./static/js/67.59faa180.chunk.js",
"./static/js/68.7902a094.chunk.js": "/react/build/./static/js/68.7902a094.chunk.js",
"static/css/69.05177416.chunk.css": "/react/build/static/css/69.05177416.chunk.css",
"./static/js/69.c59f6352.chunk.js": "/react/build/./static/js/69.c59f6352.chunk.js",
"static/css/70.520bfea6.chunk.css": "/react/build/static/css/70.520bfea6.chunk.css",
"./static/js/70.53ffff10.chunk.js": "/react/build/./static/js/70.53ffff10.chunk.js",
"static/css/71.a5678b8f.chunk.css": "/react/build/static/css/71.a5678b8f.chunk.css",
"./static/js/71.83e736e7.chunk.js": "/react/build/./static/js/71.83e736e7.chunk.js",
"static/css/72.9d206204.chunk.css": "/react/build/static/css/72.9d206204.chunk.css",
"./static/js/72.a7cc2a03.chunk.js": "/react/build/./static/js/72.a7cc2a03.chunk.js",
"./static/js/73.bc81d326.chunk.js": "/react/build/./static/js/73.bc81d326.chunk.js",
"static/css/74.ea97577b.chunk.css": "/react/build/static/css/74.ea97577b.chunk.css",
"./static/js/74.b4295353.chunk.js": "/react/build/./static/js/74.b4295353.chunk.js",
"static/css/75.2cfa3592.chunk.css": "/react/build/static/css/75.2cfa3592.chunk.css",
"./static/js/75.6f46e072.chunk.js": "/react/build/./static/js/75.6f46e072.chunk.js",
"static/css/76.b2109eb4.chunk.css": "/react/build/static/css/76.b2109eb4.chunk.css",
"./static/js/76.d42f3d17.chunk.js": "/react/build/./static/js/76.d42f3d17.chunk.js",
"static/css/77.1819b82d.chunk.css": "/react/build/static/css/77.1819b82d.chunk.css",
"./static/js/77.fe5da44a.chunk.js": "/react/build/./static/js/77.fe5da44a.chunk.js",
"static/css/78.61b37499.chunk.css": "/react/build/static/css/78.61b37499.chunk.css",
"./static/js/78.ce83ec22.chunk.js": "/react/build/./static/js/78.ce83ec22.chunk.js",
"static/css/79.61b37499.chunk.css": "/react/build/static/css/79.61b37499.chunk.css",
"./static/js/79.5342dbfc.chunk.js": "/react/build/./static/js/79.5342dbfc.chunk.js",
"static/css/80.802376aa.chunk.css": "/react/build/static/css/80.802376aa.chunk.css",
"./static/js/80.3f5ef3a2.chunk.js": "/react/build/./static/js/80.3f5ef3a2.chunk.js",
"static/css/81.92df39ea.chunk.css": "/react/build/static/css/81.92df39ea.chunk.css",
"./static/js/81.9e9bf3fd.chunk.js": "/react/build/./static/js/81.9e9bf3fd.chunk.js",
"static/css/82.92df39ea.chunk.css": "/react/build/static/css/82.92df39ea.chunk.css",
"./static/js/82.fd712587.chunk.js": "/react/build/./static/js/82.fd712587.chunk.js",
"./static/js/83.b9f283c4.chunk.js": "/react/build/./static/js/83.b9f283c4.chunk.js",
"./static/js/84.9bb7165f.chunk.js": "/react/build/./static/js/84.9bb7165f.chunk.js",
"./static/js/85.bfbe6043.chunk.js": "/react/build/./static/js/85.bfbe6043.chunk.js",
"static/css/86.a8f06a40.chunk.css": "/react/build/static/css/86.a8f06a40.chunk.css",
"./static/js/86.2f9efa27.chunk.js": "/react/build/./static/js/86.2f9efa27.chunk.js",
"static/css/87.b6f629c2.chunk.css": "/react/build/static/css/87.b6f629c2.chunk.css",
"./static/js/87.e348ac7d.chunk.js": "/react/build/./static/js/87.e348ac7d.chunk.js",
"static/css/88.632d7855.chunk.css": "/react/build/static/css/88.632d7855.chunk.css",
"./static/js/88.6a467b5d.chunk.js": "/react/build/./static/js/88.6a467b5d.chunk.js",
"static/css/89.f243baca.chunk.css": "/react/build/static/css/89.f243baca.chunk.css",
"./static/js/89.b2ac706b.chunk.js": "/react/build/./static/js/89.b2ac706b.chunk.js",
"static/css/90.3433735d.chunk.css": "/react/build/static/css/90.3433735d.chunk.css",
"./static/js/90.d1263828.chunk.js": "/react/build/./static/js/90.d1263828.chunk.js",
"static/css/91.9d206204.chunk.css": "/react/build/static/css/91.9d206204.chunk.css",
"./static/js/91.b7150f8a.chunk.js": "/react/build/./static/js/91.b7150f8a.chunk.js",
"static/css/92.9d206204.chunk.css": "/react/build/static/css/92.9d206204.chunk.css",
"./static/js/92.eb12337b.chunk.js": "/react/build/./static/js/92.eb12337b.chunk.js",
"static/css/93.92df39ea.chunk.css": "/react/build/static/css/93.92df39ea.chunk.css",
"./static/js/93.6098cd94.chunk.js": "/react/build/./static/js/93.6098cd94.chunk.js",
"./static/js/94.590a09ed.chunk.js": "/react/build/./static/js/94.590a09ed.chunk.js",
"static/css/95.11a04942.chunk.css": "/react/build/static/css/95.11a04942.chunk.css",
"./static/js/95.fa090474.chunk.js": "/react/build/./static/js/95.fa090474.chunk.js",
"static/css/96.9d206204.chunk.css": "/react/build/static/css/96.9d206204.chunk.css",
"./static/js/96.58181535.chunk.js": "/react/build/./static/js/96.58181535.chunk.js",
"./static/js/97.ecf134b1.chunk.js": "/react/build/./static/js/97.ecf134b1.chunk.js",
"./static/js/98.d0eedbe0.chunk.js": "/react/build/./static/js/98.d0eedbe0.chunk.js",
"./static/js/99.3ec78a01.chunk.js": "/react/build/./static/js/99.3ec78a01.chunk.js",
"./static/js/100.afd86b44.chunk.js": "/react/build/./static/js/100.afd86b44.chunk.js",
"./static/js/101.f94be57e.chunk.js": "/react/build/./static/js/101.f94be57e.chunk.js",
"static/css/102.3edde0c7.chunk.css": "/react/build/static/css/102.3edde0c7.chunk.css",
"./static/js/102.b599d68b.chunk.js": "/react/build/./static/js/102.b599d68b.chunk.js",
"static/css/103.93537df9.chunk.css": "/react/build/static/css/103.93537df9.chunk.css",
"./static/js/103.37711bf4.chunk.js": "/react/build/./static/js/103.37711bf4.chunk.js",
"./static/js/104.a849ee5d.chunk.js": "/react/build/./static/js/104.a849ee5d.chunk.js",
"static/css/105.18309b6c.chunk.css": "/react/build/static/css/105.18309b6c.chunk.css",
"./static/js/105.834e0f24.chunk.js": "/react/build/./static/js/105.834e0f24.chunk.js",
"./static/js/106.581458cf.chunk.js": "/react/build/./static/js/106.581458cf.chunk.js",
"./static/js/107.61313aba.chunk.js": "/react/build/./static/js/107.61313aba.chunk.js",
"./static/js/108.7162ad9d.chunk.js": "/react/build/./static/js/108.7162ad9d.chunk.js",
"./static/js/109.b6b83b49.chunk.js": "/react/build/./static/js/109.b6b83b49.chunk.js",
"static/css/110.1ff4022b.chunk.css": "/react/build/static/css/110.1ff4022b.chunk.css",
"./static/js/110.19c181c9.chunk.js": "/react/build/./static/js/110.19c181c9.chunk.js",
"static/css/111.acf78e2c.chunk.css": "/react/build/static/css/111.acf78e2c.chunk.css",
"./static/js/111.fc28ee3c.chunk.js": "/react/build/./static/js/111.fc28ee3c.chunk.js",
"static/css/112.28bf6b3d.chunk.css": "/react/build/static/css/112.28bf6b3d.chunk.css",
"./static/js/112.fe75aa10.chunk.js": "/react/build/./static/js/112.fe75aa10.chunk.js",
"static/css/113.2d9ce95a.chunk.css": "/react/build/static/css/113.2d9ce95a.chunk.css",
"./static/js/113.6e2f7811.chunk.js": "/react/build/./static/js/113.6e2f7811.chunk.js",
"static/css/114.93537df9.chunk.css": "/react/build/static/css/114.93537df9.chunk.css",
"./static/js/114.36172f9e.chunk.js": "/react/build/./static/js/114.36172f9e.chunk.js",
"static/css/115.93537df9.chunk.css": "/react/build/static/css/115.93537df9.chunk.css",
"./static/js/115.d1207bdb.chunk.js": "/react/build/./static/js/115.d1207bdb.chunk.js",
"./static/js/81.ba015d38.chunk.js": "/react/build/./static/js/81.ba015d38.chunk.js",
"static/css/82.1926e8da.chunk.css": "/react/build/static/css/82.1926e8da.chunk.css",
"./static/js/82.a1a65dfb.chunk.js": "/react/build/./static/js/82.a1a65dfb.chunk.js",
"static/css/83.72690062.chunk.css": "/react/build/static/css/83.72690062.chunk.css",
"./static/js/83.0887adae.chunk.js": "/react/build/./static/js/83.0887adae.chunk.js",
"./static/js/84.94bfd72f.chunk.js": "/react/build/./static/js/84.94bfd72f.chunk.js",
"static/css/85.4054f41b.chunk.css": "/react/build/static/css/85.4054f41b.chunk.css",
"./static/js/85.d6f1cefb.chunk.js": "/react/build/./static/js/85.d6f1cefb.chunk.js",
"static/css/86.f4de1d43.chunk.css": "/react/build/static/css/86.f4de1d43.chunk.css",
"./static/js/86.50073a17.chunk.js": "/react/build/./static/js/86.50073a17.chunk.js",
"static/css/87.d16cbade.chunk.css": "/react/build/static/css/87.d16cbade.chunk.css",
"./static/js/87.b8390d79.chunk.js": "/react/build/./static/js/87.b8390d79.chunk.js",
"static/css/88.2276e27f.chunk.css": "/react/build/static/css/88.2276e27f.chunk.css",
"./static/js/88.dea70be9.chunk.js": "/react/build/./static/js/88.dea70be9.chunk.js",
"static/css/89.131374a7.chunk.css": "/react/build/static/css/89.131374a7.chunk.css",
"./static/js/89.291ce5a8.chunk.js": "/react/build/./static/js/89.291ce5a8.chunk.js",
"static/css/90.c2f5b906.chunk.css": "/react/build/static/css/90.c2f5b906.chunk.css",
"./static/js/90.d3038559.chunk.js": "/react/build/./static/js/90.d3038559.chunk.js",
"static/css/91.fd3fa2e9.chunk.css": "/react/build/static/css/91.fd3fa2e9.chunk.css",
"./static/js/91.f18b6c1b.chunk.js": "/react/build/./static/js/91.f18b6c1b.chunk.js",
"./static/js/92.3ad04ab0.chunk.js": "/react/build/./static/js/92.3ad04ab0.chunk.js",
"static/css/93.45444cfc.chunk.css": "/react/build/static/css/93.45444cfc.chunk.css",
"./static/js/93.65332b80.chunk.js": "/react/build/./static/js/93.65332b80.chunk.js",
"static/css/94.92df39ea.chunk.css": "/react/build/static/css/94.92df39ea.chunk.css",
"./static/js/94.2eb46321.chunk.js": "/react/build/./static/js/94.2eb46321.chunk.js",
"static/css/95.92df39ea.chunk.css": "/react/build/static/css/95.92df39ea.chunk.css",
"./static/js/95.6a4663c6.chunk.js": "/react/build/./static/js/95.6a4663c6.chunk.js",
"./static/js/96.33c3003a.chunk.js": "/react/build/./static/js/96.33c3003a.chunk.js",
"./static/js/97.4d58f6ed.chunk.js": "/react/build/./static/js/97.4d58f6ed.chunk.js",
"./static/js/98.cf8af97d.chunk.js": "/react/build/./static/js/98.cf8af97d.chunk.js",
"static/css/99.3598c90d.chunk.css": "/react/build/static/css/99.3598c90d.chunk.css",
"./static/js/99.7a29bea0.chunk.js": "/react/build/./static/js/99.7a29bea0.chunk.js",
"static/css/100.b6f629c2.chunk.css": "/react/build/static/css/100.b6f629c2.chunk.css",
"./static/js/100.003304fc.chunk.js": "/react/build/./static/js/100.003304fc.chunk.js",
"static/css/101.632d7855.chunk.css": "/react/build/static/css/101.632d7855.chunk.css",
"./static/js/101.6fb0ee37.chunk.js": "/react/build/./static/js/101.6fb0ee37.chunk.js",
"static/css/102.f243baca.chunk.css": "/react/build/static/css/102.f243baca.chunk.css",
"./static/js/102.1ba8c377.chunk.js": "/react/build/./static/js/102.1ba8c377.chunk.js",
"static/css/103.e2a8a600.chunk.css": "/react/build/static/css/103.e2a8a600.chunk.css",
"./static/js/103.aeee29a1.chunk.js": "/react/build/./static/js/103.aeee29a1.chunk.js",
"static/css/104.9d206204.chunk.css": "/react/build/static/css/104.9d206204.chunk.css",
"./static/js/104.b122bfac.chunk.js": "/react/build/./static/js/104.b122bfac.chunk.js",
"static/css/105.9d206204.chunk.css": "/react/build/static/css/105.9d206204.chunk.css",
"./static/js/105.acdf0245.chunk.js": "/react/build/./static/js/105.acdf0245.chunk.js",
"static/css/106.92df39ea.chunk.css": "/react/build/static/css/106.92df39ea.chunk.css",
"./static/js/106.6ddaec4e.chunk.js": "/react/build/./static/js/106.6ddaec4e.chunk.js",
"static/css/107.92df39ea.chunk.css": "/react/build/static/css/107.92df39ea.chunk.css",
"./static/js/107.b74153ec.chunk.js": "/react/build/./static/js/107.b74153ec.chunk.js",
"./static/js/108.a0a22f46.chunk.js": "/react/build/./static/js/108.a0a22f46.chunk.js",
"static/css/109.11a04942.chunk.css": "/react/build/static/css/109.11a04942.chunk.css",
"./static/js/109.0b0b354a.chunk.js": "/react/build/./static/js/109.0b0b354a.chunk.js",
"static/css/110.9d206204.chunk.css": "/react/build/static/css/110.9d206204.chunk.css",
"./static/js/110.67808dac.chunk.js": "/react/build/./static/js/110.67808dac.chunk.js",
"./static/js/111.dbfb317d.chunk.js": "/react/build/./static/js/111.dbfb317d.chunk.js",
"./static/js/112.a09bbdae.chunk.js": "/react/build/./static/js/112.a09bbdae.chunk.js",
"./static/js/113.2e4a5519.chunk.js": "/react/build/./static/js/113.2e4a5519.chunk.js",
"./static/js/114.2a2238be.chunk.js": "/react/build/./static/js/114.2a2238be.chunk.js",
"static/css/115.3edde0c7.chunk.css": "/react/build/static/css/115.3edde0c7.chunk.css",
"./static/js/115.b47d0776.chunk.js": "/react/build/./static/js/115.b47d0776.chunk.js",
"static/css/116.93537df9.chunk.css": "/react/build/static/css/116.93537df9.chunk.css",
"./static/js/116.f43de2f8.chunk.js": "/react/build/./static/js/116.f43de2f8.chunk.js",
"static/css/117.f2060fe7.chunk.css": "/react/build/static/css/117.f2060fe7.chunk.css",
"./static/js/117.11936524.chunk.js": "/react/build/./static/js/117.11936524.chunk.js",
"static/css/118.7d2667aa.chunk.css": "/react/build/static/css/118.7d2667aa.chunk.css",
"./static/js/118.3bad926a.chunk.js": "/react/build/./static/js/118.3bad926a.chunk.js",
"static/css/119.9d206204.chunk.css": "/react/build/static/css/119.9d206204.chunk.css",
"./static/js/119.d6089266.chunk.js": "/react/build/./static/js/119.d6089266.chunk.js",
"./static/js/120.0b5693b9.chunk.js": "/react/build/./static/js/120.0b5693b9.chunk.js",
"./static/js/121.5b1672a5.chunk.js": "/react/build/./static/js/121.5b1672a5.chunk.js",
"./static/js/122.cf4115ae.chunk.js": "/react/build/./static/js/122.cf4115ae.chunk.js",
"./static/js/123.1891b573.chunk.js": "/react/build/./static/js/123.1891b573.chunk.js",
"./static/js/124.9f4ca700.chunk.js": "/react/build/./static/js/124.9f4ca700.chunk.js",
"./static/js/125.7f20b68d.chunk.js": "/react/build/./static/js/125.7f20b68d.chunk.js",
"./static/js/126.bee7c937.chunk.js": "/react/build/./static/js/126.bee7c937.chunk.js",
"./static/js/127.d073db41.chunk.js": "/react/build/./static/js/127.d073db41.chunk.js",
"./static/js/128.878acdba.chunk.js": "/react/build/./static/js/128.878acdba.chunk.js",
"./static/js/129.b738aa28.chunk.js": "/react/build/./static/js/129.b738aa28.chunk.js",
"./static/js/130.85565d42.chunk.js": "/react/build/./static/js/130.85565d42.chunk.js",
"./static/js/131.f0748961.chunk.js": "/react/build/./static/js/131.f0748961.chunk.js",
"./static/js/132.3d7bf2f1.chunk.js": "/react/build/./static/js/132.3d7bf2f1.chunk.js",
"./static/js/133.751e5873.chunk.js": "/react/build/./static/js/133.751e5873.chunk.js",
"./static/js/134.091df8c8.chunk.js": "/react/build/./static/js/134.091df8c8.chunk.js",
"./static/js/135.781429cf.chunk.js": "/react/build/./static/js/135.781429cf.chunk.js",
"./static/js/136.92778520.chunk.js": "/react/build/./static/js/136.92778520.chunk.js",
"./static/js/137.93988170.chunk.js": "/react/build/./static/js/137.93988170.chunk.js",
"./static/js/138.44f95a6c.chunk.js": "/react/build/./static/js/138.44f95a6c.chunk.js",
"./static/js/139.04825aa2.chunk.js": "/react/build/./static/js/139.04825aa2.chunk.js",
"./static/js/140.9300e577.chunk.js": "/react/build/./static/js/140.9300e577.chunk.js",
"./static/js/141.7fe85b5c.chunk.js": "/react/build/./static/js/141.7fe85b5c.chunk.js",
"./static/js/142.4986be2c.chunk.js": "/react/build/./static/js/142.4986be2c.chunk.js",
"./static/js/143.8deca8a8.chunk.js": "/react/build/./static/js/143.8deca8a8.chunk.js",
"./static/js/144.e3a19259.chunk.js": "/react/build/./static/js/144.e3a19259.chunk.js",
"./static/js/145.11e1109e.chunk.js": "/react/build/./static/js/145.11e1109e.chunk.js",
"./static/js/146.88651818.chunk.js": "/react/build/./static/js/146.88651818.chunk.js",
"./static/js/147.76ae369e.chunk.js": "/react/build/./static/js/147.76ae369e.chunk.js",
"./static/js/148.bf2227d8.chunk.js": "/react/build/./static/js/148.bf2227d8.chunk.js",
"./static/js/149.42933dea.chunk.js": "/react/build/./static/js/149.42933dea.chunk.js",
"./static/js/150.f2e48d21.chunk.js": "/react/build/./static/js/150.f2e48d21.chunk.js",
"./static/js/151.b66da5bb.chunk.js": "/react/build/./static/js/151.b66da5bb.chunk.js",
"./static/js/152.5b33b737.chunk.js": "/react/build/./static/js/152.5b33b737.chunk.js",
"./static/js/153.f20f94ab.chunk.js": "/react/build/./static/js/153.f20f94ab.chunk.js",
"./static/js/154.1dcd577d.chunk.js": "/react/build/./static/js/154.1dcd577d.chunk.js",
"./static/js/155.1b354e97.chunk.js": "/react/build/./static/js/155.1b354e97.chunk.js",
"./static/js/156.f051c4e9.chunk.js": "/react/build/./static/js/156.f051c4e9.chunk.js",
"./static/js/157.75e7240f.chunk.js": "/react/build/./static/js/157.75e7240f.chunk.js",
"./static/js/158.dc0da031.chunk.js": "/react/build/./static/js/158.dc0da031.chunk.js",
"./static/js/159.0444bc4e.chunk.js": "/react/build/./static/js/159.0444bc4e.chunk.js",
"./static/js/160.54a63cf6.chunk.js": "/react/build/./static/js/160.54a63cf6.chunk.js",
"./static/js/161.5fcc2993.chunk.js": "/react/build/./static/js/161.5fcc2993.chunk.js",
"./static/js/162.3d05705b.chunk.js": "/react/build/./static/js/162.3d05705b.chunk.js",
"./static/js/163.999b2cd6.chunk.js": "/react/build/./static/js/163.999b2cd6.chunk.js",
"./static/js/164.bc1a4e19.chunk.js": "/react/build/./static/js/164.bc1a4e19.chunk.js",
"./static/js/165.26955e70.chunk.js": "/react/build/./static/js/165.26955e70.chunk.js",
"./static/js/166.e6fa2f04.chunk.js": "/react/build/./static/js/166.e6fa2f04.chunk.js",
"./static/js/167.73863021.chunk.js": "/react/build/./static/js/167.73863021.chunk.js",
"./static/js/168.9e6be64f.chunk.js": "/react/build/./static/js/168.9e6be64f.chunk.js",
"./static/js/169.97340bbd.chunk.js": "/react/build/./static/js/169.97340bbd.chunk.js",
"./static/js/170.8b9b7fbc.chunk.js": "/react/build/./static/js/170.8b9b7fbc.chunk.js",
"./static/js/171.51b25453.chunk.js": "/react/build/./static/js/171.51b25453.chunk.js",
"./static/js/172.a9f3bab1.chunk.js": "/react/build/./static/js/172.a9f3bab1.chunk.js",
"./static/js/173.24903936.chunk.js": "/react/build/./static/js/173.24903936.chunk.js",
"./static/js/174.bcec984e.chunk.js": "/react/build/./static/js/174.bcec984e.chunk.js",
"./static/js/175.ead87ea5.chunk.js": "/react/build/./static/js/175.ead87ea5.chunk.js",
"./static/js/176.3591636e.chunk.js": "/react/build/./static/js/176.3591636e.chunk.js",
"./static/js/177.40ade417.chunk.js": "/react/build/./static/js/177.40ade417.chunk.js",
"./static/js/178.bf3dac42.chunk.js": "/react/build/./static/js/178.bf3dac42.chunk.js",
"./static/js/179.55d44588.chunk.js": "/react/build/./static/js/179.55d44588.chunk.js",
"./static/js/180.1ff60c84.chunk.js": "/react/build/./static/js/180.1ff60c84.chunk.js",
"./static/js/181.3011cf53.chunk.js": "/react/build/./static/js/181.3011cf53.chunk.js",
"./static/js/182.e2f6713c.chunk.js": "/react/build/./static/js/182.e2f6713c.chunk.js",
"./static/js/183.0a31f275.chunk.js": "/react/build/./static/js/183.0a31f275.chunk.js",
"./static/js/184.d84e2682.chunk.js": "/react/build/./static/js/184.d84e2682.chunk.js",
"./static/js/185.4c3bd620.chunk.js": "/react/build/./static/js/185.4c3bd620.chunk.js",
"./static/js/186.610bb516.chunk.js": "/react/build/./static/js/186.610bb516.chunk.js",
"./static/js/187.a15540eb.chunk.js": "/react/build/./static/js/187.a15540eb.chunk.js",
"main.css": "/react/build/static/css/main.ceb94a14.chunk.css",
"main.js": "/react/build/./static/js/main.516632e1.chunk.js",
"runtime~main.js": "/react/build/./static/js/runtime~main.677b7222.js",
"./static/js/140.9300e577.chunk.js.LICENSE.txt": "/react/build/./static/js/140.9300e577.chunk.js.LICENSE.txt",
"./static/js/182.e2f6713c.chunk.js.LICENSE.txt": "/react/build/./static/js/182.e2f6713c.chunk.js.LICENSE.txt",
"./static/js/116.b81ed987.chunk.js": "/react/build/./static/js/116.b81ed987.chunk.js",
"./static/js/117.7fff8d1f.chunk.js": "/react/build/./static/js/117.7fff8d1f.chunk.js",
"./static/js/118.90196e17.chunk.js": "/react/build/./static/js/118.90196e17.chunk.js",
"./static/js/119.8ca783c3.chunk.js": "/react/build/./static/js/119.8ca783c3.chunk.js",
"./static/js/120.dfad4f45.chunk.js": "/react/build/./static/js/120.dfad4f45.chunk.js",
"./static/js/121.7e4e15f6.chunk.js": "/react/build/./static/js/121.7e4e15f6.chunk.js",
"static/css/122.1ff4022b.chunk.css": "/react/build/static/css/122.1ff4022b.chunk.css",
"./static/js/122.b9661dd4.chunk.js": "/react/build/./static/js/122.b9661dd4.chunk.js",
"static/css/123.acf78e2c.chunk.css": "/react/build/static/css/123.acf78e2c.chunk.css",
"./static/js/123.2b4bea2a.chunk.js": "/react/build/./static/js/123.2b4bea2a.chunk.js",
"static/css/124.28bf6b3d.chunk.css": "/react/build/static/css/124.28bf6b3d.chunk.css",
"./static/js/124.0efba3cd.chunk.js": "/react/build/./static/js/124.0efba3cd.chunk.js",
"static/css/125.af9850ad.chunk.css": "/react/build/static/css/125.af9850ad.chunk.css",
"./static/js/125.c9bdba80.chunk.js": "/react/build/./static/js/125.c9bdba80.chunk.js",
"static/css/126.93537df9.chunk.css": "/react/build/static/css/126.93537df9.chunk.css",
"./static/js/126.1e1c6b0d.chunk.js": "/react/build/./static/js/126.1e1c6b0d.chunk.js",
"static/css/127.93537df9.chunk.css": "/react/build/static/css/127.93537df9.chunk.css",
"./static/js/127.ce9a385e.chunk.js": "/react/build/./static/js/127.ce9a385e.chunk.js",
"static/css/128.93537df9.chunk.css": "/react/build/static/css/128.93537df9.chunk.css",
"./static/js/128.7c3345ad.chunk.js": "/react/build/./static/js/128.7c3345ad.chunk.js",
"static/css/129.f2060fe7.chunk.css": "/react/build/static/css/129.f2060fe7.chunk.css",
"./static/js/129.e53ef67f.chunk.js": "/react/build/./static/js/129.e53ef67f.chunk.js",
"static/css/130.0485185f.chunk.css": "/react/build/static/css/130.0485185f.chunk.css",
"./static/js/130.0612b9b9.chunk.js": "/react/build/./static/js/130.0612b9b9.chunk.js",
"static/css/131.9d206204.chunk.css": "/react/build/static/css/131.9d206204.chunk.css",
"./static/js/131.4f4d8f60.chunk.js": "/react/build/./static/js/131.4f4d8f60.chunk.js",
"./static/js/132.34a2259c.chunk.js": "/react/build/./static/js/132.34a2259c.chunk.js",
"./static/js/133.85d8a606.chunk.js": "/react/build/./static/js/133.85d8a606.chunk.js",
"./static/js/134.c846ec39.chunk.js": "/react/build/./static/js/134.c846ec39.chunk.js",
"./static/js/135.42dc9e35.chunk.js": "/react/build/./static/js/135.42dc9e35.chunk.js",
"./static/js/136.e713bbda.chunk.js": "/react/build/./static/js/136.e713bbda.chunk.js",
"./static/js/137.9a584547.chunk.js": "/react/build/./static/js/137.9a584547.chunk.js",
"./static/js/138.30c9bf3e.chunk.js": "/react/build/./static/js/138.30c9bf3e.chunk.js",
"./static/js/139.471b727e.chunk.js": "/react/build/./static/js/139.471b727e.chunk.js",
"./static/js/140.2cf678ec.chunk.js": "/react/build/./static/js/140.2cf678ec.chunk.js",
"./static/js/141.0c37428d.chunk.js": "/react/build/./static/js/141.0c37428d.chunk.js",
"./static/js/142.90447ba1.chunk.js": "/react/build/./static/js/142.90447ba1.chunk.js",
"./static/js/143.a728fd15.chunk.js": "/react/build/./static/js/143.a728fd15.chunk.js",
"./static/js/144.da3d7cb2.chunk.js": "/react/build/./static/js/144.da3d7cb2.chunk.js",
"./static/js/145.5ff39369.chunk.js": "/react/build/./static/js/145.5ff39369.chunk.js",
"./static/js/146.9055d194.chunk.js": "/react/build/./static/js/146.9055d194.chunk.js",
"./static/js/147.67ae26a3.chunk.js": "/react/build/./static/js/147.67ae26a3.chunk.js",
"./static/js/148.469d55ff.chunk.js": "/react/build/./static/js/148.469d55ff.chunk.js",
"./static/js/149.82ddc723.chunk.js": "/react/build/./static/js/149.82ddc723.chunk.js",
"./static/js/150.d9806ad6.chunk.js": "/react/build/./static/js/150.d9806ad6.chunk.js",
"./static/js/151.aa27b140.chunk.js": "/react/build/./static/js/151.aa27b140.chunk.js",
"./static/js/152.f27906a3.chunk.js": "/react/build/./static/js/152.f27906a3.chunk.js",
"./static/js/153.a95c448d.chunk.js": "/react/build/./static/js/153.a95c448d.chunk.js",
"./static/js/154.75dff73a.chunk.js": "/react/build/./static/js/154.75dff73a.chunk.js",
"./static/js/155.bf7b3b90.chunk.js": "/react/build/./static/js/155.bf7b3b90.chunk.js",
"./static/js/156.a5d3cd4c.chunk.js": "/react/build/./static/js/156.a5d3cd4c.chunk.js",
"./static/js/157.3bf78dcc.chunk.js": "/react/build/./static/js/157.3bf78dcc.chunk.js",
"./static/js/158.2ac8f8b0.chunk.js": "/react/build/./static/js/158.2ac8f8b0.chunk.js",
"./static/js/159.4c65dad8.chunk.js": "/react/build/./static/js/159.4c65dad8.chunk.js",
"./static/js/160.8fe98dbd.chunk.js": "/react/build/./static/js/160.8fe98dbd.chunk.js",
"./static/js/161.81b3dc53.chunk.js": "/react/build/./static/js/161.81b3dc53.chunk.js",
"./static/js/162.80cba987.chunk.js": "/react/build/./static/js/162.80cba987.chunk.js",
"./static/js/163.431c740e.chunk.js": "/react/build/./static/js/163.431c740e.chunk.js",
"./static/js/164.9fe89370.chunk.js": "/react/build/./static/js/164.9fe89370.chunk.js",
"./static/js/165.6a20768f.chunk.js": "/react/build/./static/js/165.6a20768f.chunk.js",
"./static/js/166.ced1b182.chunk.js": "/react/build/./static/js/166.ced1b182.chunk.js",
"./static/js/167.49b56732.chunk.js": "/react/build/./static/js/167.49b56732.chunk.js",
"./static/js/168.b9bf1e06.chunk.js": "/react/build/./static/js/168.b9bf1e06.chunk.js",
"./static/js/169.d85c0071.chunk.js": "/react/build/./static/js/169.d85c0071.chunk.js",
"./static/js/170.fc532980.chunk.js": "/react/build/./static/js/170.fc532980.chunk.js",
"./static/js/171.b062dc4f.chunk.js": "/react/build/./static/js/171.b062dc4f.chunk.js",
"./static/js/172.10fae3a9.chunk.js": "/react/build/./static/js/172.10fae3a9.chunk.js",
"./static/js/173.9252f343.chunk.js": "/react/build/./static/js/173.9252f343.chunk.js",
"./static/js/174.3a5ed8e6.chunk.js": "/react/build/./static/js/174.3a5ed8e6.chunk.js",
"./static/js/175.9babcf3f.chunk.js": "/react/build/./static/js/175.9babcf3f.chunk.js",
"./static/js/176.a70acaca.chunk.js": "/react/build/./static/js/176.a70acaca.chunk.js",
"./static/js/177.dbfa5850.chunk.js": "/react/build/./static/js/177.dbfa5850.chunk.js",
"./static/js/178.eed56d06.chunk.js": "/react/build/./static/js/178.eed56d06.chunk.js",
"./static/js/179.6b354d9a.chunk.js": "/react/build/./static/js/179.6b354d9a.chunk.js",
"./static/js/180.af942319.chunk.js": "/react/build/./static/js/180.af942319.chunk.js",
"./static/js/181.70e499f1.chunk.js": "/react/build/./static/js/181.70e499f1.chunk.js",
"./static/js/182.e7c64d3e.chunk.js": "/react/build/./static/js/182.e7c64d3e.chunk.js",
"./static/js/183.093ee74f.chunk.js": "/react/build/./static/js/183.093ee74f.chunk.js",
"./static/js/184.7ed09e68.chunk.js": "/react/build/./static/js/184.7ed09e68.chunk.js",
"./static/js/185.e07e87d8.chunk.js": "/react/build/./static/js/185.e07e87d8.chunk.js",
"./static/js/186.609d9b25.chunk.js": "/react/build/./static/js/186.609d9b25.chunk.js",
"./static/js/187.b08cc870.chunk.js": "/react/build/./static/js/187.b08cc870.chunk.js",
"./static/js/188.9d3f7b7c.chunk.js": "/react/build/./static/js/188.9d3f7b7c.chunk.js",
"./static/js/189.3fbef684.chunk.js": "/react/build/./static/js/189.3fbef684.chunk.js",
"./static/js/190.95b861fa.chunk.js": "/react/build/./static/js/190.95b861fa.chunk.js",
"./static/js/191.dd01864e.chunk.js": "/react/build/./static/js/191.dd01864e.chunk.js",
"./static/js/192.f1caa1fa.chunk.js": "/react/build/./static/js/192.f1caa1fa.chunk.js",
"./static/js/193.bc21c27e.chunk.js": "/react/build/./static/js/193.bc21c27e.chunk.js",
"./static/js/194.fdf7dc7d.chunk.js": "/react/build/./static/js/194.fdf7dc7d.chunk.js",
"main.css": "/react/build/static/css/main.bdb06a8e.chunk.css",
"main.js": "/react/build/./static/js/main.eae036cf.chunk.js",
"runtime~main.js": "/react/build/./static/js/runtime~main.cbbbfc02.js",
"./static/js/147.67ae26a3.chunk.js.LICENSE.txt": "/react/build/./static/js/147.67ae26a3.chunk.js.LICENSE.txt",
"./static/js/189.3fbef684.chunk.js.LICENSE.txt": "/react/build/./static/js/189.3fbef684.chunk.js.LICENSE.txt",
"./static/js/2.d659edf3.chunk.js.LICENSE.txt": "/react/build/./static/js/2.d659edf3.chunk.js.LICENSE.txt",
"./static/js/27.fc2d3a1f.chunk.js.LICENSE.txt": "/react/build/./static/js/27.fc2d3a1f.chunk.js.LICENSE.txt",
"./static/js/7.a1394f8d.chunk.js.LICENSE.txt": "/react/build/./static/js/7.a1394f8d.chunk.js.LICENSE.txt",
"./static/js/main.516632e1.chunk.js.LICENSE.txt": "/react/build/./static/js/main.516632e1.chunk.js.LICENSE.txt",
"./static/js/34.b06d630a.chunk.js.LICENSE.txt": "/react/build/./static/js/34.b06d630a.chunk.js.LICENSE.txt",
"./static/js/35.d6dd0530.chunk.js.LICENSE.txt": "/react/build/./static/js/35.d6dd0530.chunk.js.LICENSE.txt",
"./static/js/8.882648e1.chunk.js.LICENSE.txt": "/react/build/./static/js/8.882648e1.chunk.js.LICENSE.txt",
"./static/js/main.eae036cf.chunk.js.LICENSE.txt": "/react/build/./static/js/main.eae036cf.chunk.js.LICENSE.txt",
"css.worker.js": "/react/build/css.worker.js",
"editor.worker.js": "/react/build/editor.worker.js",
"html.worker.js": "/react/build/html.worker.js",
"index.html": "/react/build/index.html",
"json.worker.js": "/react/build/json.worker.js",
"static/media/Index.scss": "/react/build/static/media/typebg.b2b0ea32.png",
"static/media/2-2-1.png": "/react/build/static/media/2-2-1.afd0f2f5.png",
"static/media/2-2-2.png": "/react/build/static/media/2-2-2.26bc3301.png",
"static/media/2-2-3.png": "/react/build/static/media/2-2-3.6d6ce99c.png",
"static/media/2-2-head.png": "/react/build/static/media/2-2-head.5e69dbb2.png",
"static/media/2-3-1.png": "/react/build/static/media/2-3-1.bcb33d47.png",
"static/media/2-3-2.png": "/react/build/static/media/2-3-2.84718f27.png",
"static/media/2-3-3.png": "/react/build/static/media/2-3-3.db9fe021.png",
"static/media/2-3-4.png": "/react/build/static/media/2-3-4.15673036.png",
"static/media/2-6-1.png": "/react/build/static/media/2-6-1.302b729e.png",
"static/media/2-6-2.png": "/react/build/static/media/2-6-2.b262b91e.png",
"static/media/3-1.png": "/react/build/static/media/3-1.9fdda521.png",
"static/media/3-2.png": "/react/build/static/media/3-2.47050941.png",
"static/media/3-3.png": "/react/build/static/media/3-3.c767aae7.png",
"static/media/3-4.png": "/react/build/static/media/3-4.92820cbc.png",
"static/media/4-1.png": "/react/build/static/media/4-1.79fa159d.png",
"static/media/4-2.png": "/react/build/static/media/4-2.9c066e75.png",
"static/media/4-3.png": "/react/build/static/media/4-3.a1487a5b.png",
"static/media/4-4.png": "/react/build/static/media/4-4.5eb40734.png",
"static/media/BJHKHT.png": "/react/build/static/media/BJHKHT.f065403a.png",
"static/media/CEC.png": "/react/build/static/media/CEC.3b748059.png",
"static/media/GFKJ.png": "/react/build/static/media/GFKJ.eb30c414.png",
"static/media/HSKY.png": "/react/build/static/media/HSKY.2e76ba44.png",
"static/media/ISCAS.png": "/react/build/static/media/ISCAS.851fcfda.png",
"static/media/KYRJLM.png": "/react/build/static/media/KYRJLM.2d659e5c.png",
"static/media/katex.min.css": "/react/build/static/media/KaTeX_Typewriter-Regular.d3c8e68f.woff",
"static/media/LC.png": "/react/build/static/media/LC.f247fdb8.png",
"static/media/LSLM.png": "/react/build/static/media/LSLM.99387946.png",
"static/media/ML.png": "/react/build/static/media/ML.08d278e2.png",
"static/media/NJDX.png": "/react/build/static/media/NJDX.bb34b326.png",
"static/media/QH.png": "/react/build/static/media/QH.b57a0131.png",
"static/media/SHJT.png": "/react/build/static/media/SHJT.426bf0c7.png",
"static/media/TX.png": "/react/build/static/media/TX.b703476c.png",
"static/media/WXYJY.png": "/react/build/static/media/WXYJY.21e40191.png",
"static/media/XH.png": "/react/build/static/media/XH.a0a88f17.png",
"static/media/XJY.png": "/react/build/static/media/XJY.b4c57bf1.png",
"static/media/YKD.png": "/react/build/static/media/YKD.4f7e2766.png",
"static/media/ZC.png": "/react/build/static/media/ZC.ad056aa5.png",
"static/media/achievements.png": "/react/build/static/media/achievements.f20b7e39.png",
"static/media/ball.png": "/react/build/static/media/ball.24214b6e.png",
"static/media/AboutUs.scss": "/react/build/static/media/joinUs.26ec28cd.png",
"static/media/banner.png": "/react/build/static/media/banner.f7da2db1.png",
"static/media/banner_list.jpg": "/react/build/static/media/banner_list.e02c5e16.jpg",
"static/media/beijing.png": "/react/build/static/media/beijing.bfcd5b0e.png",
"static/media/beijintulogontwo.png": "/react/build/static/media/beijintulogontwo.41076faf.png",
"static/media/Index.scss": "/react/build/static/media/bg.401bf2cf.png",
"static/media/educoder.png": "/react/build/static/media/educoder.695bfe08.png",
"static/media/logo.png": "/react/build/static/media/logo.1c60f36c.png",
"static/media/LoginRegisterPage.scss": "/react/build/static/media/rightBg.55f14f0c.png",
"static/media/codeafter.png": "/react/build/static/media/codeafter.c3088c74.png",
"static/media/computer.png": "/react/build/static/media/computer.4fe86b12.png",
"static/media/earth.png": "/react/build/static/media/earth.050b1435.png",
"static/media/fun1.png": "/react/build/static/media/fun1.c99ffa49.png",
"static/media/fun2.png": "/react/build/static/media/fun2.12f22bca.png",
"static/media/fun3.png": "/react/build/static/media/fun3.75c280e6.png",
"static/media/fun4.png": "/react/build/static/media/fun4.f499794e.png",
"static/media/fun5.png": "/react/build/static/media/fun5.96b44942.png",
"static/media/huake.png": "/react/build/static/media/huake.63b6a34d.png",
"static/media/huawei.png": "/react/build/static/media/huawei.73ec7c22.png",
"static/media/img1.png": "/react/build/static/media/img1.8560258f.png",
"static/media/img2.png": "/react/build/static/media/img2.ae303051.png",
"static/media/jijinhui.png": "/react/build/static/media/jijinhui.041fb524.png",
"static/media/logo.png": "/react/build/static/media/logo.35cca493.png",
"static/media/mulan.png": "/react/build/static/media/mulan.690d2289.png",
"static/media/slick-theme.css": "/react/build/static/media/slick.c94f7671.ttf",
"static/media/subtitle.png": "/react/build/static/media/subtitle.5019e086.png",
"static/media/index.scss": "/react/build/static/media/taskbar.49a40f3a.png",
"static/media/xigongye.png": "/react/build/static/media/xigongye.d51231d3.png",
"static/media/xiuos.png": "/react/build/static/media/xiuos.67682257.png",
"ts.worker.js": "/react/build/ts.worker.js",
"ts.worker.js.LICENSE.txt": "/react/build/ts.worker.js.LICENSE.txt"
}

View File

@ -1268,11 +1268,17 @@ a.shixun-task-btn {
/*-----------实训配置、评测脚本-------------*/
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1631773579834') format('woff2'),
url('iconfont.woff?t=1631773579834') format('woff'),
url('iconfont.ttf?t=1631773579834') format('truetype');
}
html body {
font-size: 14px;
line-height: 2.0;
background: #fafafa;
font-family: "Microsoft YaHei", "SimSun";
font-family: "iconfont";
color: #05101a;
height: 100%;
position: relative;
@ -3941,7 +3947,7 @@ html>body #ajax-indicator {
}
.head-nav {
text-align: center;
height: 70px;
height: 58px;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
@ -3953,14 +3959,14 @@ html>body #ajax-indicator {
position: absolute;
top: 0px;
z-index: 3;
height: 70px;
height: 58px;
box-sizing: border-box;
}
.head-nav ul#header-nav li {
float: left;
height: 70px;
line-height: 70px;
height: 58px;
line-height: 58px;
cursor: pointer;
position: relative;
font-size: 16px;
@ -3971,7 +3977,7 @@ html>body #ajax-indicator {
display: block;
height: 100%;
width: 100%;
color: #333;
color: #fff;
font-size: 16px;
}
@ -3983,10 +3989,6 @@ html>body #ajax-indicator {
margin-right: 0px
}
.head-nav ul#header-nav li.active{
/* background-color: #3B3B3B; */
}
.head-nav ul#header-nav li p:hover {
color: #cccccc;
@ -6705,13 +6707,10 @@ p{
right: 0px;
top:4px;
color: #999;
<<<<<<< HEAD
=======
}
.ant-input, .ant-input .ant-input-suffix{
background-color: #fff!important;
}
.has-error .ant-input{
background-color: #FEF1F0!important;
>>>>>>> pre_develop
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1634881729644') format('woff2'),
url('iconfont.woff?t=1634881729644') format('woff'),
url('iconfont.ttf?t=1634881729644') format('truetype');
src: url('iconfont.woff2?t=1637544235157') format('woff2'),
url('iconfont.woff?t=1637544235157') format('woff'),
url('iconfont.ttf?t=1637544235157') format('truetype');
}
.iconfont {
@ -13,6 +13,106 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zhishitupu:before {
content: "\e8fc";
}
.icon-jisuanji1:before {
content: "\e8fd";
}
.icon-dianzi1:before {
content: "\e8ff";
}
.icon-junshililun1:before {
content: "\e900";
}
.icon-ruanjiangongcheng1:before {
content: "\e901";
}
.icon-yixue1:before {
content: "\e902";
}
.icon-tongxin1:before {
content: "\e904";
}
.icon-zhengcefagui1:before {
content: "\e906";
}
.icon-dashuju:before {
content: "\e8f3";
}
.icon-rengongzhineng:before {
content: "\e8f6";
}
.icon-a-shuangyinhao12x:before {
content: "\e8f2";
}
.icon-dingbu:before {
content: "\e8ee";
}
.icon-bangzhu1:before {
content: "\e8ef";
}
.icon-yijianfankui2:before {
content: "\e8f0";
}
.icon-fenxiang:before {
content: "\e8f1";
}
.icon-dizhi:before {
content: "\e8eb";
}
.icon-youxiang1:before {
content: "\e8ec";
}
.icon-dianhuaicon:before {
content: "\e8ed";
}
.icon-tianjiaicon:before {
content: "\e8e8";
}
.icon-lingshengicon:before {
content: "\e8ea";
}
.icon-gengduoicon:before {
content: "\e8e5";
}
.icon-shijianicon:before {
content: "\e8e7";
}
.icon-mimaicon:before {
content: "\e8e1";
}
.icon-gouicon:before {
content: "\e8e2";
}
.icon-zhankaiicon:before {
content: "\e8e3";
}
.icon-wenjian7:before {
content: "\e8e0";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,181 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "25748537",
"name": "知识图谱",
"font_class": "zhishitupu",
"unicode": "e8fc",
"unicode_decimal": 59644
},
{
"icon_id": "25748551",
"name": "计算机",
"font_class": "jisuanji1",
"unicode": "e8fd",
"unicode_decimal": 59645
},
{
"icon_id": "25748553",
"name": "电子",
"font_class": "dianzi1",
"unicode": "e8ff",
"unicode_decimal": 59647
},
{
"icon_id": "25748554",
"name": "军事理论",
"font_class": "junshililun1",
"unicode": "e900",
"unicode_decimal": 59648
},
{
"icon_id": "25748555",
"name": "软件工程",
"font_class": "ruanjiangongcheng1",
"unicode": "e901",
"unicode_decimal": 59649
},
{
"icon_id": "25748556",
"name": "医学",
"font_class": "yixue1",
"unicode": "e902",
"unicode_decimal": 59650
},
{
"icon_id": "25748558",
"name": "通信",
"font_class": "tongxin1",
"unicode": "e904",
"unicode_decimal": 59652
},
{
"icon_id": "25748560",
"name": "政策法规",
"font_class": "zhengcefagui1",
"unicode": "e906",
"unicode_decimal": 59654
},
{
"icon_id": "25748528",
"name": "大数据",
"font_class": "dashuju",
"unicode": "e8f3",
"unicode_decimal": 59635
},
{
"icon_id": "25748531",
"name": "人工智能",
"font_class": "rengongzhineng",
"unicode": "e8f6",
"unicode_decimal": 59638
},
{
"icon_id": "25733167",
"name": "双引号(1)@2x",
"font_class": "a-shuangyinhao12x",
"unicode": "e8f2",
"unicode_decimal": 59634
},
{
"icon_id": "25701947",
"name": "顶部",
"font_class": "dingbu",
"unicode": "e8ee",
"unicode_decimal": 59630
},
{
"icon_id": "25701948",
"name": "帮助",
"font_class": "bangzhu1",
"unicode": "e8ef",
"unicode_decimal": 59631
},
{
"icon_id": "25701949",
"name": "意见反馈",
"font_class": "yijianfankui2",
"unicode": "e8f0",
"unicode_decimal": 59632
},
{
"icon_id": "25701950",
"name": "分享",
"font_class": "fenxiang",
"unicode": "e8f1",
"unicode_decimal": 59633
},
{
"icon_id": "25580217",
"name": "地址",
"font_class": "dizhi",
"unicode": "e8eb",
"unicode_decimal": 59627
},
{
"icon_id": "25580218",
"name": "邮箱",
"font_class": "youxiang1",
"unicode": "e8ec",
"unicode_decimal": 59628
},
{
"icon_id": "25580219",
"name": "电话icon",
"font_class": "dianhuaicon",
"unicode": "e8ed",
"unicode_decimal": 59629
},
{
"icon_id": "25284174",
"name": "添加icon",
"font_class": "tianjiaicon",
"unicode": "e8e8",
"unicode_decimal": 59624
},
{
"icon_id": "25284175",
"name": "铃声icon",
"font_class": "lingshengicon",
"unicode": "e8ea",
"unicode_decimal": 59626
},
{
"icon_id": "25204490",
"name": "更多icon",
"font_class": "gengduoicon",
"unicode": "e8e5",
"unicode_decimal": 59621
},
{
"icon_id": "25204491",
"name": "时间icon",
"font_class": "shijianicon",
"unicode": "e8e7",
"unicode_decimal": 59623
},
{
"icon_id": "25188228",
"name": "密码icon",
"font_class": "mimaicon",
"unicode": "e8e1",
"unicode_decimal": 59617
},
{
"icon_id": "25188229",
"name": "钩icon",
"font_class": "gouicon",
"unicode": "e8e2",
"unicode_decimal": 59618
},
{
"icon_id": "25188230",
"name": "展开icon",
"font_class": "zhankaiicon",
"unicode": "e8e3",
"unicode_decimal": 59619
},
{
"icon_id": "24656750",
"name": "文件",

Binary file not shown.

Binary file not shown.

BIN
public/react/build/favicon-.ico Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1 +1 @@
<!doctype html><html lang="zh-CN" class="notranslate translated-ltr" translate="no"><head><meta charset="utf-8"><meta name="”Keywords”" content="”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″"><meta name="”Keywords”" content="”TrustieOpenSourceProject″"><meta name="”Keywords”" content="”issue,bug,tracker,软件工程,课程实践″"><meta name="”Description”" content="”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”"><meta name="theme-color" content="#000000"><link rel="manifest" href="/react/build//manifest.json"><link rel="stylesheet" href="/react/build/css/iconfont.css"><link rel="stylesheet" href="/react/build/css/edu-purge.css"><link rel="stylesheet" href="/react/build/css/editormd.min.css"><link rel="stylesheet" href="/react/build/css/merge.css"><link href="/react/build/static/css/main.ceb94a14.chunk.css" rel="stylesheet"></head><body><div id="md_div" style="display:none"></div><div id="root" class="page -layout-v -fit widthunit"></div><div id="picture_display" style="display:none"></div><script src="/react/build/js/jquery-1.8.3.min.js"></script><script src="/react/build/js/js_min_all.js"></script><script src="/react/build/js/codemirror/codemirror.js"></script><script src="/react/build/js/editormd/editormd.min.js"></script><script src="/react/build/js/codemirror/merge/merge.js"></script><script src="/react/build/./static/js/runtime~main.677b7222.js"></script><script src="/react/build/./static/js/main.516632e1.chunk.js"></script></body></html>
<!doctype html><html lang="zh-CN" class="notranslate translated-ltr" translate="no"><head><meta charset="utf-8"><meta name="”Keywords”" content="”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″"><meta name="”Keywords”" content="”TrustieOpenSourceProject″"><meta name="”Keywords”" content="”issue,bug,tracker,软件工程,课程实践″"><meta name="”Description”" content="”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”"><meta name="theme-color" content="#000000"><link rel="manifest" href="/react/build//manifest.json"><link rel="stylesheet" href="/react/build/css/iconfont.css"><link rel="stylesheet" href="/react/build/css/edu-purge.css"><link rel="stylesheet" href="/react/build/css/editormd.min.css"><link rel="stylesheet" href="/react/build/css/merge.css"><link href="/react/build/static/css/main.bdb06a8e.chunk.css" rel="stylesheet"></head><body><div id="md_div" style="display:none"></div><div id="root" class="page -layout-v -fit widthunit"></div><div id="picture_display" style="display:none"></div><script src="/react/build/js/jquery-1.8.3.min.js"></script><script src="/react/build/js/js_min_all.js"></script><script src="/react/build/js/codemirror/codemirror.js"></script><script src="/react/build/js/editormd/editormd.min.js"></script><script src="/react/build/js/codemirror/merge/merge.js"></script><script src="/react/build/./static/js/runtime~main.cbbbfc02.js"></script><script src="/react/build/./static/js/main.eae036cf.chunk.js"></script></body></html>

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