forked from Gitlink/forgeplus
Merge branch 'dev_nanda' of https://gitlink.org.cn/Gitlink/forgeplus
# Conflicts: # app/controllers/application_controller.rb # app/controllers/pull_requests_controller.rb # app/controllers/users_controller.rb # app/models/ci/user.rb # app/models/gitea/pull.rb # app/models/gitea/webhook.rb # app/models/gitea/webhook_task.rb # app/models/organization.rb # app/models/project.rb # app/models/project_category.rb # app/models/user.rb # app/services/projects/create_service.rb
This commit is contained in:
commit
fc4db3bb9a
|
@ -73,7 +73,7 @@ vendor/bundle/
|
|||
/public/admin
|
||||
/mysql_data
|
||||
/public/repo/
|
||||
|
||||
/coverage
|
||||
|
||||
.generators
|
||||
.rakeTasks
|
||||
|
@ -81,7 +81,7 @@ db/bak/
|
|||
docker/
|
||||
educoder.sql
|
||||
redis_data/
|
||||
Dockerfile
|
||||
dump.rdb
|
||||
.tags*
|
||||
ceshi_user.xlsx
|
||||
ceshi_user.xlsx
|
||||
public/trace_task_results
|
|
@ -0,0 +1,33 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt update
|
||||
|
||||
RUN apt install -y openssl libssl-dev imagemagick git ruby-dev nodejs libmariadb-dev libmysqlclient-dev shared-mime-info libpq-dev libxml2-dev libxslt-dev
|
||||
RUN DEBIAN_FRONTEND="noninteractive" apt -y install tzdata
|
||||
RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
WORKDIR /home/app/gitlink
|
||||
|
||||
ADD ./ /home/app/gitlink
|
||||
|
||||
RUN gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
|
||||
|
||||
RUN gem update --system
|
||||
|
||||
RUN gem install bundler
|
||||
RUN gem install rake
|
||||
|
||||
RUN rm -rf Gemfile.lock
|
||||
|
||||
#RUN cp config/configuration.yml.example config/configuration.yml
|
||||
#RUN cp config/database.yml.example config/database.yml
|
||||
#RUN touch config/redis.yml
|
||||
#RUN touch config/elasticsearch.yml
|
||||
|
||||
RUN bundle install
|
||||
|
||||
EXPOSE 4000
|
||||
RUN rails s -p 4000 -b '0.0.0.0'
|
||||
|
||||
|
||||
|
278
Gemfile
278
Gemfile
|
@ -1,130 +1,148 @@
|
|||
source 'https://gems.ruby-china.com'
|
||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
|
||||
gem 'rails', '~> 5.2.0'
|
||||
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
|
||||
gem 'puma', '~> 3.11'
|
||||
gem 'sass-rails', '~> 5.0'
|
||||
gem 'uglifier', '>= 1.3.0'
|
||||
|
||||
# gem 'coffee-rails', '~> 4.2'
|
||||
gem 'turbolinks', '~> 5'
|
||||
gem 'jbuilder', '~> 2.5'
|
||||
gem 'groupdate', '~> 4.1.0'
|
||||
gem 'chartkick'
|
||||
gem 'grape-entity', '~> 0.7.1'
|
||||
gem 'kaminari', '~> 1.1', '>= 1.1.1'
|
||||
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
|
||||
gem 'chinese_pinyin'
|
||||
|
||||
gem 'rack-cors'
|
||||
gem 'redis-rails'
|
||||
gem 'roo-xls'
|
||||
gem 'simple_xlsx_reader'
|
||||
|
||||
gem 'rubyzip'
|
||||
|
||||
gem 'spreadsheet'
|
||||
gem 'ruby-ole'
|
||||
# 导出为xlsx
|
||||
gem 'axlsx', '~> 3.0.0.pre'
|
||||
gem 'axlsx_rails', '~> 0.5.2'
|
||||
|
||||
gem 'oauth2'
|
||||
#导出为pdf
|
||||
gem 'pdfkit'
|
||||
gem 'wkhtmltopdf-binary'
|
||||
# gem 'request_store'
|
||||
#gem 'iconv'
|
||||
# markdown 转html
|
||||
gem 'redcarpet', '~> 3.4'
|
||||
|
||||
gem 'rqrcode', '~> 0.10.1'
|
||||
gem 'rqrcode_png'
|
||||
|
||||
gem 'acts-as-taggable-on', '~> 6.0'
|
||||
|
||||
# a tree structure
|
||||
gem 'ancestry'
|
||||
gem 'acts_as_list'
|
||||
gem 'omniauth-cas'
|
||||
|
||||
# profiler Middleware
|
||||
gem 'rack-mini-profiler'
|
||||
|
||||
# object-based searching
|
||||
gem 'ransack'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '~> 3.8'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'prettier'
|
||||
gem 'rubocop', '~> 0.52.0'
|
||||
gem 'solargraph', '~> 0.38.0'
|
||||
gem 'awesome_print'
|
||||
gem 'web-console', '>= 3.3.0'
|
||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||
gem 'spring'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
gem "annotate", "~> 2.6.0"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '>= 2.15', '< 4.0'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'chromedriver-helper'
|
||||
end
|
||||
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
||||
|
||||
#编码检测
|
||||
gem 'rchardet', '~> 1.8'
|
||||
|
||||
# http client
|
||||
gem 'faraday', '~> 0.15.4'
|
||||
|
||||
# view
|
||||
gem 'active_decorator'
|
||||
gem 'bootstrap', '~> 4.3.1'
|
||||
gem 'jquery-rails'
|
||||
gem 'simple_form'
|
||||
gem 'font-awesome-sass', '4.7.0'
|
||||
|
||||
# i18n
|
||||
gem 'rails-i18n', '~> 5.1'
|
||||
|
||||
# job
|
||||
gem 'sidekiq'
|
||||
gem 'sinatra'
|
||||
gem "sidekiq-cron", "~> 1.1"
|
||||
|
||||
# batch insert
|
||||
gem 'bulk_insert'
|
||||
|
||||
# elasticsearch
|
||||
gem 'searchkick'
|
||||
|
||||
gem 'aasm'
|
||||
gem 'enumerize'
|
||||
|
||||
gem 'diffy'
|
||||
|
||||
gem 'deep_cloneable', '~> 3.0.0'
|
||||
|
||||
# oauth2
|
||||
gem 'omniauth', '~> 1.9.0'
|
||||
gem 'omniauth-oauth2', '~> 1.6.0'
|
||||
|
||||
# global var
|
||||
gem 'request_store'
|
||||
|
||||
# 敏感词汇
|
||||
gem 'harmonious_dictionary', '~> 0.0.1'
|
||||
|
||||
gem 'parallel', '~> 1.19', '>= 1.19.1'
|
||||
|
||||
gem 'letter_avatar'
|
||||
source 'https://gems.ruby-china.com'
|
||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
|
||||
gem 'rails', '~> 5.2.0'
|
||||
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
|
||||
gem 'puma', '~> 3.11'
|
||||
gem 'sass-rails', '~> 5.0'
|
||||
gem 'uglifier', '>= 1.3.0'
|
||||
|
||||
# gem 'coffee-rails', '~> 4.2'
|
||||
gem 'turbolinks', '~> 5'
|
||||
gem 'jbuilder', '~> 2.5'
|
||||
gem 'groupdate', '~> 4.1.0'
|
||||
gem 'chartkick'
|
||||
gem 'grape-entity', '~> 0.7.1'
|
||||
gem 'kaminari', '~> 1.1', '>= 1.1.1'
|
||||
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
|
||||
gem 'chinese_pinyin'
|
||||
|
||||
gem 'rack-cors'
|
||||
gem 'redis-rails'
|
||||
gem 'roo-xls'
|
||||
gem 'simple_xlsx_reader'
|
||||
|
||||
gem 'rubyzip'
|
||||
|
||||
gem 'spreadsheet'
|
||||
gem 'ruby-ole'
|
||||
# 导出为xlsx
|
||||
gem 'axlsx', '~> 3.0.0.pre'
|
||||
gem 'axlsx_rails', '~> 0.5.2'
|
||||
|
||||
gem 'oauth2'
|
||||
#导出为pdf
|
||||
gem 'pdfkit'
|
||||
gem 'wkhtmltopdf-binary'
|
||||
# gem 'request_store'
|
||||
#gem 'iconv'
|
||||
# markdown 转html
|
||||
gem 'redcarpet', '~> 3.4'
|
||||
|
||||
gem 'rqrcode', '~> 0.10.1'
|
||||
gem 'rqrcode_png'
|
||||
|
||||
gem 'acts-as-taggable-on', '~> 6.0'
|
||||
|
||||
# a tree structure
|
||||
gem 'ancestry'
|
||||
gem 'acts_as_list'
|
||||
gem 'omniauth-cas'
|
||||
|
||||
# profiler Middleware
|
||||
gem 'rack-mini-profiler'
|
||||
|
||||
# object-based searching
|
||||
gem 'ransack'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '~> 3.8'
|
||||
gem 'rails-controller-testing'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'prettier'
|
||||
gem 'rubocop', '~> 0.52.0'
|
||||
gem 'solargraph', '~> 0.38.0'
|
||||
gem 'awesome_print'
|
||||
gem 'web-console', '>= 3.3.0'
|
||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||
gem 'spring'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
gem "annotate", "~> 2.6.0"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '>= 2.15', '< 4.0'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'chromedriver-helper'
|
||||
gem 'simplecov', '~>0.12.0', require: false
|
||||
end
|
||||
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
||||
|
||||
#编码检测
|
||||
gem 'rchardet', '~> 1.8'
|
||||
|
||||
# http client
|
||||
gem 'faraday', '~> 0.15.4'
|
||||
|
||||
# view
|
||||
gem 'active_decorator'
|
||||
gem 'bootstrap', '~> 4.3.1'
|
||||
gem 'jquery-rails'
|
||||
gem 'simple_form'
|
||||
gem 'font-awesome-sass', '4.7.0'
|
||||
|
||||
# i18n
|
||||
gem 'rails-i18n', '~> 5.1'
|
||||
|
||||
# job
|
||||
gem 'sidekiq',"5.2.8"
|
||||
gem 'sinatra'
|
||||
gem "sidekiq-cron", "1.2.0"
|
||||
gem 'whenever'
|
||||
|
||||
# batch insert
|
||||
gem 'bulk_insert'
|
||||
|
||||
# elasticsearch
|
||||
gem 'searchkick'
|
||||
|
||||
gem 'aasm'
|
||||
gem 'enumerize'
|
||||
|
||||
gem 'diffy'
|
||||
|
||||
gem 'deep_cloneable', '~> 3.0.0'
|
||||
|
||||
# oauth2
|
||||
gem 'omniauth', '~> 1.9.0'
|
||||
gem 'omniauth-oauth2', '~> 1.6.0'
|
||||
gem "omniauth-github"
|
||||
gem "omniauth-rails_csrf_protection"
|
||||
gem 'omniauth-gitee', '~> 1.0.0'
|
||||
gem "omniauth-wechat-oauth2"
|
||||
|
||||
# global var
|
||||
gem 'request_store'
|
||||
|
||||
# 敏感词汇
|
||||
gem 'harmonious_dictionary', '~> 0.0.1'
|
||||
|
||||
gem 'parallel', '~> 1.19', '>= 1.19.1'
|
||||
|
||||
# log
|
||||
gem 'multi_logger'
|
||||
|
||||
gem 'letter_avatar'
|
||||
|
||||
gem 'jwt'
|
||||
|
||||
gem 'doorkeeper'
|
||||
|
||||
gem 'doorkeeper-jwt'
|
||||
|
||||
gem 'gitea-client', '~> 0.11.1'
|
31
Gemfile.lock
31
Gemfile.lock
|
@ -106,6 +106,12 @@ GEM
|
|||
activerecord (>= 3.1.0, < 7)
|
||||
diff-lcs (1.3)
|
||||
diffy (3.3.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
doorkeeper (5.5.1)
|
||||
railties (>= 5)
|
||||
doorkeeper-jwt (0.4.1)
|
||||
jwt (>= 2.1)
|
||||
e2mmap (0.1.0)
|
||||
elasticsearch (7.5.0)
|
||||
elasticsearch-api (= 7.5.0)
|
||||
|
@ -129,6 +135,8 @@ GEM
|
|||
fugit (1.4.1)
|
||||
et-orbi (~> 1.1, >= 1.1.8)
|
||||
raabro (~> 1.4)
|
||||
gitea-client (0.10.5)
|
||||
rest-client (~> 2.1.0)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
grape-entity (0.7.1)
|
||||
|
@ -139,6 +147,9 @@ GEM
|
|||
harmonious_dictionary (0.0.1)
|
||||
hashie (3.6.0)
|
||||
htmlentities (4.3.4)
|
||||
http-accept (1.7.0)
|
||||
http-cookie (1.0.5)
|
||||
domain_name (~> 0.5)
|
||||
i18n (1.8.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-like (0.3.1)
|
||||
|
@ -176,6 +187,9 @@ GEM
|
|||
mimemagic (~> 0.3.2)
|
||||
maruku (0.7.3)
|
||||
method_source (0.9.2)
|
||||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2022.0105)
|
||||
mimemagic (0.3.10)
|
||||
nokogiri (~> 1)
|
||||
rake
|
||||
|
@ -189,6 +203,7 @@ GEM
|
|||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mysql2 (0.5.3)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.2)
|
||||
nokogiri (1.10.8)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
|
@ -288,6 +303,11 @@ GEM
|
|||
regexp_parser (1.7.0)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
reverse_markdown (1.4.0)
|
||||
nokogiri
|
||||
roo (2.8.3)
|
||||
|
@ -414,6 +434,9 @@ GEM
|
|||
thread_safe (~> 0.1)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (1.6.1)
|
||||
web-console (3.7.0)
|
||||
actionview (>= 5.0)
|
||||
|
@ -450,14 +473,18 @@ DEPENDENCIES
|
|||
chromedriver-helper
|
||||
deep_cloneable (~> 3.0.0)
|
||||
diffy
|
||||
doorkeeper
|
||||
doorkeeper-jwt
|
||||
enumerize
|
||||
faraday (~> 0.15.4)
|
||||
font-awesome-sass (= 4.7.0)
|
||||
gitea-client (~> 0.10.2)
|
||||
grape-entity (~> 0.7.1)
|
||||
groupdate (~> 4.1.0)
|
||||
harmonious_dictionary (~> 0.0.1)
|
||||
jbuilder (~> 2.5)
|
||||
jquery-rails
|
||||
jwt
|
||||
kaminari (~> 1.1, >= 1.1.1)
|
||||
letter_avatar
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
|
@ -489,8 +516,8 @@ DEPENDENCIES
|
|||
sass-rails (~> 5.0)
|
||||
searchkick
|
||||
selenium-webdriver
|
||||
sidekiq
|
||||
sidekiq-cron (~> 1.1)
|
||||
sidekiq (= 5.2.8)
|
||||
sidekiq-cron (= 1.2.0)
|
||||
simple_form
|
||||
simple_xlsx_reader
|
||||
sinatra
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -121,4 +121,4 @@ You may obtain a copy of Mulan PSL v2 at:
|
|||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
|
92
README.md
92
README.md
|
@ -9,7 +9,7 @@ GitLink(确实开源)是中国计算机学会(CCF)官方指定的开源
|
|||
|
||||
- **分布式协作开发**:基于Git打造分布式代码托管环境,提供免费公、私有代码仓库,支持在线文件编辑、代码分支管理、协作贡献统计、代码仓库复刻(Fork)、贡献合并请求(PR)、群智贡献审阅等功能,让您的项目在这里健康、快速的成长!
|
||||
|
||||
- **一站式过程管理**:提供易修(Issue)、里程碑、通知提醒、标签归档等多样化任务管理工具,支持各类开发任务的发布、指派与跟踪,同时提供在线Wiki文档、组织多粒度管理等功能,为您搭建一站式的项目过程管理环境,让您的团队协作更高效、过程更透明!
|
||||
- **一站式过程管理**:提供疑修(Issue)、里程碑、通知提醒、标签归档等多样化任务管理工具,支持各类开发任务的发布、指派与跟踪,同时提供在线Wiki文档、组织多粒度管理等功能,为您搭建一站式的项目过程管理环境,让您的团队协作更高效、过程更透明!
|
||||
|
||||
- **高效流水线运维**:融合DevOps思想,提供轻量级的工作流引擎(Engine),打通编码、测试、构建、部署等开发运维环节;支持自定义配置、代码静态扫描、构建自动触发、容器镜像托管等功能,同时支持接入第三方运维工具,让您的代码更加快速、可靠地形成高质量的产品!
|
||||
|
||||
|
@ -34,18 +34,52 @@ GitLink(确实开源)是中国计算机学会(CCF)官方指定的开源
|
|||
* imagemagick
|
||||
|
||||
### 步骤
|
||||
|
||||
(1)克隆稳定版本
|
||||
(1)安装 Rails 必要的一些三方库:
|
||||
- Mac OS X
|
||||
```bash
|
||||
brew install imagemagick ghostscript libxml2 libxslt libiconv
|
||||
```
|
||||
|
||||
- Ubuntu
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y openssl libssl-dev imagemagick git ruby-dev nodejs libmariadb-dev libmysqlclient-dev shared-mime-info libpq-dev libxml2-dev libxslt-dev
|
||||
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y tzdata
|
||||
sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
```
|
||||
|
||||
(2)安装 Ruby, Rails 运行环境:[如何快速正确的安装 Ruby, Rails 运行环境](https://ruby-china.org/wiki/install_ruby_guide)
|
||||
```bash
|
||||
#检验环境是否正确
|
||||
ruby -v
|
||||
#ruby 2.4.x ...
|
||||
|
||||
gem -v
|
||||
#3.x.x
|
||||
|
||||
bundle -v
|
||||
#Bundler version 2.x.x
|
||||
|
||||
rails -v
|
||||
#Rails 5.2.x
|
||||
```
|
||||
|
||||
(3)克隆稳定版本
|
||||
```bash
|
||||
git clone -b master https://gitlink.org.cn/Gitlink/forgeplus.git
|
||||
```
|
||||
|
||||
(2)安装依赖包
|
||||
(4)安装依赖包
|
||||
```bash
|
||||
cd forgeplus && bundle install
|
||||
#进入目录
|
||||
cd forgeplus
|
||||
#删除Gemfile.lock
|
||||
rm -rf Gemfile.lock
|
||||
#安装依赖包
|
||||
bundle install
|
||||
```
|
||||
|
||||
(3)配置初始化文件:进入项目根目录执行以下命令
|
||||
(5)配置初始化文件:进入项目根目录执行以下命令
|
||||
```bash
|
||||
cp config/configuration.yml.example config/configuration.yml
|
||||
cp config/database.yml.example config/database.yml
|
||||
|
@ -53,8 +87,8 @@ touch config/redis.yml
|
|||
touch config/elasticsearch.yml
|
||||
```
|
||||
|
||||
(4)配置数据库:数据库配置信息请查看/config/database.yml文件,项目默认采用mysql数据库, 如需更改,请自行修改配置信息,默认配置如下
|
||||
```bash
|
||||
(6)配置数据库:数据库配置信息请查看/config/database.yml文件,项目默认采用mysql数据库, 如需更改,请自行修改配置信息,默认配置如下
|
||||
```yaml
|
||||
default: &default
|
||||
adapter: mysql2
|
||||
host: 127.0.0.1
|
||||
|
@ -63,7 +97,7 @@ default: &default
|
|||
password: 123456
|
||||
```
|
||||
|
||||
(5)配置gitea服务(可选):如需要部署自己的gitea平台,请参考[gitea官方平台文档](https://docs.gitea.io/zh-cn/install-from-binary/)。因目前gitea平台api受限,暂时推荐从forge平台获取[gitea部署文件](https://www.gitlink.org.cn/Gitlink/gitea-binary)进行部署
|
||||
(7)配置gitea服务(可选):如需要部署自己的gitea平台,请参考[gitea官方平台文档](https://docs.gitea.io/zh-cn/install-from-binary/)。因目前gitea平台api受限,暂时推荐从forge平台获取[gitea部署文件](https://www.gitlink.org.cn/Gitlink/gitea-binary)进行部署
|
||||
|
||||
- 配置gitea服务步骤:
|
||||
|
||||
|
@ -71,7 +105,7 @@ default: &default
|
|||
|
||||
-- 修改forge平台的 config/configuration.yml中的gitea服务指向地址,如:
|
||||
|
||||
```ruby
|
||||
```yaml
|
||||
gitea:
|
||||
access_key_id: 'root'
|
||||
access_key_secret: 'password'
|
||||
|
@ -79,61 +113,59 @@ gitea:
|
|||
base_url: '/api/v1'
|
||||
```
|
||||
|
||||
(6)安装redis环境:请自行搜索各平台如何安装部署redis环境
|
||||
(8)配置/config/database.yml文件(安装redis环境:请自行搜索各平台如何安装部署redis环境)
|
||||
```yaml
|
||||
default: &default
|
||||
url: redis://localhost:6379
|
||||
db: 1
|
||||
|
||||
(7)安装imagemagick插件:
|
||||
- Mac OS X
|
||||
```bash
|
||||
brew install imagemagick ghostscript
|
||||
production:
|
||||
<<: *default
|
||||
url: redis://localhost:6379
|
||||
```
|
||||
|
||||
- Linux
|
||||
```bash
|
||||
sudo apt-get install -y imagemagick
|
||||
```
|
||||
|
||||
(8)创建数据库:开发环境为development, 生成环境为production
|
||||
(9)创建数据库:开发环境为development, 生成环境为production
|
||||
```bash
|
||||
rails db:create RAILS_ENV=development
|
||||
```
|
||||
|
||||
(9)导入数据表结构
|
||||
(10)导入数据表结构
|
||||
|
||||
```bash
|
||||
bundle exec rake sync_table_structure:import_csv
|
||||
```
|
||||
|
||||
(10)执行migrate迁移文件:开发环境为development, 生成环境为production
|
||||
(11)执行migrate迁移文件:开发环境为development, 生成环境为production
|
||||
```bash
|
||||
rails db:migrate RAILS_ENV=development
|
||||
```
|
||||
|
||||
(11)clone前端代码:将前端代码克隆到public/react目录下,目录结构应该是: public/react/build
|
||||
(12)clone前端代码:将前端代码克隆到public/react目录下,目录结构应该是: public/react/build
|
||||
```bash
|
||||
git clone -b standalone https://gitlink.org.cn/Gitlink/build.git
|
||||
git clone -b master https://gitlink.org.cn/Gitlink/build.git
|
||||
```
|
||||
|
||||
(12)启动redis(此处以macOS系统为例)
|
||||
(13)启动redis(此处以macOS系统为例)
|
||||
```bash
|
||||
redis-server&
|
||||
```
|
||||
|
||||
(13)启动sidekiq:开发环境为development, 生成环境为production
|
||||
(14)启动sidekiq:开发环境为development, 生成环境为production
|
||||
```bash
|
||||
bundle exec sidekiq -C config/sidekiq.yml -e production -d
|
||||
```
|
||||
|
||||
(14)启动rails服务
|
||||
(15)启动rails服务
|
||||
```bash
|
||||
rails s
|
||||
```
|
||||
|
||||
(15)浏览器访问:在浏览器中输入如下地址访问
|
||||
(16)浏览器访问:在浏览器中输入如下地址访问
|
||||
```bash
|
||||
http://localhost:3000/
|
||||
```
|
||||
|
||||
(16)其他说明:通过页面注册以第一个用户为平台管理员用户
|
||||
(17)其他说明:通过页面注册以第一个用户为平台管理员用户
|
||||
|
||||
|
||||
## 页面展示
|
||||
|
|
|
@ -1,136 +1,137 @@
|
|||
//= require rails-ujs
|
||||
//= require activestorage
|
||||
//= require turbolinks
|
||||
//= require jquery3
|
||||
//= require popper
|
||||
//= require bootstrap-sprockets
|
||||
//= require jquery.validate.min
|
||||
//= require additional-methods.min
|
||||
//= require bootstrap-notify
|
||||
//= require jquery.cookie.min
|
||||
//= require select2
|
||||
//= require moment.min
|
||||
//= require jquery.cxselect
|
||||
//= require bootstrap-datepicker
|
||||
//= require bootstrap-datetimepicker
|
||||
//= require bootstrap.viewer
|
||||
//= require jquery.mloading
|
||||
//= require jquery-confirm.min
|
||||
//= require common
|
||||
|
||||
//= require echarts
|
||||
//= require codemirror/lib/codemirror
|
||||
//= require codemirror/mode/shell/shell
|
||||
//= require editormd/editormd
|
||||
//= require editormd/languages/zh-tw
|
||||
//= require dragula/dragula
|
||||
|
||||
//= require_tree ./i18n
|
||||
//= require_tree ./admins
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
||||
}
|
||||
});
|
||||
|
||||
// ******** select2 global config ********
|
||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||
|
||||
Turbolinks.setProgressBarDelay(200);
|
||||
|
||||
$.notifyDefaults({
|
||||
type: 'success',
|
||||
z_index: 9999,
|
||||
delay: 2000
|
||||
});
|
||||
|
||||
function show_success_flash(){
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
||||
// 图片查看大图
|
||||
$('img.preview-image').bootstrapViewer();
|
||||
|
||||
// flash alert提示框自动关闭
|
||||
if($('.admin-alert-container .alert').length > 0){
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
||||
}, 2000);
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert.alert-danger').alert('close');
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("turbolinks:before-cache", function () {
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
});
|
||||
// var progressBar = new Turbolinks.ProgressBar();
|
||||
|
||||
// $(document).on('ajax:send', function(event){
|
||||
// console.log('ajax send', event);
|
||||
// progressBar.setValue(0)
|
||||
// progressBar.show()
|
||||
// });
|
||||
//
|
||||
// $(document).on('ajax:complete', function(event){
|
||||
// console.log('ajax complete', event);
|
||||
// progressBar.setValue(1)
|
||||
// progressBar.hide() // 分页时不触发,奇怪
|
||||
// });
|
||||
// $(document).on('ajax:success', function(event){
|
||||
// console.log('ajax success', event);
|
||||
// });
|
||||
// $(document).on('ajax:error', function(event){
|
||||
// console.log('ajax error', event);
|
||||
// });
|
||||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
//= require rails-ujs
|
||||
//= require activestorage
|
||||
//= require turbolinks
|
||||
//= require jquery3
|
||||
//= require popper
|
||||
//= require bootstrap-sprockets
|
||||
//= require jquery.validate.min
|
||||
//= require additional-methods.min
|
||||
//= require bootstrap-notify
|
||||
//= require jquery.cookie.min
|
||||
//= require select2
|
||||
//= require moment.min
|
||||
//= require jquery.cxselect
|
||||
//= require bootstrap-datepicker
|
||||
//= require bootstrap-datetimepicker
|
||||
//= require bootstrap.viewer
|
||||
//= require bootstrap/bootstrap-toggle
|
||||
//= require jquery.mloading
|
||||
//= require jquery-confirm.min
|
||||
//= require common
|
||||
|
||||
//= require echarts
|
||||
//= require codemirror/lib/codemirror
|
||||
//= require codemirror/mode/shell/shell
|
||||
//= require editormd/editormd
|
||||
//= require editormd/languages/zh-tw
|
||||
//= require dragula/dragula
|
||||
|
||||
//= require_tree ./i18n
|
||||
//= require_tree ./admins
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
||||
}
|
||||
});
|
||||
|
||||
// ******** select2 global config ********
|
||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||
|
||||
Turbolinks.setProgressBarDelay(200);
|
||||
|
||||
$.notifyDefaults({
|
||||
type: 'success',
|
||||
z_index: 9999,
|
||||
delay: 2000
|
||||
});
|
||||
|
||||
function show_success_flash(){
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
||||
// 图片查看大图
|
||||
$('img.preview-image').bootstrapViewer();
|
||||
|
||||
// flash alert提示框自动关闭
|
||||
if($('.admin-alert-container .alert').length > 0){
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
||||
}, 2000);
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert.alert-danger').alert('close');
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("turbolinks:before-cache", function () {
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
});
|
||||
// var progressBar = new Turbolinks.ProgressBar();
|
||||
|
||||
// $(document).on('ajax:send', function(event){
|
||||
// console.log('ajax send', event);
|
||||
// progressBar.setValue(0)
|
||||
// progressBar.show()
|
||||
// });
|
||||
//
|
||||
// $(document).on('ajax:complete', function(event){
|
||||
// console.log('ajax complete', event);
|
||||
// progressBar.setValue(1)
|
||||
// progressBar.hide() // 分页时不触发,奇怪
|
||||
// });
|
||||
// $(document).on('ajax:success', function(event){
|
||||
// console.log('ajax success', event);
|
||||
// });
|
||||
// $(document).on('ajax:error', function(event){
|
||||
// console.log('ajax error', event);
|
||||
// });
|
||||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
})
|
|
@ -0,0 +1,180 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// TOGGLE PUBLIC CLASS DEFINITION
|
||||
// ==============================
|
||||
|
||||
var Toggle = function (element, options) {
|
||||
this.$element = $(element)
|
||||
this.options = $.extend({}, this.defaults(), options)
|
||||
this.render()
|
||||
}
|
||||
|
||||
Toggle.VERSION = '2.2.0'
|
||||
|
||||
Toggle.DEFAULTS = {
|
||||
on: 'On',
|
||||
off: 'Off',
|
||||
onstyle: 'primary',
|
||||
offstyle: 'default',
|
||||
size: 'normal',
|
||||
style: '',
|
||||
width: null,
|
||||
height: null
|
||||
}
|
||||
|
||||
Toggle.prototype.defaults = function() {
|
||||
return {
|
||||
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||
}
|
||||
}
|
||||
|
||||
Toggle.prototype.render = function () {
|
||||
this._onstyle = 'btn-' + this.options.onstyle
|
||||
this._offstyle = 'btn-' + this.options.offstyle
|
||||
var size = this.options.size === 'large' ? 'btn-lg'
|
||||
: this.options.size === 'small' ? 'btn-sm'
|
||||
: this.options.size === 'mini' ? 'btn-xs'
|
||||
: ''
|
||||
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||
.addClass(this._onstyle + ' ' + size)
|
||||
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||
.addClass(this._offstyle + ' ' + size + ' active')
|
||||
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||
.addClass(size)
|
||||
var $toggleGroup = $('<div class="toggle-group">')
|
||||
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||
.addClass(size).addClass(this.options.style)
|
||||
|
||||
this.$element.wrap($toggle)
|
||||
$.extend(this, {
|
||||
$toggle: this.$element.parent(),
|
||||
$toggleOn: $toggleOn,
|
||||
$toggleOff: $toggleOff,
|
||||
$toggleGroup: $toggleGroup
|
||||
})
|
||||
this.$toggle.append($toggleGroup)
|
||||
|
||||
var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
|
||||
var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
|
||||
$toggleOn.addClass('toggle-on')
|
||||
$toggleOff.addClass('toggle-off')
|
||||
this.$toggle.css({ width: width, height: height })
|
||||
if (this.options.height) {
|
||||
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||
}
|
||||
this.update(true)
|
||||
this.trigger(true)
|
||||
}
|
||||
|
||||
Toggle.prototype.toggle = function () {
|
||||
if (this.$element.prop('checked')) this.off()
|
||||
else this.on()
|
||||
}
|
||||
|
||||
Toggle.prototype.on = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||
this.$element.prop('checked', true)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.off = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||
this.$element.prop('checked', false)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.enable = function () {
|
||||
this.$toggle.removeAttr('disabled')
|
||||
this.$element.prop('disabled', false)
|
||||
}
|
||||
|
||||
Toggle.prototype.disable = function () {
|
||||
this.$toggle.attr('disabled', 'disabled')
|
||||
this.$element.prop('disabled', true)
|
||||
}
|
||||
|
||||
Toggle.prototype.update = function (silent) {
|
||||
if (this.$element.prop('disabled')) this.disable()
|
||||
else this.enable()
|
||||
if (this.$element.prop('checked')) this.on(silent)
|
||||
else this.off(silent)
|
||||
}
|
||||
|
||||
Toggle.prototype.trigger = function (silent) {
|
||||
this.$element.off('change.bs.toggle')
|
||||
if (!silent) this.$element.change()
|
||||
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||
this.update()
|
||||
}, this))
|
||||
}
|
||||
|
||||
Toggle.prototype.destroy = function() {
|
||||
this.$element.off('change.bs.toggle')
|
||||
this.$toggleGroup.remove()
|
||||
this.$element.removeData('bs.toggle')
|
||||
this.$element.unwrap()
|
||||
}
|
||||
|
||||
// TOGGLE PLUGIN DEFINITION
|
||||
// ========================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.toggle')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||
if (typeof option == 'string' && data[option]) data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.bootstrapToggle
|
||||
|
||||
$.fn.bootstrapToggle = Plugin
|
||||
$.fn.bootstrapToggle.Constructor = Toggle
|
||||
|
||||
// TOGGLE NO CONFLICT
|
||||
// ==================
|
||||
|
||||
$.fn.toggle.noConflict = function () {
|
||||
$.fn.bootstrapToggle = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TOGGLE DATA-API
|
||||
// ===============
|
||||
|
||||
$(function() {
|
||||
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||
})
|
||||
|
||||
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||
var $checkbox = $(this).find('input[type=checkbox]')
|
||||
$checkbox.bootstrapToggle('toggle')
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||
//# sourceMappingURL=bootstrap-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"bootstrap-toggle.min.js","sources":["bootstrap-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","outerHeight","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,SAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,SACV,SAAtBjB,KAAKI,QAAQa,KAAkB,SAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUa,aAAcV,EAAWU,cAAeT,EAAcS,aAAa,EACpHlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUc,cAAeX,EAAWW,cACjFd,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQQ,KAAMrB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUe,IAAI,cAAef,EAAUL,SAAW,MAClDQ,EAAWY,IAAI,cAAeZ,EAAWR,SAAW,OAErDpB,KAAKyC,QAAO,GACZzC,KAAK0C,SAAQ,IAGdrC,EAAOgB,UAAUsB,OAAS,WACrB3C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU+B,GAC/B,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUP,IAAM,SAAU8B,GAChC,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUyB,OAAS,WACzB9C,KAAKgC,QAAQe,WAAW,YACxB/C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU2B,QAAU,WAC1BhD,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUoB,OAAS,SAAUG,GAC/B5C,KAAKO,SAAS0B,KAAK,YAAajC,KAAKgD,UACpChD,KAAK8C,SACN9C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG+B,GACtC5C,KAAKc,IAAI8B,IAGfvC,EAAOgB,UAAUqB,QAAU,SAAUE,GACpC5C,KAAKO,SAASO,IAAI,oBACb8B,GAAQ5C,KAAKO,SAAS0C,SAC3BjD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEqD,MAAM,WAC5ClD,KAAKyC,UACHzC,QAGJK,EAAOgB,UAAU8B,QAAU,WAC1BnD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAasB,SAClBpD,KAAKO,SAAS8C,WAAW,aACzBrD,KAAKO,SAAS+C,SAiBf,IAAIC,GAAM1D,EAAE2D,GAAGC,eAEf5D,GAAE2D,GAAGC,gBAA8B3D,EACnCD,EAAE2D,GAAGC,gBAAgBC,YAAcrD,EAKnCR,EAAE2D,GAAGb,OAAOgB,WAAa,WAExB,MADA9D,GAAE2D,GAAGC,gBAAkBF,EAChBvD,MAMRH,EAAE,WACDA,EAAE,6CAA6C4D,oBAGhD5D,EAAE+D,UAAU/C,GAAG,kBAAmB,2BAA4B,SAASgD,GACtE,GAAIC,GAAYjE,EAAEG,MAAM+D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -0,0 +1,180 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// TOGGLE PUBLIC CLASS DEFINITION
|
||||
// ==============================
|
||||
|
||||
var Toggle = function (element, options) {
|
||||
this.$element = $(element)
|
||||
this.options = $.extend({}, this.defaults(), options)
|
||||
this.render()
|
||||
}
|
||||
|
||||
Toggle.VERSION = '2.2.0'
|
||||
|
||||
Toggle.DEFAULTS = {
|
||||
on: 'On',
|
||||
off: 'Off',
|
||||
onstyle: 'primary',
|
||||
offstyle: 'default',
|
||||
size: 'normal',
|
||||
style: '',
|
||||
width: null,
|
||||
height: null
|
||||
}
|
||||
|
||||
Toggle.prototype.defaults = function() {
|
||||
return {
|
||||
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||
}
|
||||
}
|
||||
|
||||
Toggle.prototype.render = function () {
|
||||
this._onstyle = 'btn-' + this.options.onstyle
|
||||
this._offstyle = 'btn-' + this.options.offstyle
|
||||
var size = this.options.size === 'large' ? 'btn-large'
|
||||
: this.options.size === 'small' ? 'btn-small'
|
||||
: this.options.size === 'mini' ? 'btn-mini'
|
||||
: ''
|
||||
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||
.addClass(this._onstyle + ' ' + size)
|
||||
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||
.addClass(this._offstyle + ' ' + size + ' active')
|
||||
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||
.addClass(size)
|
||||
var $toggleGroup = $('<div class="toggle-group">')
|
||||
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||
.addClass(size).addClass(this.options.style)
|
||||
|
||||
this.$element.wrap($toggle)
|
||||
$.extend(this, {
|
||||
$toggle: this.$element.parent(),
|
||||
$toggleOn: $toggleOn,
|
||||
$toggleOff: $toggleOff,
|
||||
$toggleGroup: $toggleGroup
|
||||
})
|
||||
this.$toggle.append($toggleGroup)
|
||||
|
||||
var width = this.options.width || Math.max($toggleOn.width(), $toggleOff.width())+($toggleHandle.outerWidth()/2)
|
||||
var height = this.options.height || Math.max($toggleOn.height(), $toggleOff.height())
|
||||
$toggleOn.addClass('toggle-on')
|
||||
$toggleOff.addClass('toggle-off')
|
||||
this.$toggle.css({ width: width, height: height })
|
||||
if (this.options.height) {
|
||||
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||
}
|
||||
this.update(true)
|
||||
this.trigger(true)
|
||||
}
|
||||
|
||||
Toggle.prototype.toggle = function () {
|
||||
if (this.$element.prop('checked')) this.off()
|
||||
else this.on()
|
||||
}
|
||||
|
||||
Toggle.prototype.on = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||
this.$element.prop('checked', true)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.off = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||
this.$element.prop('checked', false)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.enable = function () {
|
||||
this.$toggle.removeAttr('disabled')
|
||||
this.$element.prop('disabled', false)
|
||||
}
|
||||
|
||||
Toggle.prototype.disable = function () {
|
||||
this.$toggle.attr('disabled', 'disabled')
|
||||
this.$element.prop('disabled', true)
|
||||
}
|
||||
|
||||
Toggle.prototype.update = function (silent) {
|
||||
if (this.$element.prop('disabled')) this.disable()
|
||||
else this.enable()
|
||||
if (this.$element.prop('checked')) this.on(silent)
|
||||
else this.off(silent)
|
||||
}
|
||||
|
||||
Toggle.prototype.trigger = function (silent) {
|
||||
this.$element.off('change.bs.toggle')
|
||||
if (!silent) this.$element.change()
|
||||
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||
this.update()
|
||||
}, this))
|
||||
}
|
||||
|
||||
Toggle.prototype.destroy = function() {
|
||||
this.$element.off('change.bs.toggle')
|
||||
this.$toggleGroup.remove()
|
||||
this.$element.removeData('bs.toggle')
|
||||
this.$element.unwrap()
|
||||
}
|
||||
|
||||
// TOGGLE PLUGIN DEFINITION
|
||||
// ========================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.toggle')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||
if (typeof option == 'string' && data[option]) data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.bootstrapToggle
|
||||
|
||||
$.fn.bootstrapToggle = Plugin
|
||||
$.fn.bootstrapToggle.Constructor = Toggle
|
||||
|
||||
// TOGGLE NO CONFLICT
|
||||
// ==================
|
||||
|
||||
$.fn.toggle.noConflict = function () {
|
||||
$.fn.bootstrapToggle = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TOGGLE DATA-API
|
||||
// ===============
|
||||
|
||||
$(function() {
|
||||
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||
})
|
||||
|
||||
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||
var $checkbox = $(this).find('input[type=checkbox]')
|
||||
$checkbox.bootstrapToggle('toggle')
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-large":"small"===this.options.size?"btn-small":"mini"===this.options.size?"btn-mini":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.width(),d.width())+e.outerWidth()/2,i=this.options.height||Math.max(c.height(),d.height());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||
//# sourceMappingURL=bootstrap2-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"bootstrap2-toggle.min.js","sources":["bootstrap2-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,YAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,YACV,SAAtBjB,KAAKI,QAAQa,KAAkB,WAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUN,QAASS,EAAWT,SAAUU,EAAcS,aAAa,EAC1GlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUL,SAAUQ,EAAWR,SAC5EK,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQO,KAAMpB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUc,IAAI,cAAed,EAAUL,SAAW,MAClDQ,EAAWW,IAAI,cAAeX,EAAWR,SAAW,OAErDpB,KAAKwC,QAAO,GACZxC,KAAKyC,SAAQ,IAGdpC,EAAOgB,UAAUqB,OAAS,WACrB1C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU8B,GAC/B,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUP,IAAM,SAAU6B,GAChC,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUwB,OAAS,WACzB7C,KAAKgC,QAAQc,WAAW,YACxB9C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU0B,QAAU,WAC1B/C,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUmB,OAAS,SAAUG,GAC/B3C,KAAKO,SAAS0B,KAAK,YAAajC,KAAK+C,UACpC/C,KAAK6C,SACN7C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG8B,GACtC3C,KAAKc,IAAI6B,IAGftC,EAAOgB,UAAUoB,QAAU,SAAUE,GACpC3C,KAAKO,SAASO,IAAI,oBACb6B,GAAQ3C,KAAKO,SAASyC,SAC3BhD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEoD,MAAM,WAC5CjD,KAAKwC,UACHxC,QAGJK,EAAOgB,UAAU6B,QAAU,WAC1BlD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAaqB,SAClBnD,KAAKO,SAAS6C,WAAW,aACzBpD,KAAKO,SAAS8C,SAiBf,IAAIC,GAAMzD,EAAE0D,GAAGC,eAEf3D,GAAE0D,GAAGC,gBAA8B1D,EACnCD,EAAE0D,GAAGC,gBAAgBC,YAAcpD,EAKnCR,EAAE0D,GAAGb,OAAOgB,WAAa,WAExB,MADA7D,GAAE0D,GAAGC,gBAAkBF,EAChBtD,MAMRH,EAAE,WACDA,EAAE,6CAA6C2D,oBAGhD3D,EAAE8D,UAAU9C,GAAG,kBAAmB,2BAA4B,SAAS+C,GACtE,GAAIC,GAAYhE,EAAEG,MAAM8D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -8,6 +8,7 @@
|
|||
@import "jquery.mloading";
|
||||
@import "jquery-confirm.min";
|
||||
@import "bootstrap-datetimepicker.min";
|
||||
@import "bootstrap/bootstrap-toggle.min";
|
||||
|
||||
@import "codemirror/lib/codemirror";
|
||||
@import "editormd/css/editormd.min";
|
||||
|
@ -203,4 +204,14 @@ input.form-control {
|
|||
color: #23272B;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.table th, .table td {
|
||||
padding: 0.75rem 0.1rem;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.table .thead-light th{
|
||||
white-space: nowrap;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
.checkbox label .toggle,
|
||||
.checkbox-inline .toggle {
|
||||
margin-left: -20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toggle input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: left 0.35s;
|
||||
-webkit-transition: left 0.35s;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.toggle.off .toggle-group {
|
||||
left: -100%;
|
||||
}
|
||||
.toggle-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
border-width: 0 1px;
|
||||
}
|
||||
|
||||
.toggle.btn { min-width: 59px; min-height: 34px; }
|
||||
.toggle-on.btn { padding-right: 24px; }
|
||||
.toggle-off.btn { padding-left: 24px; }
|
||||
|
||||
.toggle.btn-lg { min-width: 79px; min-height: 45px; }
|
||||
.toggle-on.btn-lg { padding-right: 31px; }
|
||||
.toggle-off.btn-lg { padding-left: 31px; }
|
||||
.toggle-handle.btn-lg { width: 40px; }
|
||||
|
||||
.toggle.btn-sm { min-width: 50px; min-height: 30px;}
|
||||
.toggle-on.btn-sm { padding-right: 20px; }
|
||||
.toggle-off.btn-sm { padding-left: 20px; }
|
||||
|
||||
.toggle.btn-xs { min-width: 35px; min-height: 22px;}
|
||||
.toggle-on.btn-xs { padding-right: 12px; }
|
||||
.toggle-off.btn-xs { padding-left: 12px; }
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
|
||||
.toggle{position:relative;overflow:hidden}
|
||||
.toggle input[type=checkbox]{display:none}
|
||||
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||
.toggle.off .toggle-group{left:-100%}
|
||||
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||
.toggle.btn{min-width:59px;min-height:34px}
|
||||
.toggle-on.btn{padding-right:24px}
|
||||
.toggle-off.btn{padding-left:24px}
|
||||
.toggle.btn-lg{min-width:79px;min-height:45px}
|
||||
.toggle-on.btn-lg{padding-right:31px}
|
||||
.toggle-off.btn-lg{padding-left:31px}
|
||||
.toggle-handle.btn-lg{width:40px}
|
||||
.toggle.btn-sm{min-width:50px;min-height:30px}
|
||||
.toggle-on.btn-sm{padding-right:20px}
|
||||
.toggle-off.btn-sm{padding-left:20px}
|
||||
.toggle.btn-xs{min-width:35px;min-height:22px}
|
||||
.toggle-on.btn-xs{padding-right:12px}
|
||||
.toggle-off.btn-xs{padding-left:12px}
|
|
@ -0,0 +1,85 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
label.checkbox .toggle,
|
||||
label.checkbox.inline .toggle {
|
||||
margin-left: -20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.toggle {
|
||||
min-width: 40px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toggle input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: left 0.35s;
|
||||
-webkit-transition: left 0.35s;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.toggle.off .toggle-group {
|
||||
left: -100%;
|
||||
}
|
||||
.toggle-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
border-width: 0 1px;
|
||||
}
|
||||
.toggle-handle.btn-mini {
|
||||
top: -1px;
|
||||
}
|
||||
.toggle.btn { min-width: 30px; }
|
||||
.toggle-on.btn { padding-right: 24px; }
|
||||
.toggle-off.btn { padding-left: 24px; }
|
||||
|
||||
.toggle.btn-large { min-width: 40px; }
|
||||
.toggle-on.btn-large { padding-right: 35px; }
|
||||
.toggle-off.btn-large { padding-left: 35px; }
|
||||
|
||||
.toggle.btn-small { min-width: 25px; }
|
||||
.toggle-on.btn-small { padding-right: 20px; }
|
||||
.toggle-off.btn-small { padding-left: 20px; }
|
||||
|
||||
.toggle.btn-mini { min-width: 20px; }
|
||||
.toggle-on.btn-mini { padding-right: 12px; }
|
||||
.toggle-off.btn-mini { padding-left: 12px; }
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
label.checkbox .toggle,label.checkbox.inline .toggle{margin-left:-20px;margin-right:5px}
|
||||
.toggle{min-width:40px;height:20px;position:relative;overflow:hidden}
|
||||
.toggle input[type=checkbox]{display:none}
|
||||
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||
.toggle.off .toggle-group{left:-100%}
|
||||
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||
.toggle-handle.btn-mini{top:-1px}
|
||||
.toggle.btn{min-width:30px}
|
||||
.toggle-on.btn{padding-right:24px}
|
||||
.toggle-off.btn{padding-left:24px}
|
||||
.toggle.btn-large{min-width:40px}
|
||||
.toggle-on.btn-large{padding-right:35px}
|
||||
.toggle-off.btn-large{padding-left:35px}
|
||||
.toggle.btn-small{min-width:25px}
|
||||
.toggle-on.btn-small{padding-right:20px}
|
||||
.toggle-off.btn-small{padding-left:20px}
|
||||
.toggle.btn-mini{min-width:20px}
|
||||
.toggle-on.btn-mini{padding-right:12px}
|
||||
.toggle-off.btn-mini{padding-left:12px}
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the log controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,84 @@
|
|||
body {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
margin: 33px;
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
p, ol, ul, td {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
|
||||
&:visited {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0 5px 7px;
|
||||
}
|
||||
|
||||
div {
|
||||
&.field, &.actions {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#notice {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.field_with_errors {
|
||||
padding: 2px;
|
||||
background-color: red;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#error_explanation {
|
||||
width: 450px;
|
||||
border: 2px solid red;
|
||||
padding: 7px 7px 0;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f0f0f0;
|
||||
|
||||
h2 {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding: 5px 5px 5px 15px;
|
||||
font-size: 12px;
|
||||
margin: -7px -7px 0;
|
||||
background-color: #c00;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul li {
|
||||
font-size: 12px;
|
||||
list-style: square;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the SponsorTiers controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the Sponsorships controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the Wallets controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -1,6 +1,25 @@
|
|||
class AccountsController < ApplicationController
|
||||
before_action :require_login, only: [:login_check, :simple_update]
|
||||
include ApplicationHelper
|
||||
|
||||
#skip_before_action :check_account, :only => [:logout]
|
||||
|
||||
def simple_update
|
||||
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
|
||||
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
|
||||
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
|
||||
Register::RemoteForm.new(simple_update_params).validate!
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
result = auto_update(current_user, simple_update_params)
|
||||
if result[:message].blank?
|
||||
render_ok
|
||||
else
|
||||
render_error(result[:message])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
render json: session
|
||||
end
|
||||
|
@ -92,7 +111,9 @@ class AccountsController < ApplicationController
|
|||
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: @user.mail
|
||||
email: @user.mail,
|
||||
login_name: @user.login,
|
||||
source_id: 0
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
|
@ -120,6 +141,7 @@ class AccountsController < ApplicationController
|
|||
Register::Form.new(register_params).validate!
|
||||
|
||||
user = Users::RegisterService.call(register_params)
|
||||
user.mail = "#{user.login}@example.org" if user.mail.blank?
|
||||
password = register_params[:password].strip
|
||||
|
||||
# gitea用户注册, email, username, password
|
||||
|
@ -131,6 +153,10 @@ class AccountsController < ApplicationController
|
|||
user.gitea_uid = gitea_user[:body]['id']
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
# 绑定授权账号
|
||||
if ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s) && session[:unionid].present?
|
||||
"OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: user, uid: session[:unionid])
|
||||
end
|
||||
successful_authentication(user)
|
||||
render_ok
|
||||
end
|
||||
|
@ -244,6 +270,7 @@ class AccountsController < ApplicationController
|
|||
|
||||
set_autologin_cookie(user)
|
||||
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
|
||||
# user.daily_reward
|
||||
user.update_column(:last_login_on, Time.now)
|
||||
session[:"#{default_yun_session}"] = user.id
|
||||
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
|
||||
|
@ -315,7 +342,12 @@ class AccountsController < ApplicationController
|
|||
Register::CheckColumnsForm.new(check_params).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
def login_check
|
||||
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
||||
|
@ -358,7 +390,7 @@ class AccountsController < ApplicationController
|
|||
params.require(:user).permit(:login, :email, :phone)
|
||||
end
|
||||
|
||||
def login_params
|
||||
def login_params
|
||||
params.require(:account).permit(:login, :password)
|
||||
end
|
||||
|
||||
|
@ -367,13 +399,13 @@ class AccountsController < ApplicationController
|
|||
end
|
||||
|
||||
def register_params
|
||||
params.permit(:login, :namespace, :password, :password_confirmation, :code)
|
||||
params.permit(:login, :namespace, :password, :password_confirmation, :code, :type)
|
||||
end
|
||||
|
||||
def reset_password_params
|
||||
params.permit(:login, :password, :password_confirmation, :code)
|
||||
end
|
||||
|
||||
|
||||
def find_user
|
||||
phone_or_mail = strip(reset_password_params[:login])
|
||||
User.where("phone = :search OR mail = :search", search: phone_or_mail).last
|
||||
|
@ -382,5 +414,8 @@ class AccountsController < ApplicationController
|
|||
def remote_register_params
|
||||
params.permit(:username, :email, :password, :platform)
|
||||
end
|
||||
|
||||
|
||||
def simple_update_params
|
||||
params.permit(:username, :email, :password, :platform)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,33 @@
|
|||
class Admins::DashboardsController < Admins::BaseController
|
||||
def index
|
||||
@active_user_count = User.where(last_login_on: today).count
|
||||
@weekly_active_user_count = User.where(last_login_on: current_week).count
|
||||
@month_active_user_count = User.where(last_login_on: current_month).count
|
||||
# 用户活跃数
|
||||
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
|
||||
weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:user_id).uniq
|
||||
month_user_ids = CommitLog.where(created_at: current_month).pluck(:user_id).uniq
|
||||
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
|
||||
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
|
||||
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
||||
user_ids = User.where(created_on: pre_week).pluck(:id).uniq
|
||||
weekly_keep_user_count = User.where(id: user_ids).where(last_login_on: current_week).count
|
||||
@weekly_keep_rate = format("%.2f", user_ids.size > 0 ? weekly_keep_user_count.to_f / user_ids.size : 0)
|
||||
|
||||
@new_user_count = User.where(created_on: current_month).count
|
||||
# 新用户注册数
|
||||
@day_new_user_count = User.where(created_on: today).count
|
||||
@weekly_new_user_count = User.where(created_on: current_week).count
|
||||
@month_new_user_count = User.where(created_on: current_month).count
|
||||
|
||||
# 活跃项目数
|
||||
day_project_ids = (CommitLog.where(created_at: today).pluck(:project_id).uniq + Issue.where(created_on: today).pluck(:project_id).uniq).uniq
|
||||
weekly_project_ids = (CommitLog.where(created_at: current_week).pluck(:project_id).uniq + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
|
||||
month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq
|
||||
@day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count
|
||||
@weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
|
||||
@month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
|
||||
|
||||
# 新增项目数
|
||||
@day_new_project_count = Project.where(created_on: today).count
|
||||
@weekly_new_project_count = Project.where(created_on: current_week).count
|
||||
@month_new_project_count = Project.where(created_on: current_month).count
|
||||
end
|
||||
|
||||
def month_active_user
|
||||
|
@ -16,7 +39,6 @@ class Admins::DashboardsController < Admins::BaseController
|
|||
{ value: count['professional'].to_i, name: '专业人士' },
|
||||
{ value: count[nil].to_i, name: '未选职业' },
|
||||
]
|
||||
|
||||
render_ok(data: data)
|
||||
end
|
||||
|
||||
|
@ -42,10 +64,14 @@ class Admins::DashboardsController < Admins::BaseController
|
|||
end
|
||||
|
||||
def current_week
|
||||
7.days.ago.beginning_of_day..Time.now.end_of_day
|
||||
7.days.ago.end_of_day..Time.now.end_of_day
|
||||
end
|
||||
|
||||
def current_month
|
||||
30.days.ago.beginning_of_day..Time.now.end_of_day
|
||||
30.days.ago.end_of_day..Time.now.end_of_day
|
||||
end
|
||||
|
||||
def pre_week
|
||||
14.days.ago.end_of_day..7.days.ago.end_of_day
|
||||
end
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
class Admins::FeedbacksController < Admins::BaseController
|
||||
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
||||
|
||||
def index
|
||||
sort_by = Feedback.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
feedbacks = Feedback.order("#{sort_by} #{sort_direction}")
|
||||
@feedbacks = paginate(feedbacks)
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @feedback.destroy
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:success] = "反馈意见删除成功"
|
||||
else
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:danger] = "反馈意见删除失败"
|
||||
end
|
||||
end
|
||||
|
||||
def new_history
|
||||
@feedback_message_history = FeedbackMessageHistory.new
|
||||
end
|
||||
|
||||
def create_history
|
||||
@feedback_message_history = @feedback.feedback_message_histories.new(feedback_message_history_params)
|
||||
@feedback_message_history.user = current_user
|
||||
if @feedback_message_history.save
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:success] = "发送通知成功"
|
||||
else
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:danger] = @feedback_message_history.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def feedback_params
|
||||
params.require(:feedback).permit!
|
||||
end
|
||||
|
||||
def feedback_message_history_params
|
||||
params.require(:feedback_message_history).permit(:title, :content)
|
||||
end
|
||||
|
||||
def get_feedback
|
||||
@feedback = Feedback.find_by_id(params[:id])
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
|
|||
def create
|
||||
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
result = Admins::ImportUserService.call(params[:file].to_io)
|
||||
result = Admins::ImportUserFromExcelService.call(params[:file].to_io)
|
||||
render_ok(result)
|
||||
rescue Admins::ImportUserService::Error => ex
|
||||
render_error(ex)
|
||||
|
|
|
@ -2,8 +2,24 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
before_action :get_template, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
message_templates = MessageTemplate.group(:type).count.keys
|
||||
@message_templates = kaminari_array_paginate(message_templates)
|
||||
message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result
|
||||
@message_templates = kaminari_paginate(message_templates)
|
||||
end
|
||||
|
||||
def new
|
||||
@message_template = MessageTemplate.new
|
||||
end
|
||||
|
||||
def create
|
||||
@message_template = MessageTemplate::CustomTip.new(message_template_params)
|
||||
@message_template.type = "MessageTemplate::CustomTip"
|
||||
if @message_template.save!
|
||||
redirect_to admins_message_templates_path
|
||||
flash[:success] = "创建消息模板成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建消息模板失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -31,7 +47,9 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
|
||||
private
|
||||
def message_template_params
|
||||
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
|
||||
# type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
|
||||
# params.require(type.split("::").join("_").underscore.to_sym).permit!
|
||||
params.require(:message_template).permit!
|
||||
end
|
||||
|
||||
def get_template
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
class Admins::NpsController < Admins::BaseController
|
||||
def index
|
||||
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
||||
@user_nps = UserNp.joins(:user).order(created_at: :desc)
|
||||
keyword = params[:keyword].to_s.strip.presence
|
||||
if keyword
|
||||
sql = 'CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword OR users.login LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword'
|
||||
@user_nps = @user_nps.where(sql, keyword: "%#{keyword}%")
|
||||
end
|
||||
@user_nps = @user_nps.where("action_type != 'close'") if params[:done_score].present?
|
||||
@min_score = @user_nps.where("action_type != 'close'").minimum("score")
|
||||
@max_score = @user_nps.where("action_type != 'close'").maximum("score")
|
||||
@score_total_count = UserNp.where("action_type !='close'").count
|
||||
@user_nps = paginate @user_nps.includes(:user)
|
||||
end
|
||||
|
||||
def switch_change
|
||||
edu_setting = EduSetting.find_by(name: "nps-on-off-switch")
|
||||
if edu_setting.blank?
|
||||
edu_setting = EduSetting.new(name: "nps-on-off-switch")
|
||||
end
|
||||
edu_setting.value = params[:switch].to_s
|
||||
edu_setting.save
|
||||
render_ok
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
||||
before_action :validate_params, only: [:create, :update]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
def index
|
||||
sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
|
@ -31,12 +31,12 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
# }
|
||||
@project_ignore = Ignore.new(ignore_params)
|
||||
|
||||
if @project_ignore.save!
|
||||
if @project_ignore.save
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:success] = "创建成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建失败"
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -58,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
redirect_to admins_project_ignores_path
|
||||
flash[:success] = "更新成功"
|
||||
else
|
||||
render :edit
|
||||
flash[:danger] = "更新失败"
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
params.require(:ignore).permit(:name,:content)
|
||||
end
|
||||
|
||||
def validate_params
|
||||
name = params[:ignore][:name]
|
||||
if name.blank?
|
||||
flash[:danger] = "名称不允许为空"
|
||||
redirect_to admins_project_ignores_path
|
||||
elsif check_ignore_present?(name) && @project_ignore.blank?
|
||||
flash[:danger] = "创建失败:名称已存在"
|
||||
redirect_to admins_project_ignores_path
|
||||
end
|
||||
end
|
||||
# def validate_params
|
||||
# name = params[:ignore][:name]
|
||||
# if name.blank?
|
||||
# flash[:danger] = "名称不允许为空"
|
||||
# redirect_to admins_project_ignores_path
|
||||
# elsif check_ignore_present?(name) && @project_ignore.blank?
|
||||
# flash[:danger] = "创建失败:名称已存在"
|
||||
# redirect_to admins_project_ignores_path
|
||||
# end
|
||||
# end
|
||||
|
||||
def check_ignore_present?(name)
|
||||
return true if name.blank?
|
||||
name_downcase = name.downcase
|
||||
name_upcase = name.upcase
|
||||
name_first_big = name.capitalize
|
||||
Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
||||
end
|
||||
# def check_ignore_present?(name)
|
||||
# return true if name.blank?
|
||||
# name_downcase = name.downcase
|
||||
# name_upcase = name.upcase
|
||||
# name_first_big = name.capitalize
|
||||
# Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
||||
# end
|
||||
|
||||
end
|
||||
|
|
|
@ -27,17 +27,18 @@ class Admins::ProjectLanguagesController < Admins::BaseController
|
|||
flash[:success] = '创建成功'
|
||||
else
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:danger] = '创建失败'
|
||||
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @project_language.update_attribute(:name, @name)
|
||||
@project_language.attributes = {name: @name}
|
||||
if @project_language.save
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:success] = '更新成功'
|
||||
else
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:success] = '更新失败'
|
||||
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Admins::ProjectLicensesController < Admins::BaseController
|
||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
||||
before_action :validate_params, only: [:create, :update]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
def index
|
||||
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
|
@ -30,13 +30,12 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
# position: max_position
|
||||
# }
|
||||
@project_license = License.new(license_params)
|
||||
|
||||
if @project_license.save!
|
||||
if @project_license.save
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:success] = "创建成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建失败"
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -54,12 +53,13 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
# permissions: permissions.to_s,
|
||||
# limitations: limitations.to_s
|
||||
# }
|
||||
if @project_license.update_attributes(license_params)
|
||||
@project_license.attributes = license_params
|
||||
if @project_license.save
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:success] = "更新成功"
|
||||
else
|
||||
render :edit
|
||||
flash[:danger] = "更新失败"
|
||||
render admins_project_licenses_path
|
||||
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,23 +98,23 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
params.require(:license).permit(:name,:content)
|
||||
end
|
||||
|
||||
def validate_params
|
||||
name = params[:license][:name]
|
||||
if name.blank?
|
||||
flash[:danger] = "名称不允许为空"
|
||||
redirect_to admins_project_licenses_path
|
||||
elsif check_license_present?(name) && @project_license.blank?
|
||||
flash[:danger] = "创建失败:名称已存在"
|
||||
redirect_to admins_project_licenses_path
|
||||
end
|
||||
end
|
||||
# def validate_params
|
||||
# name = params[:license][:name]
|
||||
# if name.blank?
|
||||
# flash[:danger] = "名称不允许为空"
|
||||
# redirect_to admins_project_licenses_path
|
||||
# elsif check_license_present?(name) && @project_license.blank?
|
||||
# flash[:danger] = "创建失败:名称已存在"
|
||||
# redirect_to admins_project_licenses_path
|
||||
# end
|
||||
# end
|
||||
|
||||
def check_license_present?(name)
|
||||
return true if name.blank?
|
||||
name_downcase = name.downcase
|
||||
name_upcase = name.upcase
|
||||
name_first_big = name.capitalize
|
||||
License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
||||
end
|
||||
# def check_license_present?(name)
|
||||
# return true if name.blank?
|
||||
# name_downcase = name.downcase
|
||||
# name_upcase = name.upcase
|
||||
# name_first_big = name.capitalize
|
||||
# License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
||||
# end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
def index
|
||||
@banners = paginate(::Topic::Banner)
|
||||
@banners = paginate(::Topic::Banner.where("title like ?", "%#{params[:search]}%")) if params[:search].present?
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -52,6 +53,6 @@ class Admins::Topic::BannersController < Admins::Topic::BaseController
|
|||
end
|
||||
|
||||
def banner_params
|
||||
params.require(:topic_banner).permit(:title, :order_index)
|
||||
params.require(:topic_banner).permit(:title, :order_index, :url)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
class Api::V1::BaseController < ApplicationController
|
||||
|
||||
include Api::ProjectHelper
|
||||
include Api::UserHelper
|
||||
include Api::PullHelper
|
||||
|
||||
# before_action :doorkeeper_authorize!
|
||||
# skip_before_action :user_setup
|
||||
|
||||
protected
|
||||
# def current_user
|
||||
# #client方法对接,需要一直带着用户标识uid
|
||||
# Rails.logger.info doorkeeper_token
|
||||
# if doorkeeper_token && doorkeeper_token.resource_owner_id.blank?
|
||||
# # return User.anonymous if params[:uid].nil?
|
||||
# # tip_exception("2222")
|
||||
# # return render_error('缺少用户标识!') if params[:uid].nil?
|
||||
# User.current = User.find(params[:uid])
|
||||
# else
|
||||
# User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
||||
# end
|
||||
# end
|
||||
|
||||
def limit
|
||||
params.fetch(:limit, 15)
|
||||
end
|
||||
def page
|
||||
params.fetch(:page, 1)
|
||||
end
|
||||
|
||||
# 具有对仓库的管理权限
|
||||
def require_manager_above
|
||||
@project = load_project
|
||||
return render_forbidden if !current_user.admin? && !@project.manager?(current_user)
|
||||
end
|
||||
|
||||
# 具有对仓库的操作权限
|
||||
def require_operate_above
|
||||
@project = load_project
|
||||
return render_forbidden if !current_user.admin? && !@project.operator?(current_user)
|
||||
end
|
||||
|
||||
# 具有仓库的操作权限或者fork仓库的操作权限
|
||||
def require_operate_above_or_fork_project
|
||||
@project = load_project
|
||||
puts !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||
end
|
||||
|
||||
# 具有对仓库的访问权限
|
||||
def require_public_and_member_above
|
||||
@project = load_project
|
||||
return render_forbidden if !@project.is_public && !current_user.admin? && !@project.member?(current_user)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
class Api::V1::Projects::BranchesController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:all]
|
||||
|
||||
def all
|
||||
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
before_action :require_operate_above, only: [:create]
|
||||
|
||||
def create
|
||||
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
private
|
||||
def branch_params
|
||||
params.require(:branch).permit(:new_branch_name, :old_branch_name)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
class Api::V1::Projects::CodeStatsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:index]
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::CodeStats::ListService.call(@project, {ref: params[:ref]}, current_user&.gitea_token)
|
||||
puts @result_object
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class Api::V1::Projects::CommitsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:index, :diff]
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
|
||||
puts @result_object
|
||||
end
|
||||
|
||||
def diff
|
||||
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class Api::V1::Projects::ContentsController < Api::V1::BaseController
|
||||
before_action :require_operate_above_or_fork_project, only: [:batch]
|
||||
|
||||
def batch
|
||||
@batch_content_params = batch_content_params
|
||||
# 处理下author和committer信息,如果没传则默认为当前用户信息
|
||||
@batch_content_params.merge!(author_email: current_user.mail, author_name: current_user.login) if batch_content_params[:author_email].blank? && batch_content_params[:author_name].blank?
|
||||
@batch_content_params.merge!(committer_email: current_user.mail, committer_name: current_user.login) if batch_content_params[:committer_email].blank? && batch_content_params[:committer_name].blank?
|
||||
|
||||
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, @batch_content_params, @project.owner.gitea_token)
|
||||
end
|
||||
|
||||
private
|
||||
def batch_content_params
|
||||
params.require(:content).permit(:author_email, :author_name, :author_timeunix, :branch, :committer_email, :committer_name, :committer_timeunix, :message, :new_branch, files: [ :action_type, :content, :encoding, :file_path])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class Api::V1::Projects::GitController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:trees, :blobs]
|
||||
|
||||
def trees
|
||||
@result_object = Api::V1::Projects::Git::TreesService.call(@project, params[:sha], {recursive: params[:recursive], page: page, limit: limit}, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def blobs
|
||||
@result_object = Api::V1::Projects::Git::BlobsService.call(@project, params[:sha], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class Api::V1::Projects::Pulls::BaseController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above
|
||||
before_action :load_pull_request
|
||||
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
class Api::V1::Projects::Pulls::JournalsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@journals = Api::V1::Projects::Pulls::Journals::ListService.call(@project, @pull_request, params, current_user)
|
||||
@journals = @journals.limit(200)
|
||||
end
|
||||
|
||||
def create
|
||||
@journal = Api::V1::Projects::Pulls::Journals::CreateService.call(@project, @pull_request, create_params, current_user)
|
||||
end
|
||||
|
||||
before_action :find_journal, only: [:update, :destroy]
|
||||
|
||||
def update
|
||||
@journal = Api::V1::Projects::Pulls::Journals::UpdateService.call(@project, @pull_request, @journal, update_params, current_user)
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @journal.destroy
|
||||
render_ok
|
||||
else
|
||||
render_error("删除评论失败!")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def create_params
|
||||
params.permit(:parent_id, :line_code, :note, :commit_id, :path, :type, :review_id, :diff => {})
|
||||
end
|
||||
|
||||
def update_params
|
||||
params.permit(:note, :commit_id, :state)
|
||||
end
|
||||
|
||||
def find_journal
|
||||
@journal = @pull_request.journals.find_by_id(params[:id])
|
||||
return render_not_found unless @journal.present?
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above
|
||||
|
||||
def index
|
||||
@pulls = Api::V1::Projects::Pulls::ListService.call(@project, query_params)
|
||||
@pulls = kaminari_paginate(@pulls)
|
||||
end
|
||||
|
||||
before_action :load_pull_request, only: [:show]
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token)
|
||||
@last_review = @pull_request.reviews.order(created_at: :desc).take
|
||||
end
|
||||
|
||||
private
|
||||
def query_params
|
||||
params.permit(:status, :keyword, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
class Api::V1::Projects::Pulls::ReviewsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@reviews = @pull_request.reviews
|
||||
@reviews = @reviews.where(status: params[:status]) if params[:status].present?
|
||||
# @reviews = kaminari_paginate(@reviews)
|
||||
end
|
||||
|
||||
before_action :require_reviewer, only: [:create]
|
||||
|
||||
def create
|
||||
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
||||
end
|
||||
|
||||
private
|
||||
def require_reviewer
|
||||
return render_forbidden('您没有审查权限,请联系项目管理员') if !current_user.admin? && !@pull_request.reviewers.exists?(current_user.id) && !@project.manager?(current_user)
|
||||
end
|
||||
|
||||
def review_params
|
||||
params.require(:review).permit(:content, :commit_id, :status)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
class Api::V1::Projects::Pulls::VersionsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::Pulls::Versions::ListService.call(@project, @pull_request, {page: page, limit: limit}, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def diff
|
||||
@result_object = Api::V1::Projects::Pulls::Versions::GetDiffService.call(@project, @pull_request, params[:id], {filepath: params[:filepath]}, current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
class Api::V1::Projects::WebhooksController < Api::V1::BaseController
|
||||
before_action :require_manager_above
|
||||
before_action :find_webhook, only: [:show, :update, :destroy, :tests, :hooktasks]
|
||||
|
||||
def index
|
||||
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
|
||||
@webhooks = @project.webhooks
|
||||
@webhooks = @webhooks.where(type: params[:type]) if params[:type].present?
|
||||
@webhooks = kaminari_paginate(@webhooks)
|
||||
end
|
||||
|
||||
def create
|
||||
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
|
||||
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, create_webhook_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::Webhooks::GetService.call(@project, params[:id], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def update
|
||||
@result_object = Api::V1::Projects::Webhooks::UpdateService.call(@project, params[:id], webhook_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@result_object = Api::V1::Projects::Webhooks::DeleteService.call(@project, params[:id], current_user&.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('删除失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def tests
|
||||
@result_object = Api::V1::Projects::Webhooks::TestsService.call(@project, params[:id], current_user&.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('推送失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def hooktasks
|
||||
@hooktasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
|
||||
@hooktasks = kaminari_paginate(@hooktasks)
|
||||
end
|
||||
|
||||
private
|
||||
def create_webhook_params
|
||||
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, :type, events: [])
|
||||
end
|
||||
|
||||
def webhook_params
|
||||
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
|
||||
end
|
||||
|
||||
def find_webhook
|
||||
@webhook = Gitea::Webhook.find_by_id(params[:id])
|
||||
return render_not_found unless @webhook.present?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
class Api::V1::ProjectsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:show, :compare, :blame]
|
||||
|
||||
def index
|
||||
render_ok
|
||||
end
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
|
||||
end
|
||||
|
||||
def compare
|
||||
@result_object = Api::V1::Projects::CompareService.call(@project, params[:from], params[:to], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def blame
|
||||
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
class Api::V1::Users::FeedbacksController < Api::V1::BaseController
|
||||
|
||||
before_action :load_observe_user
|
||||
before_action :check_auth_for_observe_user
|
||||
|
||||
def create
|
||||
@result = Api::V1::Users::Feedbacks::CreateService.call(@observe_user, feedback_params)
|
||||
return render_error("反馈意见创建失败.") if @result.nil?
|
||||
return render_ok
|
||||
end
|
||||
|
||||
private
|
||||
def feedback_params
|
||||
params.permit(:content)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
class Api::V1::Users::ProjectsController < Api::V1::BaseController
|
||||
before_action :load_observe_user
|
||||
|
||||
def index
|
||||
@object_results = Api::V1::Users::Projects::ListService.call(@observe_user, query_params, current_user)
|
||||
@projects = kaminari_paginate(@object_results)
|
||||
end
|
||||
|
||||
private
|
||||
def query_params
|
||||
params.permit(:category, :is_public, :project_type, :sort_by, :sort_direction, :search)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,105 @@
|
|||
class Api::V1::UsersController < Api::V1::BaseController
|
||||
|
||||
before_action :load_observe_user
|
||||
before_action :check_auth_for_observe_user
|
||||
|
||||
def send_email_vefify_code
|
||||
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||
verification_code = code.sample(6).join
|
||||
mail = params[:email]
|
||||
code_type = params[:code_type]
|
||||
|
||||
sign = Digest::MD5.hexdigest("#{OPENKEY}#{mail}")
|
||||
Rails.logger.info sign
|
||||
|
||||
tip_exception(501, "请求不合理") if sign != params[:smscode]
|
||||
|
||||
# 60s内不能重复发送
|
||||
send_email_limit_cache_key = "send_email_60_second_limit:#{mail}"
|
||||
tip_exception(-2, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key)
|
||||
send_email_control = LimitForbidControl::SendEmailCode.new(mail)
|
||||
tip_exception(-2, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
|
||||
begin
|
||||
UserMailer.update_email(mail, verification_code).deliver_now
|
||||
|
||||
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
|
||||
send_email_control.increment!
|
||||
rescue Exception => e
|
||||
logger_error(e)
|
||||
tip_exception(-2,"邮件发送失败,请稍后重试")
|
||||
end
|
||||
ver_params = {code_type: code_type, code: verification_code, email: mail}
|
||||
last_code = VerificationCode.where(code_type: code_type, email: mail).last
|
||||
last_code.update_attributes!({created_at: Time.current - 10.minute}) if last_code.present?
|
||||
data = VerificationCode.new(ver_params)
|
||||
if data.save!
|
||||
render_ok
|
||||
else
|
||||
tip_exception(-1, "创建数据失败")
|
||||
end
|
||||
end
|
||||
|
||||
def check_password
|
||||
password = params[:password]
|
||||
return tip_exception(-5, "8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD
|
||||
return tip_exception(-5, "密码错误") unless @observe_user.check_password?(password)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def check_email
|
||||
mail = strip(params[:email])
|
||||
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
|
||||
|
||||
exist_owner = Owner.find_by(mail: mail)
|
||||
return tip_exception(-2, '邮箱已被使用') if exist_owner
|
||||
render_ok
|
||||
end
|
||||
|
||||
def check_email_verify_code
|
||||
code = strip(params[:code])
|
||||
mail = strip(params[:email])
|
||||
code_type = params[:code_type]
|
||||
|
||||
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
|
||||
|
||||
verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last
|
||||
return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试
|
||||
|
||||
return tip_exception(-6, "验证码不正确") if verifi_code&.code != code
|
||||
return tip_exception(-6, "验证码已失效") if !verifi_code&.effective?
|
||||
render_ok
|
||||
end
|
||||
|
||||
def check_phone_verify_code
|
||||
code = strip(params[:code])
|
||||
phone = strip(params[:phone])
|
||||
code_type = params[:code_type]
|
||||
|
||||
return tip_exception(-2, "手机号格式有误") unless phone =~ CustomRegexp::PHONE
|
||||
|
||||
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: code_type).last
|
||||
return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试
|
||||
|
||||
return tip_exception(-6, "验证码不正确") if verifi_code&.code != code
|
||||
return tip_exception(-6, "验证码已失效") if !verifi_code&.effective?
|
||||
render_ok
|
||||
end
|
||||
|
||||
def update_email
|
||||
@result_object = Api::V1::Users::UpdateEmailService.call(@observe_user, params, current_user.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('更改邮箱失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def update_phone
|
||||
@result_object = Api::V1::Users::UpdatePhoneService.call(@observe_user, params)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('更改手机号失败!')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,21 +10,25 @@ class ApplicationController < ActionController::Base
|
|||
include LoggerHelper
|
||||
include LoginHelper
|
||||
include RegisterHelper
|
||||
include UpdateHelper
|
||||
|
||||
protect_from_forgery prepend: true, unless: -> { request.format.json? }
|
||||
|
||||
before_action :check_sign
|
||||
before_action :user_setup
|
||||
#before_action :check_account
|
||||
after_action :user_trace_log
|
||||
|
||||
# TODO
|
||||
# check sql query time
|
||||
before_action do
|
||||
if request.subdomain === 'testforgeplus' || request.subdomain === "profiler"
|
||||
Rack::MiniProfiler.authorize_request
|
||||
end
|
||||
# if request.subdomain === 'testforgeplus' || request.subdomain === "profiler"
|
||||
# Rack::MiniProfiler.authorize_request
|
||||
# end
|
||||
end
|
||||
|
||||
before_action :update_last_login_on
|
||||
|
||||
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
|
||||
OPENKEY = Rails.application.config_for(:configuration)['sign_key'] || "79e33abd4b6588941ab7622aed1e67e8"
|
||||
|
||||
|
@ -79,11 +83,10 @@ class ApplicationController < ActionController::Base
|
|||
# 判断用户的邮箱或者手机是否可用
|
||||
# params[:type] 1: 注册;2:忘记密码;3:绑定
|
||||
def check_mail_and_phone_valid login, type
|
||||
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ ||
|
||||
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
|
||||
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/
|
||||
tip_exception(-2, "请输入正确的手机号或邮箱")
|
||||
end
|
||||
|
||||
|
||||
user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
|
||||
if user_exist && type.to_i == 1
|
||||
tip_exception(-2, "该手机号码或邮箱已被注册")
|
||||
|
@ -103,8 +106,10 @@ class ApplicationController < ActionController::Base
|
|||
when 1, 2, 4, 9
|
||||
# 手机类型的发送
|
||||
sigle_para = {phone: value}
|
||||
status = Gitlink::Sms.send(mobile: value, code: code)
|
||||
tip_exception(-2, code_msg(status)) if status != 0
|
||||
# status = Gitlink::Sms.send(mobile: value, code: code)
|
||||
# tip_exception(-2, code_msg(status)) if status != 0
|
||||
status = Sms::UcloudService.call(value, code, send_type)
|
||||
tip_exception(-2, ucloud_code_msg(status)) if status != 0
|
||||
when 8, 3, 5
|
||||
# 邮箱类型的发送
|
||||
sigle_para = {email: value}
|
||||
|
@ -116,8 +121,13 @@ class ApplicationController < ActionController::Base
|
|||
send_email_control = LimitForbidControl::SendEmailCode.new(value)
|
||||
tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
|
||||
begin
|
||||
UserMailer.register_email(value, code).deliver_now
|
||||
|
||||
if send_type == 3
|
||||
UserMailer.find_password(value, code).deliver_now
|
||||
elsif send_type == 5
|
||||
UserMailer.bind_email(value, code).deliver_now
|
||||
else
|
||||
UserMailer.register_email(value, code).deliver_now
|
||||
end
|
||||
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
|
||||
send_email_control.increment!
|
||||
# Mailer.run.email_register(code, value)
|
||||
|
@ -149,6 +159,27 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def ucloud_code_msg status
|
||||
case status
|
||||
when 0
|
||||
"验证码已经发送到您的手机,请注意查收"
|
||||
when 171
|
||||
"API签名错误"
|
||||
when 18014
|
||||
"无效手机号码"
|
||||
when 18017
|
||||
"无效模板"
|
||||
when 18018
|
||||
"短信模板参数与短信模板不匹配"
|
||||
when 18023
|
||||
"短信内容中含有运营商拦截的关键词"
|
||||
when 18033
|
||||
"变量内容不符合规范"
|
||||
else
|
||||
"错误码#{status}"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_type(object_type)
|
||||
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
|
||||
end
|
||||
|
@ -170,7 +201,25 @@ class ApplicationController < ActionController::Base
|
|||
# 未授权的捕捉407,弹试用申请弹框
|
||||
def require_login
|
||||
#6.13 -hs
|
||||
tip_exception(401, "请登录后再操作") unless User.current.logged?
|
||||
end
|
||||
|
||||
def require_login_or_token
|
||||
if params[:token].present?
|
||||
user = User.try_to_autologin(params[:token])
|
||||
User.current = user
|
||||
end
|
||||
tip_exception(401, "请登录后再操作") unless User.current.logged?
|
||||
end
|
||||
|
||||
def require_login_cloud_ide_saas
|
||||
if params[:sign].present? && params[:email].present?
|
||||
sign = Digest::MD5.hexdigest("#{OPENKEY}#{params[:email]}")
|
||||
if params[:sign].to_s == sign
|
||||
user = User.find_by(mail: params[:email])
|
||||
User.current = user
|
||||
end
|
||||
end
|
||||
tip_exception(401, "请登录后再操作") unless User.current.logged?
|
||||
end
|
||||
|
||||
|
@ -249,42 +298,58 @@ class ApplicationController < ActionController::Base
|
|||
#return if params[:controller] == "main"
|
||||
# Find the current user
|
||||
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
|
||||
User.current = find_current_user
|
||||
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
|
||||
|
||||
# 开放课程通过链接访问的用户
|
||||
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
|
||||
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
|
||||
|
||||
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
|
||||
user = open_class_user
|
||||
if user
|
||||
start_user_session(user)
|
||||
set_autologin_cookie(user)
|
||||
if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer')
|
||||
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
|
||||
if @doorkeeper_token.present?
|
||||
# client方法对接,需要一直带着用户标识uid
|
||||
if @doorkeeper_token.resource_owner_id.blank?
|
||||
tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
|
||||
User.current = User.find(params[:uid])
|
||||
else
|
||||
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
|
||||
end
|
||||
User.current = user
|
||||
end
|
||||
end
|
||||
# if !User.current.logged? && Rails.env.development?
|
||||
# User.current = User.find 1
|
||||
# end
|
||||
else
|
||||
User.current = find_current_user
|
||||
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
|
||||
|
||||
# 开放课程通过链接访问的用户
|
||||
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
|
||||
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
|
||||
|
||||
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
|
||||
user = open_class_user
|
||||
if user
|
||||
start_user_session(user)
|
||||
set_autologin_cookie(user)
|
||||
end
|
||||
User.current = user
|
||||
end
|
||||
end
|
||||
|
||||
if !User.current.logged? && Rails.env.development?
|
||||
user = User.find 1
|
||||
User.current = user
|
||||
start_user_session(user)
|
||||
end
|
||||
|
||||
|
||||
# 测试版前端需求
|
||||
logger.info("subdomain:#{request.subdomain}")
|
||||
if request.subdomain != "www"
|
||||
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
|
||||
User.current = User.find 81403
|
||||
elsif params[:debug] == 'student'
|
||||
User.current = User.find 8686
|
||||
elsif params[:debug] == 'admin'
|
||||
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
|
||||
user = User.find 35
|
||||
User.current = user
|
||||
cookies.signed[:user_id] = user.id
|
||||
# 测试版前端需求
|
||||
logger.info("subdomain:#{request.subdomain}")
|
||||
if request.subdomain != "www"
|
||||
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
|
||||
User.current = User.find 81403
|
||||
elsif params[:debug] == 'student'
|
||||
User.current = User.find 8686
|
||||
elsif params[:debug] == 'admin'
|
||||
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
|
||||
user = User.find 36480
|
||||
User.current = user
|
||||
cookies.signed[:user_id] = user.id
|
||||
end
|
||||
end
|
||||
end
|
||||
#User.current = User.find 35
|
||||
# User.current = User.find 81403
|
||||
end
|
||||
|
||||
# Returns the current user or nil if no user is logged in
|
||||
|
@ -302,7 +367,19 @@ class ApplicationController < ActionController::Base
|
|||
# RSS key authentication does not start a session
|
||||
User.find_by_rss_key(params[:key])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def user_trace_log
|
||||
user = current_user
|
||||
# print("*********************url:", request.url, "****routes", request.request_method)
|
||||
Rails.logger.user_trace.info("{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params}, response_code: #{response.code}, time: #{Time.now}}")
|
||||
end
|
||||
|
||||
def user_trace_update_log(old_value_hash)
|
||||
user = current_user
|
||||
str = "{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params.merge(old_value: old_value_hash)}, response_code: #{response.code}, time: #{Time.now}}"
|
||||
Rails.logger.user_trace.info(str)
|
||||
end
|
||||
|
||||
def try_to_autologin
|
||||
if cookies[autologin_cookie_name]
|
||||
|
@ -328,12 +405,17 @@ class ApplicationController < ActionController::Base
|
|||
respond_to do |format|
|
||||
format.json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
## 输出错误信息
|
||||
def error_status(message = nil)
|
||||
@status = -1
|
||||
@message = message
|
||||
## 输出错误信息
|
||||
def error_status(message = nil)
|
||||
@status = -1
|
||||
@message = message
|
||||
end
|
||||
|
||||
# 实训等对应的仓库地址
|
||||
def repo_ip_url(repo_path)
|
||||
"#{edu_setting('git_address_ip')}/#{repo_path}"
|
||||
end
|
||||
|
||||
def repo_url(repo_path)
|
||||
|
@ -572,6 +654,23 @@ class ApplicationController < ActionController::Base
|
|||
ss
|
||||
end
|
||||
|
||||
def strip_html(text, len=0, endss="...")
|
||||
ss = ""
|
||||
if !text.nil? && text.length>0
|
||||
ss=text.gsub(/<\/?.*?>/, '').strip
|
||||
ss = ss.gsub(/ */, '')
|
||||
ss = ss.gsub(/\r\n/,'') #新增
|
||||
ss = ss.gsub(/\n/,'') #新增
|
||||
if len > 0 && ss.length > len
|
||||
ss = ss[0, len] + endss
|
||||
elsif len > 0 && ss.length <= len
|
||||
ss = ss
|
||||
#ss = truncate(ss, :length => len)
|
||||
end
|
||||
end
|
||||
ss
|
||||
end
|
||||
|
||||
# Returns a string that can be used as filename value in Content-Disposition header
|
||||
def filename_for_content_disposition(name)
|
||||
request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name
|
||||
|
@ -583,8 +682,8 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
# 获取Oauth Client
|
||||
def get_client(site)
|
||||
client_id = Rails.configuration.Gitlink['client_id']
|
||||
client_secret = Rails.configuration.Gitlink['client_secret']
|
||||
client_id = Rails.configuration.educoder['client_id']
|
||||
client_secret = Rails.configuration.educoder['client_secret']
|
||||
|
||||
OAuth2::Client.new(client_id, client_secret, site: site)
|
||||
end
|
||||
|
@ -604,7 +703,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def kaminari_paginate(relation)
|
||||
limit = params[:limit] || params[:per_page]
|
||||
limit = (limit.to_i.zero? || limit.to_i > 20) ? 20 : limit.to_i
|
||||
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
|
||||
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
|
||||
|
||||
relation.page(page).per(limit)
|
||||
|
@ -681,7 +780,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
@project, @owner = Project.find_with_namespace(namespace, id)
|
||||
|
||||
if @project and current_user.can_read_project?(@project)
|
||||
if @project and (current_user.can_read_project?(@project) || controller_path == "projects/project_invite_links")
|
||||
logger.info "###########: has project and can read project"
|
||||
@project
|
||||
# elsif @project && current_user.is_a?(AnonymousUser)
|
||||
|
@ -689,9 +788,15 @@ class ApplicationController < ActionController::Base
|
|||
# @project = nil if !@project.is_public?
|
||||
# render_forbidden and return
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
if @project.present?
|
||||
logger.info "###########: has project and but can't read project"
|
||||
@project = nil
|
||||
render_forbidden and return
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
end
|
||||
end
|
||||
@project
|
||||
end
|
||||
|
@ -732,21 +837,54 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
private
|
||||
def object_not_found
|
||||
uid_logger("Missing template or cant't find record, responding with 404")
|
||||
render json: {message: "您访问的页面不存在或已被删除", status: 404}
|
||||
false
|
||||
def update_last_login_on
|
||||
if current_user.logged?
|
||||
current_user.update_column(:last_login_on, Time.now)
|
||||
end
|
||||
end
|
||||
|
||||
def object_not_found
|
||||
uid_logger("Missing template or cant't find record, responding with 404")
|
||||
render json: {message: "您访问的页面不存在或已被删除", status: 404}
|
||||
false
|
||||
end
|
||||
|
||||
def tip_show(exception)
|
||||
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
|
||||
render json: exception.tip_json
|
||||
end
|
||||
|
||||
def render_parameter_missing
|
||||
render json: { status: -1, message: '参数缺失' }
|
||||
end
|
||||
|
||||
def set_export_cookies
|
||||
cookies[:fileDownload] = true
|
||||
end
|
||||
|
||||
# 149课程的评审用户数据创建(包含创建课堂学生)
|
||||
def open_class_user
|
||||
user = User.find_by(login: "OpenClassUser")
|
||||
unless user
|
||||
ActiveRecord::Base.transaction do
|
||||
user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程",
|
||||
nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0,
|
||||
password: "12345678", phone: "11122223333", profile_completed: 1}
|
||||
user = User.create!(user_params)
|
||||
|
||||
UserExtension.create!(user_id: user.id, gender: 0, school_id: 3396, :identity => 1, :student_id => "openclassuser") # 3396
|
||||
|
||||
subject = Subject.find_by(id: 149)
|
||||
if subject
|
||||
subject.courses.each do |course|
|
||||
CourseMember.create!(course_id: course.id, role: 3, user_id: user.id) if !course.course_members.exists?(user_id: user.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
user
|
||||
end
|
||||
|
||||
# 记录热门搜索关键字
|
||||
def record_search_keyword
|
||||
keyword = params[:keyword].to_s.strip
|
||||
|
|
|
@ -1,261 +1,258 @@
|
|||
#coding=utf-8
|
||||
#
|
||||
# 文件上传
|
||||
class AttachmentsController < ApplicationController
|
||||
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
||||
before_action :find_file, only: %i[show destroy]
|
||||
before_action :attachment_candown, only: [:show]
|
||||
skip_before_action :check_sign, only: [:show, :create]
|
||||
|
||||
include ApplicationHelper
|
||||
|
||||
def show
|
||||
# 1. 优先跳到cdn
|
||||
# 2. 如果没有cdn,send_file
|
||||
if @file.cloud_url.present?
|
||||
update_downloads(@file)
|
||||
redirect_to @file.cloud_url and return
|
||||
end
|
||||
|
||||
type_attachment = params[:disposition] || "attachment"
|
||||
if type_attachment == "inline"
|
||||
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
||||
elsif type_attachment == "MP4"
|
||||
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
||||
else
|
||||
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
||||
end
|
||||
update_downloads(@file)
|
||||
end
|
||||
|
||||
|
||||
def get_file
|
||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
||||
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
|
||||
if url.starts_with?(base_url)
|
||||
domain = Gitea.gitea_config[:domain]
|
||||
api_url = Gitea.gitea_config[:base_url]
|
||||
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
|
||||
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
|
||||
response = Faraday.get(request_url)
|
||||
filename = url.to_s.split("/").pop()
|
||||
else
|
||||
response = Faraday.get(url)
|
||||
filename = params[:download_url].to_s.split("/").pop()
|
||||
end
|
||||
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
||||
end
|
||||
|
||||
def create
|
||||
# 1. 本地存储
|
||||
# 2. 上传到云
|
||||
begin
|
||||
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
||||
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
||||
raise "未上传文件" unless upload_file
|
||||
|
||||
folder = file_storage_directory
|
||||
raise "存储目录未定义" unless folder.present?
|
||||
|
||||
month_folder = current_month_folder
|
||||
save_path = File.join(folder, month_folder)
|
||||
|
||||
ext = file_ext(upload_file.original_filename)
|
||||
|
||||
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
||||
|
||||
content_type = upload_file.content_type.presence || 'application/octet-stream'
|
||||
|
||||
# remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type)
|
||||
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
||||
|
||||
logger.info "local_path: #{local_path}"
|
||||
logger.info "remote_path: #{remote_path}"
|
||||
|
||||
|
||||
disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
#存数据库
|
||||
#
|
||||
@attachment = Attachment.where(disk_filename: disk_filename,
|
||||
author_id: current_user.id,
|
||||
cloud_url: remote_path).first
|
||||
if @attachment.blank?
|
||||
@attachment = Attachment.new
|
||||
@attachment.filename = upload_file.original_filename
|
||||
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
@attachment.filesize = upload_file.tempfile.size
|
||||
@attachment.content_type = content_type
|
||||
@attachment.digest = digest
|
||||
@attachment.author_id = current_user.id
|
||||
@attachment.disk_directory = month_folder
|
||||
@attachment.cloud_url = remote_path
|
||||
@attachment.save!
|
||||
else
|
||||
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
||||
end
|
||||
|
||||
render_json
|
||||
rescue => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@file_path = absolute_path(local_path(@file))
|
||||
#return normal_status(403, "") unless @file.author == current_user
|
||||
@file.destroy!
|
||||
|
||||
delete_file(@file_path)
|
||||
normal_status("删除成功")
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
# 附件为视频时,点击播放
|
||||
def preview_attachment
|
||||
attachment = Attachment.find_by(id: params[:id])
|
||||
dir_path = "#{Rails.root}/public/preview"
|
||||
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
||||
if params[:status] == "preview"
|
||||
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
||||
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
else
|
||||
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
||||
normal_status(1, "操作成功")
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_file
|
||||
@file =
|
||||
if params[:type] == 'history'
|
||||
AttachmentHistory.find params[:id]
|
||||
else
|
||||
Attachment.find params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file(file_path)
|
||||
File.delete(file_path) if File.exist?(file_path)
|
||||
end
|
||||
|
||||
def current_month_folder
|
||||
date = Time.now
|
||||
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
||||
end
|
||||
|
||||
def file_ext(file_name)
|
||||
ext = ''
|
||||
exts = file_name.split(".")
|
||||
if exts.size > 1
|
||||
ext = ".#{exts.last}"
|
||||
end
|
||||
ext
|
||||
end
|
||||
|
||||
def file_save_to_local(save_path, temp_file, ext)
|
||||
unless Dir.exists?(save_path)
|
||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||
end
|
||||
|
||||
digest = md5_file(temp_file)
|
||||
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
||||
local_file_path = File.join(save_path, digest) + ext
|
||||
save_temp_file(temp_file, local_file_path)
|
||||
|
||||
[local_file_path, digest]
|
||||
end
|
||||
|
||||
def save_temp_file(temp_file, save_file_path)
|
||||
File.open(save_file_path, 'wb') do |f|
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
f.write(buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def md5_file(temp_file)
|
||||
md5 = Digest::MD5.new
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
md5.update(buffer)
|
||||
end
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
def file_save_to_ucloud(path, file, content_type)
|
||||
ufile = Gitlink::Ufile.new(
|
||||
ucloud_public_key: edu_setting('public_key'),
|
||||
ucloud_private_key: edu_setting('private_key'),
|
||||
ucloud_public_read: true,
|
||||
ucloud_public_bucket: edu_setting('public_bucket'),
|
||||
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
||||
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
||||
)
|
||||
File.open(file) do |f|
|
||||
ufile.put(path, f, 'Content-Type' => content_type)
|
||||
end
|
||||
edu_setting('public_cdn_host') + "/" + path
|
||||
end
|
||||
|
||||
def attachment_candown
|
||||
unless current_user.admin? || current_user.business?
|
||||
candown = true
|
||||
unless params[:type] == 'history'
|
||||
if @file.container && current_user.logged?
|
||||
if @file.container.is_a?(Issue)
|
||||
course = @file.container.project
|
||||
candown = course.member?(current_user) || course.is_public
|
||||
elsif @file.container.is_a?(Journal)
|
||||
course = @file.container.issue.project
|
||||
candown = course.member?(current_user)
|
||||
else
|
||||
course = nil
|
||||
end
|
||||
tip_exception(403, "您没有权限进入") if course.present? && !candown
|
||||
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def send_file_with_range(path, options = {})
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
logger.info("########request.headers: #{File.exist?(path)}")
|
||||
|
||||
if File.exist?(path)
|
||||
size = File.size(path)
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
if !request.headers["Range"]
|
||||
status_code = 200 # 200 OK
|
||||
offset = 0
|
||||
length = File.size(path)
|
||||
else
|
||||
status_code = 206 # 206 Partial Content
|
||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||
offset = bytes.begin
|
||||
length = bytes.end - bytes.begin
|
||||
end
|
||||
response.header["Accept-Ranges"] = "bytes"
|
||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||
response.header["status"] = status_code
|
||||
|
||||
send_data IO.binread(path, length, offset), options
|
||||
else
|
||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
#coding=utf-8
|
||||
#
|
||||
# 文件上传
|
||||
class AttachmentsController < ApplicationController
|
||||
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
||||
before_action :find_file, only: %i[show destroy]
|
||||
before_action :attachment_candown, only: [:show]
|
||||
skip_before_action :check_sign, only: [:show, :create]
|
||||
|
||||
include ApplicationHelper
|
||||
|
||||
def show
|
||||
# 1. 优先跳到cdn
|
||||
# 2. 如果没有cdn,send_file
|
||||
if @file.cloud_url.present?
|
||||
update_downloads(@file)
|
||||
redirect_to @file.cloud_url and return
|
||||
end
|
||||
|
||||
type_attachment = params[:disposition] || "attachment"
|
||||
if type_attachment == "inline"
|
||||
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
||||
elsif type_attachment == "MP4"
|
||||
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
||||
else
|
||||
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
||||
end
|
||||
update_downloads(@file)
|
||||
end
|
||||
|
||||
|
||||
def get_file
|
||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
||||
url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s)
|
||||
if url.starts_with?(base_url) && !url.starts_with?("#{base_url}/repo")
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
api_url = GiteaService.gitea_config[:base_url]
|
||||
url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?')
|
||||
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
|
||||
response = Faraday.get(request_url)
|
||||
filename = url.to_s.split("/").pop()
|
||||
else
|
||||
response = Faraday.get(url)
|
||||
filename = params[:download_url].to_s.split("/").pop()
|
||||
end
|
||||
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
||||
end
|
||||
|
||||
def create
|
||||
# 1. 本地存储
|
||||
# 2. 上传到云
|
||||
begin
|
||||
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
||||
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
||||
raise "未上传文件" unless upload_file
|
||||
|
||||
folder = file_storage_directory
|
||||
raise "存储目录未定义" unless folder.present?
|
||||
|
||||
month_folder = current_month_folder
|
||||
save_path = File.join(folder, month_folder)
|
||||
|
||||
ext = file_ext(upload_file.original_filename)
|
||||
|
||||
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
||||
|
||||
content_type = upload_file.content_type.presence || 'application/octet-stream'
|
||||
|
||||
# remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type)
|
||||
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
||||
|
||||
logger.info "local_path: #{local_path}"
|
||||
logger.info "remote_path: #{remote_path}"
|
||||
|
||||
|
||||
disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
#存数据库
|
||||
#
|
||||
@attachment = Attachment.where(disk_filename: disk_filename,
|
||||
author_id: current_user.id,
|
||||
cloud_url: remote_path).first
|
||||
if @attachment.blank?
|
||||
@attachment = Attachment.new
|
||||
@attachment.filename = upload_file.original_filename
|
||||
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
@attachment.filesize = upload_file.tempfile.size
|
||||
@attachment.content_type = content_type
|
||||
@attachment.digest = digest
|
||||
@attachment.author_id = current_user.id
|
||||
@attachment.disk_directory = month_folder
|
||||
@attachment.cloud_url = remote_path
|
||||
@attachment.save!
|
||||
else
|
||||
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
||||
end
|
||||
|
||||
render_json
|
||||
rescue => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@file_path = absolute_path(local_path(@file))
|
||||
#return normal_status(403, "") unless @file.author == current_user
|
||||
@file.destroy!
|
||||
|
||||
delete_file(@file_path)
|
||||
normal_status("删除成功")
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
# 附件为视频时,点击播放
|
||||
def preview_attachment
|
||||
attachment = Attachment.find_by(id: params[:id])
|
||||
dir_path = "#{Rails.root}/public/preview"
|
||||
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
||||
if params[:status] == "preview"
|
||||
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
||||
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
else
|
||||
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
||||
normal_status(1, "操作成功")
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_file
|
||||
@file =
|
||||
if params[:type] == 'history'
|
||||
AttachmentHistory.find params[:id]
|
||||
else
|
||||
Attachment.find params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file(file_path)
|
||||
File.delete(file_path) if File.exist?(file_path)
|
||||
end
|
||||
|
||||
def current_month_folder
|
||||
date = Time.now
|
||||
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
||||
end
|
||||
|
||||
def file_ext(file_name)
|
||||
ext = ''
|
||||
exts = file_name.split(".")
|
||||
if exts.size > 1
|
||||
ext = ".#{exts.last}"
|
||||
end
|
||||
ext
|
||||
end
|
||||
|
||||
def file_save_to_local(save_path, temp_file, ext)
|
||||
unless Dir.exists?(save_path)
|
||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||
end
|
||||
|
||||
digest = md5_file(temp_file)
|
||||
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
||||
local_file_path = File.join(save_path, digest) + ext
|
||||
save_temp_file(temp_file, local_file_path)
|
||||
|
||||
[local_file_path, digest]
|
||||
end
|
||||
|
||||
def save_temp_file(temp_file, save_file_path)
|
||||
File.open(save_file_path, 'wb') do |f|
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
f.write(buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def md5_file(temp_file)
|
||||
md5 = Digest::MD5.new
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
md5.update(buffer)
|
||||
end
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
def file_save_to_ucloud(path, file, content_type)
|
||||
ufile = Gitlink::Ufile.new(
|
||||
ucloud_public_key: edu_setting('public_key'),
|
||||
ucloud_private_key: edu_setting('private_key'),
|
||||
ucloud_public_read: true,
|
||||
ucloud_public_bucket: edu_setting('public_bucket'),
|
||||
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
||||
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
||||
)
|
||||
File.open(file) do |f|
|
||||
ufile.put(path, f, 'Content-Type' => content_type)
|
||||
end
|
||||
edu_setting('public_cdn_host') + "/" + path
|
||||
end
|
||||
|
||||
def attachment_candown
|
||||
unless current_user.admin? || current_user.business?
|
||||
candown = true
|
||||
if @file.container
|
||||
if @file.container.is_a?(Issue)
|
||||
project = @file.container.project
|
||||
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||
elsif @file.container.is_a?(Journal)
|
||||
project = @file.container.issue.project
|
||||
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||
else
|
||||
project = nil
|
||||
end
|
||||
tip_exception(403, "您没有权限进入") if project.present? && !candown
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def send_file_with_range(path, options = {})
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
logger.info("########request.headers: #{File.exist?(path)}")
|
||||
|
||||
if File.exist?(path)
|
||||
size = File.size(path)
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
if !request.headers["Range"]
|
||||
status_code = 200 # 200 OK
|
||||
offset = 0
|
||||
length = File.size(path)
|
||||
else
|
||||
status_code = 206 # 206 Partial Content
|
||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||
offset = bytes.begin
|
||||
length = bytes.end - bytes.begin
|
||||
end
|
||||
response.header["Accept-Ranges"] = "bytes"
|
||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||
response.header["status"] = status_code
|
||||
|
||||
send_data IO.binread(path, length, offset), options
|
||||
else
|
||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,35 +1,19 @@
|
|||
class BindUsersController < ApplicationController
|
||||
# before_action :require_login
|
||||
|
||||
def create
|
||||
# user = CreateBindUserService.call(create_params)
|
||||
#
|
||||
if params[:type] == "qq"
|
||||
begin
|
||||
user = CreateBindUserService.call(current_user, create_params)
|
||||
successful_authentication(user) if user.id != current_user.id
|
||||
Rails.logger.debug "--------------开始绑定用户------------"
|
||||
Rails.logger.debug "--------------params: #{params.to_unsafe_h}"
|
||||
tip_exception '系统错误' if session[:unionid].blank?
|
||||
|
||||
render_ok
|
||||
rescue ApplicationService::Error => ex
|
||||
render_error(ex.message)
|
||||
end
|
||||
else
|
||||
begin
|
||||
tip_exception '系统错误' if session[:unionid].blank?
|
||||
bind_user = User.try_to_login(params[:username], params[:password])
|
||||
tip_exception '用户名或者密码错误' if bind_user.blank?
|
||||
tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
|
||||
tip_exception '参数错误' unless ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s)
|
||||
tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
|
||||
|
||||
bind_user = User.try_to_login(params[:username], params[:password])
|
||||
tip_exception '用户名或者密码错误' if bind_user.blank?
|
||||
tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
|
||||
tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
|
||||
|
||||
OpenUsers::Wechat.create!(user: bind_user, uid: session[:unionid])
|
||||
successful_authentication(bind_user)
|
||||
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
render_error(e.message)
|
||||
end
|
||||
end
|
||||
"OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: bind_user, uid: session[:unionid])
|
||||
successful_authentication(bind_user)
|
||||
@user = bind_user
|
||||
end
|
||||
|
||||
def new_user
|
||||
|
|
|
@ -14,12 +14,12 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
|
||||
def create
|
||||
flag, msg = check_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
|
@ -27,17 +27,17 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def activate
|
||||
return render_error('请先认证') unless current_user.ci_certification?
|
||||
return tip_exception('请先认证') unless current_user.ci_certification?
|
||||
|
||||
begin
|
||||
@cloud_account = Ci::CloudAccount.find params[:id]
|
||||
ActiveRecord::Base.transaction do
|
||||
if @repo
|
||||
return render_error('该项目已经激活') if @repo.repo_active?
|
||||
return tip_exception('该项目已经激活') if @repo.repo_active?
|
||||
@repo.activate!(@project)
|
||||
else
|
||||
@repo = Ci::Repo.auto_create!(@ci_user, @project)
|
||||
|
@ -50,7 +50,7 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,39 +59,39 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
|
||||
def bind
|
||||
flag, msg = check_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def trustie_bind
|
||||
account = params[:account].to_s
|
||||
return render_error("account不能为空.") if account.blank?
|
||||
return tip_exception("account不能为空.") if account.blank?
|
||||
|
||||
flag, msg = check_trustie_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = trustie_bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def unbind
|
||||
|
@ -107,18 +107,18 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def oauth_grant
|
||||
password = params[:password].to_s
|
||||
return render_error('你输入的密码不正确.') unless current_user.check_password?(password)
|
||||
return tip_exception('你输入的密码不正确.') unless current_user.check_password?(password)
|
||||
|
||||
oauth = current_user.oauths.last
|
||||
return render_error("服务器出小差了.") if oauth.blank?
|
||||
return tip_exception("服务器出小差了.") if oauth.blank?
|
||||
|
||||
result = gitea_oauth_grant!(password, oauth)
|
||||
return render_error('授权失败.') unless result === true
|
||||
return tip_exception('授权失败.') unless result === true
|
||||
current_user.set_drone_step!(User::DEVOPS_CERTIFICATION)
|
||||
end
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
ActiveRecord::Base.transaction do
|
||||
size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size
|
||||
if size > 0
|
||||
render_error("#{params[:branch]}分支已经存在流水线!")
|
||||
tip_exception("#{params[:branch]}分支已经存在流水线!")
|
||||
return
|
||||
end
|
||||
pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner],
|
||||
|
@ -53,7 +53,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok({id: pipeline.id})
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
# 在代码库创建文件
|
||||
|
@ -81,6 +81,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
repo_branch: pipeline.branch,
|
||||
repo_config: pipeline.file_name
|
||||
}
|
||||
Rails.logger.info("########create_params===#{create_params.to_json}")
|
||||
repo = Ci::Repo.create_repo(create_params)
|
||||
repo
|
||||
end
|
||||
|
@ -118,7 +119,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -132,7 +133,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def content
|
||||
|
@ -182,7 +183,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage
|
||||
|
@ -192,7 +193,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def delete_stage
|
||||
|
@ -205,7 +206,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage_index(pipeline_id, show_index, diff)
|
||||
|
@ -229,7 +230,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
unless steps.empty?
|
||||
steps.each do |step|
|
||||
unless step[:template_id]
|
||||
render_error('请选择模板!')
|
||||
tip_exception('请选择模板!')
|
||||
return
|
||||
end
|
||||
if !step[:id]
|
||||
|
@ -246,7 +247,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def create_stage_step
|
||||
|
@ -262,7 +263,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage_step
|
||||
|
@ -279,7 +280,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def delete_stage_step
|
||||
|
@ -289,6 +290,6 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,19 +30,19 @@ class Ci::ProjectsController < Ci::BaseController
|
|||
@file = interactor.result
|
||||
render_result(1, "更新成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
tip_exception(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def activate
|
||||
return render_error('你还未认证') unless current_user.ci_certification?
|
||||
return tip_exception('你还未认证') unless current_user.ci_certification?
|
||||
|
||||
begin
|
||||
ActiveRecord::Base.transaction do
|
||||
if @repo
|
||||
return render_error('该项目已经激活') if @repo.repo_active?
|
||||
@repo.destroy! if @repo&.repo_user_id == 0
|
||||
return tip_exception('该项目已经激活') if @repo.repo_active?
|
||||
@repo.activate!(@project)
|
||||
return render_ok
|
||||
else
|
||||
@repo = Ci::Repo.auto_create!(@ci_user, @project)
|
||||
@ci_user.update_column(:user_syncing, false)
|
||||
|
@ -55,12 +55,12 @@ class Ci::ProjectsController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
||||
def deactivate
|
||||
return render_error('该项目已经取消激活') if !@repo.repo_active?
|
||||
return tip_exception('该项目已经取消激活') if !@repo.repo_active?
|
||||
|
||||
@project.update_column(:open_devops, false)
|
||||
@repo.deactivate_repos!
|
||||
|
|
|
@ -20,14 +20,14 @@ class Ci::SecretsController < Ci::BaseController
|
|||
if result["id"]
|
||||
render_ok
|
||||
else
|
||||
render_error(result["message"])
|
||||
tip_exception(result["message"])
|
||||
end
|
||||
else
|
||||
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret
|
||||
if result["id"]
|
||||
render_ok
|
||||
else
|
||||
render_error(result["message"])
|
||||
tip_exception(result["message"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -39,7 +39,7 @@ class Ci::SecretsController < Ci::BaseController
|
|||
Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret
|
||||
render_ok
|
||||
else
|
||||
render_error("参数名不能为空")
|
||||
tip_exception("参数名不能为空")
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_ok
|
||||
|
|
|
@ -50,7 +50,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -63,7 +63,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
)
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -73,7 +73,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
#======流水线模板查询=====#
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
class CommitLogsController < ApplicationController
|
||||
|
||||
def create
|
||||
tip_exception "未认证" unless params[:token].to_s == "7917908927b6f1b792f2027a08a8b24a2de42c1692c2fd45da0dee5cf90a5af5"
|
||||
ref = params[:ref]
|
||||
user_name = params[:pusher][:login]
|
||||
user_mail = params[:pusher][:email]
|
||||
user = User.find_by(mail: user_mail)
|
||||
user = User.find_by(login: user_name) if user.blank?
|
||||
|
||||
repository_id = params[:repository][:id]
|
||||
repository_name = params[:repository][:name]
|
||||
repository_full_name = params[:repository][:full_name]
|
||||
owner_name = repository_full_name.split("/")[0]
|
||||
owner = User.find_by(login: owner_name)
|
||||
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
|
||||
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
|
||||
project.update_column(:updated_on, Time.now) if project.present?
|
||||
params[:commits].each do |commit|
|
||||
commit_id = commit[:id]
|
||||
message = commit[:message]
|
||||
CommitLog.create(user: user, project: project, repository_id: repository_id,
|
||||
name: repository_name, full_name: repository_full_name,
|
||||
ref: ref, commit_id: commit_id, message: message)
|
||||
# 统计数据新增
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {commits: 1}, project.id)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -6,9 +6,14 @@ class CompareController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
load_compare_params
|
||||
compare
|
||||
@merge_status, @merge_message = get_merge_message
|
||||
if params[:type] == "sha"
|
||||
load_compare_params
|
||||
@compare_result ||= gitea_compare(@base, @head)
|
||||
else
|
||||
load_compare_params
|
||||
compare
|
||||
@merge_status, @merge_message = get_merge_message
|
||||
end
|
||||
@page_size = page_size <= 0 ? 1 : page_size
|
||||
@page_limit = page_limit <=0 ? 15 : page_limit
|
||||
@page_offset = (@page_size -1) * @page_limit
|
||||
|
@ -58,7 +63,7 @@ class CompareController < ApplicationController
|
|||
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
|
||||
end
|
||||
|
||||
def page_size
|
||||
def page_size
|
||||
params.fetch(:page, 1).to_i
|
||||
end
|
||||
|
||||
|
|
|
@ -18,15 +18,15 @@ module Acceleratorable
|
|||
end
|
||||
|
||||
def accelerator_domain
|
||||
Gitea.gitea_config[:accelerator]["domain"]
|
||||
GiteaService.gitea_config[:accelerator]["domain"]
|
||||
end
|
||||
|
||||
def accelerator_username
|
||||
Gitea.gitea_config[:accelerator]["access_key_id"]
|
||||
GiteaService.gitea_config[:accelerator]["access_key_id"]
|
||||
end
|
||||
|
||||
def config_accelerator?
|
||||
Gitea.gitea_config[:accelerator].present?
|
||||
GiteaService.gitea_config[:accelerator].present?
|
||||
end
|
||||
|
||||
def is_foreign_url?(clone_addr)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
module Api::ProjectHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_project
|
||||
namespace = params[:owner]
|
||||
repo = params[:repo]
|
||||
|
||||
@project, @owner = Project.find_with_namespace(namespace, repo)
|
||||
|
||||
if @project
|
||||
logger.info "###########:project founded"
|
||||
@project
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
end
|
||||
@project
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module Api::PullHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_pull_request
|
||||
pull_request_id = params[:pull_id] || params[:id]
|
||||
@pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id)
|
||||
@issue = @pull_request&.issue
|
||||
if @pull_request
|
||||
logger.info "###########pull_request founded"
|
||||
@pull_request
|
||||
else
|
||||
logger.info "###########pull_request not found"
|
||||
@pull_request = nil
|
||||
render_not_found and return
|
||||
end
|
||||
|
||||
@pull_request
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
module Api::UserHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_observe_user
|
||||
username = params[:owner]
|
||||
|
||||
@observe_user = User.find_by(login: username)
|
||||
|
||||
if @observe_user
|
||||
logger.info "###########observe_user not founded"
|
||||
@observe_user
|
||||
else
|
||||
logger.info "###########observe_user not found"
|
||||
@observe_user = nil
|
||||
render_not_found and return
|
||||
end
|
||||
@observe_user
|
||||
end
|
||||
|
||||
# 是否具有查看用户或编辑用户的权限
|
||||
def check_auth_for_observe_user
|
||||
return render_forbidden unless current_user.admin? || @observe_user.id == current_user.id
|
||||
end
|
||||
|
||||
def strip(str)
|
||||
str.to_s.strip.presence
|
||||
end
|
||||
end
|
|
@ -160,9 +160,9 @@ module Ci::CloudAccountManageable
|
|||
state = SecureRandom.hex(8)
|
||||
# redirect_uri eg:
|
||||
# https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805
|
||||
redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
|
||||
clientId = client_id(oauth)
|
||||
grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{clientId}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}"
|
||||
# redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
|
||||
# clientId = client_id(oauth)
|
||||
grant_url = "#{@cloud_account.drone_url}/login"
|
||||
logger.info "[gitea] grant_url: #{grant_url}"
|
||||
|
||||
conn = Faraday.new(url: grant_url) do |req|
|
||||
|
@ -179,7 +179,7 @@ module Ci::CloudAccountManageable
|
|||
|
||||
def drone_oauth_user!(url, state)
|
||||
logger.info "[drone] drone_oauth_user url: #{url}"
|
||||
conn = Faraday.new(url: "#{Gitea.gitea_config[:domain]}#{url}") do |req|
|
||||
conn = Faraday.new(url: url) do |req|
|
||||
req.request :url_encoded
|
||||
req.adapter Faraday.default_adapter
|
||||
req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}"
|
||||
|
@ -188,8 +188,8 @@ module Ci::CloudAccountManageable
|
|||
response = conn.get
|
||||
logger.info "[drone] response headers: #{response.headers}"
|
||||
|
||||
true
|
||||
# response.headers['location'].include?('error') ? false : true
|
||||
# true
|
||||
response.headers['location'].include?('error') ? false : true
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -11,7 +11,7 @@ module LoginHelper
|
|||
|
||||
def set_autologin_cookie(user)
|
||||
token = Token.get_or_create_permanent_login_token(user, "autologin")
|
||||
sync_user_token_to_trustie(user.login, token.value)
|
||||
# sync_user_token_to_trustie(user.login, token.value)
|
||||
|
||||
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
|
||||
cookie_options = {
|
||||
|
@ -44,6 +44,7 @@ module LoginHelper
|
|||
set_autologin_cookie(user)
|
||||
|
||||
UserAction.create(action_id: user&.id, action_type: 'Login', user_id: user&.id, ip: request.remote_ip)
|
||||
# user.daily_reward
|
||||
user.update_column(:last_login_on, Time.now)
|
||||
# 注册完成后有一天的试用申请(先去掉)
|
||||
# UserDayCertification.create(user_id: user.id, status: 1)
|
||||
|
@ -116,6 +117,7 @@ module LoginHelper
|
|||
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
|
||||
if interactor.success?
|
||||
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
|
||||
user.update_column(:is_sync_pwd, true)
|
||||
true
|
||||
else
|
||||
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
module RegisterHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def autologin_register(username, email, password, platform= 'forge', need_edit_info = false)
|
||||
def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false)
|
||||
result = {message: nil, user: nil}
|
||||
email = email.blank? ? "#{username}@example.org" : email
|
||||
|
||||
user = User.new(admin: false, login: username, mail: email, type: "User")
|
||||
user.password = password
|
||||
user.platform = platform
|
||||
user.phone = phone if phone.present?
|
||||
user.nickname = nickname if nickname.present?
|
||||
if need_edit_info
|
||||
user.need_edit_info
|
||||
else
|
||||
else
|
||||
user.activate
|
||||
end
|
||||
|
||||
|
||||
return unless user.valid?
|
||||
|
||||
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
|
||||
result ={}
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(username, password)
|
||||
|
@ -26,7 +30,7 @@ module RegisterHelper
|
|||
result[:user] = {id: user.id, token: user.gitea_token}
|
||||
end
|
||||
else
|
||||
result[:message] = interactor.error
|
||||
result[:message] = interactor.result[:message]
|
||||
end
|
||||
result
|
||||
end
|
||||
|
@ -58,4 +62,32 @@ module RegisterHelper
|
|||
end
|
||||
end
|
||||
|
||||
def auto_update(user, params={})
|
||||
return if params.blank?
|
||||
result = {message: nil, user: nil}
|
||||
before_login = user.login
|
||||
user.login = params[:username]
|
||||
user.password = params[:password]
|
||||
user.mail = params[:email]
|
||||
|
||||
if user.save!
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: params[:email],
|
||||
login_name: params[:username],
|
||||
new_name: params[:username],
|
||||
source_id: 0
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
|
||||
if interactor.success?
|
||||
result[:user] = user
|
||||
else
|
||||
result[:message] = '用户同步Gitea失败!'
|
||||
end
|
||||
else
|
||||
result[:message] = user.errors.full_messages.join(",")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,8 @@ module RenderHelper
|
|||
render json: { status: 0, message: 'success' }.merge(data)
|
||||
end
|
||||
|
||||
def render_error(message = '')
|
||||
render json: { status: -1, message: message }
|
||||
def render_error(message = '', status = -1)
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
|
||||
def render_not_acceptable(message = '请求已拒绝')
|
||||
|
|
|
@ -5,7 +5,17 @@ module Repository::LanguagesPercentagable
|
|||
result = Gitea::Repository::Languages::ListService.call(@owner.login,
|
||||
@repository.identifier, current_user&.gitea_token)
|
||||
|
||||
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
|
||||
@transform_language = result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
|
||||
update_project_language(@transform_language) unless @transform_language.nil?
|
||||
@transform_language
|
||||
end
|
||||
|
||||
def update_project_language(language)
|
||||
return if @project.project_language.present?
|
||||
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
|
||||
@project.update_column(:project_language_id, db_language.id)
|
||||
rescue
|
||||
return
|
||||
end
|
||||
|
||||
# hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781}
|
||||
|
|
|
@ -3,9 +3,12 @@ class ForksController < ApplicationController
|
|||
before_action :require_profile_completed, only: [:create]
|
||||
before_action :load_project
|
||||
before_action :authenticate_project!, :authenticate_user!
|
||||
skip_after_action :user_trace_log, only: [:create]
|
||||
|
||||
def create
|
||||
@new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call
|
||||
user = current_user
|
||||
Rails.logger.user_trace.info("{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params.merge(forkee: @new_project.id)}, response_code: #{response.code}, time: #{Time.now}}")
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -7,7 +7,7 @@ class IssueTagsController < ApplicationController
|
|||
|
||||
|
||||
def index
|
||||
issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}")
|
||||
issue_tags = @project.issue_tags.includes(:issues).reorder("issue_tags.#{order_name} #{order_type}")
|
||||
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
|
||||
@page = params[:page] || 1
|
||||
@limit = params[:limit] || 15
|
||||
|
|
|
@ -11,6 +11,8 @@ class IssuesController < ApplicationController
|
|||
before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue]
|
||||
before_action :check_token_enough, :find_atme_receivers, only: [:create, :update]
|
||||
|
||||
skip_after_action :user_trace_log, only: [:update]
|
||||
|
||||
include ApplicationHelper
|
||||
include TagChosenHelper
|
||||
|
||||
|
@ -237,6 +239,7 @@ class IssuesController < ApplicationController
|
|||
# end
|
||||
# end
|
||||
# end
|
||||
issue_hash = old_value_to_hash(@issue, params)
|
||||
|
||||
if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id)
|
||||
normal_status(-1, "不允许修改为关闭状态")
|
||||
|
@ -244,6 +247,9 @@ class IssuesController < ApplicationController
|
|||
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
|
||||
Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
|
||||
if @issue.update_attributes(issue_params)
|
||||
|
||||
user_trace_update_log(issue_hash)
|
||||
|
||||
if @issue&.pull_request.present?
|
||||
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
|
||||
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?
|
||||
|
|
|
@ -4,6 +4,7 @@ class JournalsController < ApplicationController
|
|||
before_action :set_issue
|
||||
before_action :check_issue_permission
|
||||
before_action :set_journal, only: [:destroy, :edit, :update]
|
||||
skip_after_action :user_trace_log, only: [:update]
|
||||
|
||||
def index
|
||||
@page = params[:page] || 1
|
||||
|
@ -86,9 +87,11 @@ class JournalsController < ApplicationController
|
|||
|
||||
def update
|
||||
content = params[:content]
|
||||
if content.present?
|
||||
if content.present?
|
||||
old_value = old_value_to_hash(@journal, params)
|
||||
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
|
||||
if @journal.update_attribute(:notes, content)
|
||||
user_trace_update_log(old_value)
|
||||
normal_status(0, "更新成功")
|
||||
else
|
||||
normal_status(-1, "更新失败")
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
class LogController < ApplicationController
|
||||
def list
|
||||
path = "#{Rails.root}/log"
|
||||
@file_list = []
|
||||
Dir.foreach(path) do |file|
|
||||
@file_list << file
|
||||
end
|
||||
@file_list = @file_list.sort
|
||||
end
|
||||
|
||||
def download
|
||||
path = "#{Rails.root}/log/#{params[:filename]}"
|
||||
if params[:filename] && File.exist?(path) && File.file?(path)
|
||||
send_file(path, filename: params[:filename])
|
||||
else
|
||||
render json: { message: 'no such file!' }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
class MarkFilesController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :load_project
|
||||
before_action :load_pull_request
|
||||
|
||||
def index
|
||||
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token, { "only-file-name": true })
|
||||
@mark_files = MarkFile.where(pull_request_id: @pull_request.id)
|
||||
end
|
||||
|
||||
def create
|
||||
# unless @pull_request.mark_files.present?
|
||||
# MarkFile.bulk_insert(*%i[pull_request_id, file_path_sha file_path created_at updated_at]) do |worker|
|
||||
# @files_result['Files'].each do |file|
|
||||
# worker.add(pull_request_id: @pull_request.id, file_path_sha: SecureRandom.uuid.gsub("-", ""), file_path: file['Name'])
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
def mark_file_as_unread
|
||||
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||
mark_file.file_path = file_path
|
||||
mark_file.user_id = current_user.id
|
||||
mark_file.mark_as_read = false
|
||||
mark_file.save
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
tip_exception "参数解析错误"
|
||||
end
|
||||
|
||||
def mark_file_as_read
|
||||
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||
mark_file.file_path = file_path
|
||||
mark_file.user_id = current_user.id
|
||||
mark_file.mark_as_read = true
|
||||
mark_file.save
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
tip_exception "参数解析错误"
|
||||
end
|
||||
|
||||
private
|
||||
def review_params
|
||||
params.require(:review).permit(:content, :commit_id, :status)
|
||||
end
|
||||
|
||||
def load_pull_request
|
||||
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
end
|
|
@ -6,6 +6,7 @@ class MembersController < ApplicationController
|
|||
before_action :operate!
|
||||
before_action :check_member_exists!, only: %i[create]
|
||||
before_action :check_member_not_exists!, only: %i[remove change_role]
|
||||
skip_after_action :user_trace_log, only: [:change_role]
|
||||
|
||||
def create
|
||||
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
|
||||
|
@ -26,6 +27,9 @@ class MembersController < ApplicationController
|
|||
|
||||
@total_count = scope.size
|
||||
@members = paginate(scope)
|
||||
if @project.owner.is_a?(Organization) && (params[:page].to_i == 1 || params[:page].blank?) && !@project.members.exists?(user_id: current_user.id)
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
end
|
||||
end
|
||||
|
||||
def remove
|
||||
|
@ -39,7 +43,9 @@ class MembersController < ApplicationController
|
|||
end
|
||||
|
||||
def change_role
|
||||
old_value = @project.members.where(user_id: params[:user_id])[0].roles.last.name
|
||||
interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role])
|
||||
user_trace_update_log(old_value)
|
||||
SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name) if Site.has_notice_menu?
|
||||
render_response(interactor)
|
||||
rescue Exception => e
|
||||
|
@ -61,11 +67,14 @@ class MembersController < ApplicationController
|
|||
end
|
||||
|
||||
def check_member_exists!
|
||||
return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
return render_error("#{@user&.nickname}已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?)
|
||||
end
|
||||
|
||||
def check_member_not_exists!
|
||||
return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
return render_error("用户为组织成员,请到组织下操作!") if (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) && !member_exists?
|
||||
return render_error("#{@user&.nickname}还不是项目成员") unless member_exists?
|
||||
end
|
||||
|
||||
def check_user_profile_completed
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class NoticesController < ApplicationController
|
||||
|
||||
def create
|
||||
tip_exception("参数有误") if params["source"].blank?
|
||||
return tip_exception("参数有误") if params["source"].blank?
|
||||
user_id = params[:user_id]
|
||||
|
||||
if params["source"] == "CompetitionBegin"
|
||||
|
@ -13,9 +13,21 @@ class NoticesController < ApplicationController
|
|||
elsif params["source"] == "CompetitionReview"
|
||||
competition_id = params[:competition_id]
|
||||
SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id)
|
||||
elsif params["source"] == "CustomTip"
|
||||
users_id = params[:users_id]
|
||||
props = params[:props].to_unsafe_hash
|
||||
return tip_exception("参数有误") unless props.is_a?(Hash) && users_id.is_a?(Array)
|
||||
template_id = params[:template_id]
|
||||
SendTemplateMessageJob.perform_later('CustomTip', users_id, template_id, props)
|
||||
else
|
||||
tip_exception("#{params["source"]}未配置")
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def params_props
|
||||
params.require(:notice).permit(:props)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
class NpsController < ApplicationController
|
||||
|
||||
before_action :require_login
|
||||
|
||||
# close,关闭
|
||||
# createIssue,创建issue
|
||||
# createPullRequest,创建PR
|
||||
# auditPullRequest,审核PR
|
||||
# indexProject,项目主页
|
||||
# createProject,创建项目
|
||||
# createOrganization,创建组织
|
||||
def create
|
||||
tip_exception "缺少参数" if params[:action_id].blank? || params[:action_type].blank?
|
||||
UserNp.create(:action_id => params[:action_id].to_i, :action_type => params[:action_type], :user_id => User.current.id, :score => params[:score].to_f, memo: params[:memo])
|
||||
render_ok
|
||||
end
|
||||
end
|
|
@ -3,6 +3,7 @@ class Oauth::BaseController < ActionController::Base
|
|||
include LoginHelper
|
||||
include ControllerRescueHandler
|
||||
include LoggerHelper
|
||||
include RegisterHelper
|
||||
# include LaboratoryHelper
|
||||
|
||||
skip_before_action :verify_authenticity_token
|
||||
|
@ -13,13 +14,13 @@ class Oauth::BaseController < ActionController::Base
|
|||
|
||||
private
|
||||
def tip_exception(status = -1, message)
|
||||
raise Educoder::TipException.new(status, message)
|
||||
raise Gitlink::TipException.new(status, message)
|
||||
end
|
||||
|
||||
|
||||
def tip_show_exception(status = -2, message)
|
||||
raise Educoder::TipException.new(status, message)
|
||||
raise Gitlink::TipException.new(status, message)
|
||||
end
|
||||
|
||||
|
||||
def tip_show(exception)
|
||||
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
|
||||
render json: exception.tip_json
|
||||
|
@ -35,7 +36,7 @@ class Oauth::BaseController < ActionController::Base
|
|||
end
|
||||
|
||||
def auth_hash
|
||||
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||
# Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||
request.env['omniauth.auth']
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
class Oauth::CallbacksController < Oauth::BaseController
|
||||
def create
|
||||
process_callback_new
|
||||
rescue Exception => e
|
||||
Rails.logger.info "授权失败:#{e}"
|
||||
tip_exception("授权失败")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config_providers
|
||||
config = Rails.application.config_for(:configuration)
|
||||
config.dig("oauth").keys
|
||||
end
|
||||
|
||||
# QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"}
|
||||
def process_callback
|
||||
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||
if auth_hash.blank?
|
||||
redirect_to("/login") && return
|
||||
end
|
||||
|
||||
new_user = false
|
||||
platform = auth_hash[:provider]
|
||||
uid = auth_hash[:uid]
|
||||
mail = auth_hash.info.email || nil
|
||||
nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname
|
||||
|
||||
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid)
|
||||
if open_user.present? && open_user.user.present?
|
||||
successful_authentication(open_user.user)
|
||||
else
|
||||
if current_user.blank? || !current_user.logged?
|
||||
has_user = User.find_by(mail: mail)
|
||||
if has_user.present?
|
||||
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra)
|
||||
successful_authentication(has_user)
|
||||
else
|
||||
new_user = true
|
||||
login = build_login_name(platform, auth_hash.info.nickname)
|
||||
mail = "#{login}@example.org" if mail.blank?
|
||||
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||
rand_password = code.sample(10).join
|
||||
reg_result = autologin_register(login, mail, rand_password, platform, nil, nickname)
|
||||
Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ")
|
||||
if reg_result[:message].blank?
|
||||
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra)
|
||||
successful_authentication(open_user.user)
|
||||
else
|
||||
tip_exception(reg_result.present? ? reg_result[:message] : "授权失败")
|
||||
end
|
||||
end
|
||||
else
|
||||
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra)
|
||||
end
|
||||
end
|
||||
redirect_to root_path(new_user: new_user)
|
||||
end
|
||||
|
||||
def process_callback_new
|
||||
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||
if auth_hash.blank?
|
||||
redirect_to("/login") && return
|
||||
end
|
||||
platform = auth_hash[:provider]
|
||||
uid = auth_hash[:uid]
|
||||
uid = auth_hash.info.unionid if platform == "wechat"
|
||||
|
||||
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid)
|
||||
if open_user.present? && open_user.user.present?
|
||||
successful_authentication(open_user.user)
|
||||
redirect_to root_path(new_user: false)
|
||||
return
|
||||
else
|
||||
if current_user.blank? || !current_user.logged?
|
||||
session[:unionid] = uid
|
||||
else
|
||||
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: uid)
|
||||
end
|
||||
end
|
||||
Rails.logger.info("[OAuth2] session[:unionid] -> #{session[:unionid]}")
|
||||
redirect_to "/bindlogin/#{platform}"
|
||||
end
|
||||
|
||||
# gitee,github nickname=login,如果系统未占用保留原用户名
|
||||
def build_login_name(provider, nickname)
|
||||
if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank?
|
||||
nickname
|
||||
else
|
||||
User.generate_user_login('p')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
class Oauth2Controller < ActionController::Base
|
||||
layout 'doorkeeper/application'
|
||||
include LoginHelper
|
||||
|
||||
def show
|
||||
client_id = params[:call_url].split("client_id=")[1].split("&redirect_uri")[0]
|
||||
@call_url = request.fullpath.split('call_url=').last
|
||||
@app = Doorkeeper::Application.find_by(uid: client_id)
|
||||
end
|
||||
|
||||
def create
|
||||
if params[:login].blank?
|
||||
@error = {msg: '邮箱地址或用户名不能为空', id: 'login'}
|
||||
elsif params[:password].blank?
|
||||
@error = {msg: '请输入密码', id: 'password'}
|
||||
else
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
|
||||
return @error = {msg: '账号或密码错误', id: 'login'} if @user.blank?
|
||||
return @error = {msg: '违反平台使用规范,账号已被锁定', id: 'login'} if @user.locked?
|
||||
|
||||
login_control = LimitForbidControl::UserLogin.new(@user)
|
||||
return @error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} if login_control.forbid?
|
||||
|
||||
password_ok = @user.check_password?(params[:password].to_s)
|
||||
unless password_ok
|
||||
if login_control.remain_times-1 == 0
|
||||
@error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'}
|
||||
else
|
||||
@error = {msg: "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会", id: 'account'}
|
||||
end
|
||||
login_control.increment!
|
||||
return
|
||||
end
|
||||
login_control.clear
|
||||
redirect_to params[:call_url] + "&auth=" + @user.login
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,130 @@
|
|||
class ObRepositorySyncsController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :load_project
|
||||
before_action :load_ob_repository_sync, except: [:create]
|
||||
before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
render_ok(data: @ob_repository_sync)
|
||||
end
|
||||
|
||||
|
||||
def create
|
||||
tip_exception "参数错误" if params[:github_address].blank? && params[:gitee_address].blank?
|
||||
project_name ="#{@project.owner.name}:#{@project.identifier}"
|
||||
service = ObRepositorySync::ApiService.new(project_name)
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
project_params = params.merge({ "gitlink_address": "#{domain}/#{@project.owner&.login}/#{@project.identifier}.git" })
|
||||
res = service.create_projects(project_params)
|
||||
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
sync_id = res["data"]["id"]
|
||||
ob_repository_sync = ObRepositorySync.find_or_initialize_by(project_id: @project.id)
|
||||
ob_repository_sync.project_id = @project.id
|
||||
ob_repository_sync.user_id = current_user.id
|
||||
ob_repository_sync.name = project_name
|
||||
ob_repository_sync.github_address = "#{params[:github_address]}"
|
||||
ob_repository_sync.gitee_address = "#{params[:gitee_address]}"
|
||||
ob_repository_sync.github_token = "#{params[:github_token]}"
|
||||
ob_repository_sync.gitee_token = "#{params[:gitee_token]}"
|
||||
ob_repository_sync.sync_id = sync_id
|
||||
ob_repository_sync.save!
|
||||
render_ok
|
||||
end
|
||||
|
||||
def delete
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.delete_project @ob_repository_sync.sync_id
|
||||
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
if res["code"].to_s == "200"
|
||||
@ob_repository_sync.destroy!
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def jobs
|
||||
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
|
||||
page = params[:page] || 1
|
||||
limit = params[:limit] || 10
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
source = ""
|
||||
if params[:type] && params[:type].to_s.downcase == "github"
|
||||
source = "github_branch"
|
||||
elsif params[:type] && params[:type].to_s.downcase == "gitee"
|
||||
source = "gitee_branch"
|
||||
end
|
||||
res = service.get_projects_jobs(source, page, limit)
|
||||
data = res["data"]["list"]
|
||||
render_ok(count: res["data"]["total"], data: data)
|
||||
end
|
||||
|
||||
def create_jobs
|
||||
tip_exception "必须配置一个分支" if params[:github_branch].blank? && params[:gitee_branch].blank? && params[:gitlink_branch].blank?
|
||||
ob_jobs = ObRepositorySyncJob.where(ob_repository_sync_id: @ob_repository_sync.id)
|
||||
ob_jobs = ob_jobs.where(job_type: params[:job_type]) if params[:job_type].present?
|
||||
ob_jobs = ob_jobs.where(github_branch: params[:github_branch]) if params[:github_branch].present?
|
||||
ob_jobs = ob_jobs.where(gitee_branch: params[:gitee_branch]) if params[:gitee_branch].present?
|
||||
ob_jobs = ob_jobs.where(gitlink_branch: params[:gitlink_branch]) if params[:gitlink_branch].present?
|
||||
tip_exception "该分支组合已配置,不能重复!" if ob_jobs.count > 0
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.create_projects_jobs(params)
|
||||
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
job_id = res["data"]["id"]
|
||||
job = ObRepositorySyncJob.new
|
||||
job.ob_repository_sync_id = @ob_repository_sync.id
|
||||
job.github_branch = "#{params[:github_branch]}"
|
||||
job.gitee_branch = "#{params[:gitee_branch]}"
|
||||
job.gitlink_branch = "#{params[:gitlink_branch]}"
|
||||
job.job_type = "#{params[:job_type]}"
|
||||
job.base = "#{params[:base]}"
|
||||
job.job_id = job_id
|
||||
job.save
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
def delete_job
|
||||
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.delete_job params[:job_id]
|
||||
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
job = ObRepositorySyncJob.find_by(ob_repository_sync_id: @ob_repository_sync.id, job_id: params[:job_id])
|
||||
job.destroy! if job.present?
|
||||
render_ok
|
||||
end
|
||||
|
||||
def start_job
|
||||
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.start_job params[:job_id]
|
||||
tip_exception "启动错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
render_ok
|
||||
end
|
||||
|
||||
def stop_job
|
||||
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.stop_job params[:job_id]
|
||||
tip_exception "停止错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
render_ok
|
||||
end
|
||||
|
||||
def job_logs
|
||||
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
|
||||
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||
res = service.job_logs params[:job_id]
|
||||
tip_exception "请求错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||
render_ok(count: res["data"]["total"], data: res["data"]["list"])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_ob_repository_sync
|
||||
@ob_repository_sync = ObRepositorySync.find_by(project_id: @project.id)
|
||||
end
|
||||
|
||||
def authenticate_user!
|
||||
return if @project.member?(current_user) || current_user.admin?
|
||||
render_forbidden('你没有权限操作')
|
||||
end
|
||||
end
|
|
@ -4,12 +4,14 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
|
|||
|
||||
def index
|
||||
@organization_users = @organization.organization_users.includes(:user)
|
||||
search = params[:search].to_s.downcase
|
||||
user_condition_users = User.like(search).to_sql
|
||||
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
|
||||
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
|
||||
|
||||
@organization_users = @organization_users.where(user_id: users).distinct
|
||||
if params[:search].present?
|
||||
search = params[:search].to_s.downcase
|
||||
user_condition_users = User.like(search).to_sql
|
||||
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
|
||||
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
|
||||
|
||||
@organization_users = @organization_users.where(user_id: users).distinct
|
||||
end
|
||||
|
||||
@organization_users = kaminari_paginate(@organization_users)
|
||||
end
|
||||
|
|
|
@ -31,6 +31,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
Organizations::CreateForm.new(organization_params.merge(original_name: "")).validate!
|
||||
@organization = Organizations::CreateService.call(current_user, organization_params)
|
||||
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
||||
Cache::V2::OwnerCommonService.new(@organization.id).reset
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
|
@ -45,9 +46,16 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
|
||||
@organization.save!
|
||||
sync_organization_extension!
|
||||
# 更改组织可见性为私有,则需将该组织下的所有仓库同步更改为私有仓库
|
||||
if organization_extension_params[:visibility] == "privacy"
|
||||
Project.where(user_id: @organization.id).where(is_public: true).each do |project|
|
||||
update_project_private(project)
|
||||
end
|
||||
end
|
||||
|
||||
Gitea::Organization::UpdateService.call(current_user.gitea_token, login, @organization.reload)
|
||||
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
||||
Cache::V2::OwnerCommonService.new(@organization.id).reset
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
|
@ -121,5 +129,20 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
def sync_organization_extension!
|
||||
@organization.organization_extension.update_attributes!(organization_extension_params)
|
||||
end
|
||||
|
||||
def update_project_private(project)
|
||||
project.update_attributes!(is_public: false)
|
||||
project.forked_projects.update_all(is_public: project.is_public)
|
||||
gitea_params = {
|
||||
private: true,
|
||||
default_branch: project.default_branch,
|
||||
website: project.website,
|
||||
name: project.identifier
|
||||
}
|
||||
gitea_repo = Gitea::Repository::UpdateService.call(@organization, project&.repository&.identifier, gitea_params)
|
||||
project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
|
||||
# 更新对应所属分类下的项目数量(私有)
|
||||
project.project_category.decrement!(:private_projects_count, 1) if project.project_category.present?
|
||||
end
|
||||
|
||||
end
|
|
@ -21,6 +21,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
|||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def create_all
|
||||
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||
ActiveRecord::Base.transaction do
|
||||
@organization.projects.each do |project|
|
||||
TeamProject.build(@organization.id, @team.id, project.id)
|
||||
end
|
||||
Gitea::Organization::TeamProject::CreateAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
|
||||
render_ok
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||
ActiveRecord::Base.transaction do
|
||||
|
@ -33,6 +44,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
|||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def destroy_all
|
||||
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||
ActiveRecord::Base.transaction do
|
||||
@team.team_projects.each do |project|
|
||||
project.destroy!
|
||||
end
|
||||
Gitea::Organization::TeamProject::DeleteAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
|
||||
render_ok
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def load_organization
|
||||
@organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id])
|
||||
|
@ -47,7 +69,7 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
|||
end
|
||||
|
||||
def load_operate_project
|
||||
@operate_project = Project.find_by(id: project_mark) || Project.find_by(identifier: project_mark)
|
||||
@operate_project = @organization.projects.where(id: project_mark).take || @organization.projects.where(identifier: project_mark).take
|
||||
tip_exception("项目不存在") if @operate_project.nil?
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class OwnersController < ApplicationController
|
|||
|
||||
def show
|
||||
@owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
|
||||
return render_ok(type: 'User') unless @owner.present?
|
||||
return render_not_found unless @owner.present?
|
||||
# 组织
|
||||
if @owner.is_a?(Organization)
|
||||
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition
|
||||
|
|
|
@ -10,7 +10,7 @@ class ProjectCategoriesController < ApplicationController
|
|||
end
|
||||
|
||||
def group_list
|
||||
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
|
||||
@project_categories = ProjectCategory.select("id, name, projects_count, private_projects_count, (projects_count - private_projects_count) as public_projects_count").having('public_projects_count > 0').order(public_projects_count: :desc)
|
||||
# projects = Project.no_anomory_projects.visible
|
||||
# @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size
|
||||
end
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
class ProjectRankController < ApplicationController
|
||||
# 根据时间获取热门项目
|
||||
def index
|
||||
$redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names)
|
||||
$redis_cache.zunionstore("recent-days-project-rank-#{time}", get_timeable_key_names)
|
||||
deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
|
||||
$redis_cache.zrem("recent-days-project-rank", deleted_data) unless deleted_data.blank?
|
||||
@project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true)
|
||||
$redis_cache.zrem("recent-days-project-rank-#{time}", deleted_data) unless deleted_data.blank?
|
||||
@project_rank = $redis_cache.zrevrange("recent-days-project-rank-#{time}", 0, 9, withscores: true)
|
||||
rescue Exception => e
|
||||
@project_rank = []
|
||||
end
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
class Projects::ProjectInviteLinksController < Projects::BaseController
|
||||
before_action :require_manager!, except: [:show_link, :redirect_link]
|
||||
before_action :require_login
|
||||
|
||||
def current_link
|
||||
role = params[:role]
|
||||
is_apply = params[:is_apply]
|
||||
return render_error('请输入正确的参数!') unless role.present? && is_apply.present?
|
||||
@project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id, role: role, is_apply: is_apply)
|
||||
@project_invite_link = ProjectInviteLink.build!(@project, current_user, role, is_apply) unless @project_invite_link.present?
|
||||
end
|
||||
|
||||
def generate_link
|
||||
ActiveRecord::Base.transaction do
|
||||
params_data = link_params.merge({user_id: current_user.id, project_id: @project.id})
|
||||
Projects::ProjectInviteLinks::CreateForm.new(params_data).validate!
|
||||
@project_invite_link = ProjectInviteLink.build!(project, user, params_data[:role], params_data[:is_apply])
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def show_link
|
||||
@project_invite_link = ProjectInviteLink.find_by(sign: params[:invite_sign])
|
||||
return render_not_found unless @project_invite_link.present?
|
||||
end
|
||||
|
||||
def redirect_link
|
||||
Projects::LinkJoinService.call(current_user, @project, params[:invite_sign])
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
normal_status(-1, e.message)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def link_params
|
||||
params.require(:project_invite_link).permit(:role, :is_apply)
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ class Projects::WebhooksController < Projects::BaseController
|
|||
|
||||
def create
|
||||
ActiveRecord::Base.transaction do
|
||||
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19
|
||||
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
|
||||
return render_error("参数错误.") unless webhook_params.present?
|
||||
form = Projects::Webhooks::CreateForm.new(webhook_params)
|
||||
return render json: {status: -1, message: form.errors} unless form.validate!
|
||||
|
|
|
@ -22,6 +22,7 @@ class ProjectsController < ApplicationController
|
|||
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge?
|
||||
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
|
||||
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
|
||||
menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && (current_user.admin? || @project.member?(current_user.id))
|
||||
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
|
||||
menu.append(menu_hash_by_name("activity"))
|
||||
menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge?
|
||||
|
@ -39,8 +40,9 @@ class ProjectsController < ApplicationController
|
|||
category_id = params[:category_id]
|
||||
@total_count =
|
||||
if category_id.blank?
|
||||
ps = ProjectStatistic.first
|
||||
ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
|
||||
# ps = ProjectStatistic.first
|
||||
# ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
|
||||
@projects.total_count
|
||||
else
|
||||
cate = ProjectCategory.find_by(id: category_id)
|
||||
cate&.projects_count || 0
|
||||
|
@ -51,7 +53,7 @@ class ProjectsController < ApplicationController
|
|||
ActiveRecord::Base.transaction do
|
||||
Projects::CreateForm.new(project_params).validate!
|
||||
@project = Projects::CreateService.new(current_user, project_params).call
|
||||
|
||||
OpenProjectDevOpsJob.perform_later(@project&.id, current_user.id)
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
|
@ -153,6 +155,15 @@ class ProjectsController < ApplicationController
|
|||
}
|
||||
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
|
||||
@project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
|
||||
# 更新对应所属分类下的项目数量(私有)
|
||||
before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public
|
||||
after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public
|
||||
before_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][0] : @project.project_category_id
|
||||
after_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][1] : @project.project_category_id
|
||||
before_pc = ProjectCategory.find_by_id(before_pc_id)
|
||||
after_pc = ProjectCategory.find_by_id(after_pc_id)
|
||||
before_pc.decrement!(:private_projects_count, 1) if before_pc.present? && !before_is_public
|
||||
after_pc.increment!(:private_projects_count, 1) if after_pc.present? && !after_is_public
|
||||
end
|
||||
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
|
||||
end
|
||||
|
@ -170,6 +181,8 @@ class ProjectsController < ApplicationController
|
|||
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
|
||||
@project.destroy!
|
||||
@project.forked_projects.update_all(forked_from_project_id: nil)
|
||||
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||
@project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
|
||||
render_ok
|
||||
end
|
||||
else
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class PublicKeysController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :require_login_cloud_ide_saas
|
||||
before_action :find_public_key, only: [:destroy]
|
||||
|
||||
def index
|
||||
|
@ -61,4 +61,6 @@ class PublicKeysController < ApplicationController
|
|||
def find_public_key
|
||||
@public_key = current_user.public_keys.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -6,6 +6,8 @@ class PullRequestsController < ApplicationController
|
|||
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
|
||||
before_action :load_pull_request, only: [:files, :commits]
|
||||
before_action :find_atme_receivers, only: [:create, :update]
|
||||
|
||||
skip_after_action :user_trace_log, only: [:update]
|
||||
include TagChosenHelper
|
||||
include ApplicationHelper
|
||||
|
||||
|
@ -56,12 +58,19 @@ class PullRequestsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
|
||||
if params[:fork_project_id].present?
|
||||
fork_project= Project.find_by(id: params[:fork_project_id])
|
||||
return normal_status(-1, "您不是源项目开发者,没有权限,请联系源项目管理员.") unless fork_project && fork_project.operator?(current_user)
|
||||
else
|
||||
return normal_status(-1, "您不是项目开发者,没有权限,请联系项目管理员.") unless @project.operator?(current_user)
|
||||
end
|
||||
ActiveRecord::Base.transaction do
|
||||
Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
|
||||
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
|
||||
if @gitea_pull_request[:status] == :success
|
||||
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
|
||||
reviewers = User.where(id: params[:reviewer_ids])
|
||||
@pull_request.reviewers = reviewers
|
||||
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
||||
SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
||||
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
|
||||
|
@ -103,22 +112,16 @@ class PullRequestsController < ApplicationController
|
|||
Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
|
||||
merge_params
|
||||
|
||||
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
|
||||
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
|
||||
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
|
||||
return normal_status(-1, "最多只能创建一个标记。")
|
||||
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
|
||||
@issue&.issue_tags_relates&.destroy_all
|
||||
params[:issue_tag_ids].each do |tag|
|
||||
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
|
||||
end
|
||||
else
|
||||
return normal_status(-1, "请输入正确的标记。")
|
||||
end
|
||||
end
|
||||
reviewers = User.where(id: params[:reviewer_ids])
|
||||
@pull_request.reviewers = reviewers
|
||||
|
||||
old_issue_value = old_value_to_hash(@issue, @issue_params)
|
||||
old_pr_value = old_value_to_hash(@pull_request, @local_params.compact)
|
||||
old_value = {issue: old_issue_value, pull_request: old_pr_value}
|
||||
|
||||
if @issue.update_attributes(@issue_params)
|
||||
if @pull_request.update_attributes(@local_params.compact)
|
||||
user_trace_update_log(old_value)
|
||||
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
|
||||
@pull_request.gitea_number, @requests_params, current_user.gitea_token)
|
||||
|
||||
|
@ -133,7 +136,7 @@ class PullRequestsController < ApplicationController
|
|||
end
|
||||
else
|
||||
return normal_status(-1, "请输入正确的标记。")
|
||||
end
|
||||
end
|
||||
end
|
||||
if params[:status_id].to_i == 5
|
||||
@issue.issue_times.update_all(end_time: Time.now)
|
||||
|
@ -163,8 +166,6 @@ class PullRequestsController < ApplicationController
|
|||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
|
||||
<<<<<<< HEAD
|
||||
colsed === true ? normal_status(1, "已拒绝") : normal_status(-1, '合并失败')
|
||||
# author: zxh
|
||||
# 调用上链API
|
||||
success_blockchain = push_activity_2_blockchain("pull_request_refuse", @pull_request)
|
||||
|
@ -172,14 +173,14 @@ class PullRequestsController < ApplicationController
|
|||
normal_status(-1, "拒绝失败")
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
=======
|
||||
if colsed === true
|
||||
if colsed === true
|
||||
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
|
||||
# 合并请求下issue处理为关闭
|
||||
@issue&.update_attributes!({status_id:5})
|
||||
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
||||
normal_status(1, "已拒绝")
|
||||
else
|
||||
normal_status(-1, '合并失败')
|
||||
>>>>>>> upstream/master
|
||||
end
|
||||
rescue => e
|
||||
normal_status(-1, e.message)
|
||||
|
@ -197,6 +198,7 @@ class PullRequestsController < ApplicationController
|
|||
@issue_assign_to = @issue.get_assign_user
|
||||
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
|
||||
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
|
||||
@last_review = @pull_request.reviews.take
|
||||
end
|
||||
|
||||
def pr_merge
|
||||
|
@ -220,7 +222,6 @@ class PullRequestsController < ApplicationController
|
|||
# @pull_request.project_trend_status!
|
||||
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
|
||||
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
|
||||
<<<<<<< HEAD
|
||||
|
||||
# author: zxh
|
||||
# 调用上链API
|
||||
|
@ -267,10 +268,11 @@ class PullRequestsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
=======
|
||||
|
||||
# 合并请求下issue处理为关闭
|
||||
@issue&.update_attributes!({status_id:5})
|
||||
SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
||||
normal_status(1, "合并成功")
|
||||
>>>>>>> upstream/master
|
||||
else
|
||||
normal_status(-1, result.message)
|
||||
end
|
||||
|
@ -332,7 +334,7 @@ class PullRequestsController < ApplicationController
|
|||
|
||||
def get_relatived
|
||||
@project_tags = @project.issue_tags&.select(:id,:name, :color).as_json
|
||||
@project_versions = @project.versions&.select(:id,:name, :status).as_json
|
||||
@project_versions = @project.versions.opening&.select(:id,:name, :status).as_json
|
||||
@project_members = @project.all_developers
|
||||
@project_priories = IssuePriority&.select(:id,:name, :position).as_json
|
||||
end
|
||||
|
|
|
@ -1,390 +1,407 @@
|
|||
class RepositoriesController < ApplicationController
|
||||
include RepositoriesHelper
|
||||
include ApplicationHelper
|
||||
include OperateProjectAbilityAble
|
||||
include Repository::LanguagesPercentagable
|
||||
|
||||
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
|
||||
before_action :require_profile_completed, only: [:create_file]
|
||||
before_action :load_repository
|
||||
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
|
||||
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
|
||||
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
|
||||
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
|
||||
before_action :get_statistics, only: %i[top_counts]
|
||||
|
||||
def files
|
||||
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
|
||||
render json: result
|
||||
end
|
||||
|
||||
# 新版项目详情
|
||||
def detail
|
||||
@user = current_user
|
||||
@result = Repositories::DetailService.call(@owner, @repository, @user)
|
||||
@project_fork_id = @project.try(:forked_from_project_id)
|
||||
if @project_fork_id.present?
|
||||
@fork_project = Project.find_by(id: @project_fork_id)
|
||||
@fork_project_user = @fork_project.owner
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def show
|
||||
@user = current_user
|
||||
@repo = @project.repository
|
||||
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
|
||||
@project_fork_id = @project.try(:forked_from_project_id)
|
||||
if @project_fork_id.present?
|
||||
@fork_project = Project.find_by(id: @project_fork_id)
|
||||
@fork_project_user = @fork_project.owner
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def entries
|
||||
@project.increment!(:visits)
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
|
||||
if @project.educoder?
|
||||
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
|
||||
else
|
||||
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
|
||||
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
|
||||
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
||||
end
|
||||
end
|
||||
|
||||
def top_counts
|
||||
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
|
||||
end
|
||||
|
||||
def sub_entries
|
||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||
|
||||
if @project.educoder?
|
||||
if params[:type] === 'file'
|
||||
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
|
||||
logger.info "######### sub_entries: #{@sub_entries}"
|
||||
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
|
||||
|
||||
tmp_entries = {
|
||||
"content" => @sub_entries['data']['content'],
|
||||
"type" => "blob"
|
||||
}
|
||||
@sub_entries = {
|
||||
"trees"=>tmp_entries,
|
||||
"commits" => [{}]
|
||||
}
|
||||
else
|
||||
begin
|
||||
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
|
||||
if @sub_entries.blank? || @sub_entries['status'].to_i === -1
|
||||
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
|
||||
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
|
||||
tmp_entries = {
|
||||
"content" => @sub_entries['data']['content'],
|
||||
"type" => "blob"
|
||||
}
|
||||
@sub_entries = {
|
||||
"trees"=>tmp_entries,
|
||||
"commits" => [{}]
|
||||
}
|
||||
end
|
||||
rescue
|
||||
return render_error('该文件暂未开放,敬请期待.')
|
||||
end
|
||||
end
|
||||
else
|
||||
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
||||
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
|
||||
if interactor.success?
|
||||
result = interactor.result
|
||||
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def commits
|
||||
if @project.educoder?
|
||||
@commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name)
|
||||
else
|
||||
if params[:filepath].present?
|
||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||
@hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri,
|
||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
||||
else
|
||||
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
|
||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def commits_slice
|
||||
@hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier,
|
||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def commit
|
||||
@sha = params[:sha]
|
||||
if @project.educoder?
|
||||
return render_error('暂未开放,敬请期待.')
|
||||
else
|
||||
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
|
||||
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true})
|
||||
end
|
||||
end
|
||||
|
||||
def tags
|
||||
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
|
||||
|
||||
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||
end
|
||||
|
||||
def contributors
|
||||
if params[:filepath].present? || @project.educoder?
|
||||
@contributors = []
|
||||
else
|
||||
result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
|
||||
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||
end
|
||||
rescue
|
||||
@contributors = []
|
||||
end
|
||||
|
||||
def edit
|
||||
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
|
||||
end
|
||||
|
||||
def create_file
|
||||
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
# create_new_pr(params)
|
||||
#如果是更新流水线文件
|
||||
if params[:pipeline_id]
|
||||
update_pipeline(params[:pipeline_id])
|
||||
end
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def update_pipeline(pipeline_id)
|
||||
pipeline = Ci::Pipeline.find(pipeline_id)
|
||||
if pipeline
|
||||
pipeline.update!(sync: 1)
|
||||
end
|
||||
end
|
||||
|
||||
def update_file
|
||||
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
# TODO: 是否创建pr
|
||||
# create_new_pr(params)
|
||||
render_result(1, "更新成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file
|
||||
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
render_result(1, "文件删除成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def repo_hook
|
||||
|
||||
end
|
||||
|
||||
def sync_mirror
|
||||
return render_error("正在镜像中..") if @repository.mirror.waiting?
|
||||
|
||||
@repository.sync_mirror!
|
||||
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def readme
|
||||
if params[:filepath].present?
|
||||
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
|
||||
else
|
||||
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
|
||||
end
|
||||
@path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
|
||||
@readme = result[:status] === :success ? result[:body] : nil
|
||||
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
||||
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/#{Addressable::URI.escape(params[:archive])}"
|
||||
|
||||
file_path = [domain, api_url, archive_url].join
|
||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
|
||||
|
||||
return render_not_found if !request.format.zip? && !request.format.gzip?
|
||||
|
||||
redirect_to file_path
|
||||
end
|
||||
|
||||
def raw
|
||||
domain = Gitea.gitea_config[:domain]
|
||||
api_url = Gitea.gitea_config[:base_url]
|
||||
|
||||
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
|
||||
file_path = [domain, api_url, url].join
|
||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&")
|
||||
|
||||
redirect_to file_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_project
|
||||
@project = Project.find params[:id]
|
||||
render_not_found("未找到相关的仓库") unless @project
|
||||
end
|
||||
|
||||
def find_project_with_includes
|
||||
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
|
||||
end
|
||||
|
||||
def authorizate!
|
||||
return if current_user && current_user.admin?
|
||||
if @project.repository.hidden? && !@project.member?(current_user)
|
||||
render_forbidden
|
||||
end
|
||||
end
|
||||
|
||||
# TODO 获取最新commit信息
|
||||
def project_commits
|
||||
if params[:filepath].present?
|
||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||
Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri,
|
||||
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||
else
|
||||
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
|
||||
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||
end
|
||||
end
|
||||
|
||||
def get_statistics
|
||||
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
|
||||
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
|
||||
end
|
||||
|
||||
def get_ref
|
||||
@ref = params[:ref] || @project&.default_branch
|
||||
end
|
||||
|
||||
def get_latest_commit
|
||||
latest_commit = @project.educoder? ? nil : project_commits
|
||||
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
|
||||
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
|
||||
end
|
||||
|
||||
def content_params
|
||||
{
|
||||
filepath: params[:filepath],
|
||||
branch: params[:branch],
|
||||
new_branch: params[:new_branch],
|
||||
content: params[:content],
|
||||
message: params[:message],
|
||||
committer: {
|
||||
email: current_user.mail,
|
||||
name: current_user.login
|
||||
},
|
||||
identifier: @project.identifier
|
||||
}
|
||||
end
|
||||
|
||||
def hook_params(hook_type, params)
|
||||
# if hook_type == "push"
|
||||
# # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算
|
||||
# uploadPushInfo = {
|
||||
# "sha": params["commits"].present? ? params["commits"].last : "",
|
||||
# "branch": params["ref"].to_s.split("/").last,
|
||||
# "modification_lines": params["commits"].length
|
||||
# }
|
||||
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
|
||||
# uploadPushInfo = {
|
||||
# "branch": params["base"]["ref"].to_s.split("/").last,
|
||||
# "sha": params["pull_request"]["merge_base"],
|
||||
# "modification_lines": 1 #pull_request中没有commits数量
|
||||
# }
|
||||
# else
|
||||
# uploadPushInfo = {}
|
||||
# end
|
||||
|
||||
# uploadPushInfo
|
||||
end
|
||||
|
||||
def create_new_pr(params)
|
||||
if params[:new_branch].present? && params[:new_branch] != params[:branch]
|
||||
local_params = {
|
||||
title: params[:message], #标题
|
||||
body: params[:content], #内容
|
||||
head: params[:new_branch], #源分支
|
||||
base: params[:branch], #目标分支
|
||||
milestone: 0 #里程碑,未与本地的里程碑关联
|
||||
|
||||
}
|
||||
requests_params = local_params.merge({
|
||||
assignee: current_user.try(:login),
|
||||
assignees: [],
|
||||
labels: [],
|
||||
due_date: Time.now
|
||||
})
|
||||
|
||||
issue_params = {
|
||||
author_id: current_user.id,
|
||||
project_id: @project.id,
|
||||
subject: params[:message],
|
||||
description: params[:content],
|
||||
assigned_to_id: nil,
|
||||
fixed_version_id: nil,
|
||||
issue_tags_value: nil,
|
||||
issue_classify: "pull_request",
|
||||
issue_type: "1",
|
||||
tracker_id: 2,
|
||||
status_id: 1,
|
||||
priority_id: params[:priority_id] || "2"
|
||||
}
|
||||
@pull_issue = Issue.new(issue_params)
|
||||
if @pull_issue.save!
|
||||
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
|
||||
if local_requests.save
|
||||
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
|
||||
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
|
||||
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
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 files 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
|
||||
@week_project_visit_record, @month_project_visit_record = TimeableVisitRecord.build(@project.id)
|
||||
if @week_project_visit_record.visits < 300 && @month_project_visit_record.visits < 1000
|
||||
@week_project_visit_record.increment!(:visits)
|
||||
@month_project_visit_record.increment!(:visits)
|
||||
@project.increment!(:visits)
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
|
||||
end
|
||||
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 = GiteaService.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 = GiteaService.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})
|
||||
render_error(@commit[:message], @commit[:status]) if @commit.has_key?(:status) || @commit_diff.has_key?(:status)
|
||||
end
|
||||
end
|
||||
|
||||
def tags
|
||||
if params[:only_name].present?
|
||||
result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
|
||||
|
||||
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||
else
|
||||
name_result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
|
||||
|
||||
@tag_names = result.is_a?(Hash) && result.key?(:status) ? [] : name_result
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
def contributors
|
||||
if params[:filepath].present? || @project.educoder?
|
||||
@contributors = []
|
||||
else
|
||||
result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
|
||||
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||
end
|
||||
rescue
|
||||
@contributors = []
|
||||
end
|
||||
|
||||
def edit
|
||||
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
|
||||
end
|
||||
|
||||
def create_file
|
||||
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
# create_new_pr(params)
|
||||
#如果是更新流水线文件
|
||||
if params[:pipeline_id]
|
||||
update_pipeline(params[:pipeline_id])
|
||||
end
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def update_pipeline(pipeline_id)
|
||||
pipeline = Ci::Pipeline.find(pipeline_id)
|
||||
if pipeline
|
||||
pipeline.update!(sync: 1)
|
||||
end
|
||||
end
|
||||
|
||||
def update_file
|
||||
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
# TODO: 是否创建pr
|
||||
# create_new_pr(params)
|
||||
render_result(1, "更新成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file
|
||||
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||
if interactor.success?
|
||||
@file = interactor.result
|
||||
render_result(1, "文件删除成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def repo_hook
|
||||
|
||||
end
|
||||
|
||||
def sync_mirror
|
||||
return render_error("正在镜像中..") if @repository.mirror.waiting?
|
||||
|
||||
@repository.sync_mirror!
|
||||
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def readme
|
||||
if params[:filepath].present?
|
||||
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
|
||||
else
|
||||
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
|
||||
end
|
||||
@path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
|
||||
@readme = result[:status] === :success ? result[:body] : nil
|
||||
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
||||
@readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
||||
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
|
||||
rescue
|
||||
render json: nil
|
||||
end
|
||||
|
||||
def languages
|
||||
if @project.educoder?
|
||||
render json: {}
|
||||
else
|
||||
render json: languages_precentagable
|
||||
end
|
||||
end
|
||||
|
||||
def archive
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
api_url = GiteaService.gitea_config[:base_url]
|
||||
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
|
||||
|
||||
file_path = [domain, api_url, archive_url].join
|
||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
|
||||
|
||||
return render_not_found if !request.format.zip? && !request.format.gzip?
|
||||
|
||||
redirect_to file_path
|
||||
end
|
||||
|
||||
def raw
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
api_url = GiteaService.gitea_config[:base_url]
|
||||
|
||||
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
|
||||
file_path = [domain, api_url, url].join
|
||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&")
|
||||
|
||||
redirect_to file_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_project
|
||||
@project = Project.find params[:id]
|
||||
render_not_found("未找到相关的仓库") unless @project
|
||||
end
|
||||
|
||||
def find_project_with_includes
|
||||
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
|
||||
end
|
||||
|
||||
def authorizate!
|
||||
return if current_user && current_user.admin?
|
||||
if @project.repository.hidden? && !@project.member?(current_user)
|
||||
render_forbidden
|
||||
end
|
||||
end
|
||||
|
||||
# TODO 获取最新commit信息
|
||||
def project_commits
|
||||
if params[:filepath].present?
|
||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||
Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri,
|
||||
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||
else
|
||||
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
|
||||
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||
end
|
||||
end
|
||||
|
||||
def get_statistics
|
||||
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
|
||||
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
|
||||
end
|
||||
|
||||
def get_ref
|
||||
@ref = params[:ref] || @project&.default_branch
|
||||
end
|
||||
|
||||
def get_latest_commit
|
||||
latest_commit = @project.educoder? ? nil : project_commits
|
||||
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
|
||||
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
|
||||
end
|
||||
|
||||
def content_params
|
||||
{
|
||||
filepath: params[:filepath],
|
||||
branch: params[:branch],
|
||||
new_branch: params[:new_branch],
|
||||
content: params[:content],
|
||||
message: params[:message],
|
||||
committer: {
|
||||
email: current_user.mail,
|
||||
name: current_user.login
|
||||
},
|
||||
identifier: @project.identifier
|
||||
}
|
||||
end
|
||||
|
||||
def hook_params(hook_type, params)
|
||||
# if hook_type == "push"
|
||||
# # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算
|
||||
# uploadPushInfo = {
|
||||
# "sha": params["commits"].present? ? params["commits"].last : "",
|
||||
# "branch": params["ref"].to_s.split("/").last,
|
||||
# "modification_lines": params["commits"].length
|
||||
# }
|
||||
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
|
||||
# uploadPushInfo = {
|
||||
# "branch": params["base"]["ref"].to_s.split("/").last,
|
||||
# "sha": params["pull_request"]["merge_base"],
|
||||
# "modification_lines": 1 #pull_request中没有commits数量
|
||||
# }
|
||||
# else
|
||||
# uploadPushInfo = {}
|
||||
# end
|
||||
|
||||
# uploadPushInfo
|
||||
end
|
||||
|
||||
def create_new_pr(params)
|
||||
if params[:new_branch].present? && params[:new_branch] != params[:branch]
|
||||
local_params = {
|
||||
title: params[:message], #标题
|
||||
body: params[:content], #内容
|
||||
head: params[:new_branch], #源分支
|
||||
base: params[:branch], #目标分支
|
||||
milestone: 0 #里程碑,未与本地的里程碑关联
|
||||
|
||||
}
|
||||
requests_params = local_params.merge({
|
||||
assignee: current_user.try(:login),
|
||||
assignees: [],
|
||||
labels: [],
|
||||
due_date: Time.now
|
||||
})
|
||||
|
||||
issue_params = {
|
||||
author_id: current_user.id,
|
||||
project_id: @project.id,
|
||||
subject: params[:message],
|
||||
description: params[:content],
|
||||
assigned_to_id: nil,
|
||||
fixed_version_id: nil,
|
||||
issue_tags_value: nil,
|
||||
issue_classify: "pull_request",
|
||||
issue_type: "1",
|
||||
tracker_id: 2,
|
||||
status_id: 1,
|
||||
priority_id: params[:priority_id] || "2"
|
||||
}
|
||||
@pull_issue = Issue.new(issue_params)
|
||||
if @pull_issue.save!
|
||||
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
|
||||
if local_requests.save
|
||||
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
|
||||
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
|
||||
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class ReviewsController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :load_project
|
||||
before_action :load_pull_request
|
||||
|
||||
def create
|
||||
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
|
||||
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
||||
end
|
||||
|
||||
private
|
||||
def review_params
|
||||
params.require(:review).permit(:content, :commit_id, :status)
|
||||
end
|
||||
|
||||
def load_pull_request
|
||||
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
end
|
|
@ -1,24 +1,26 @@
|
|||
class SettingsController < ApplicationController
|
||||
def show
|
||||
@old_projects_url = nil
|
||||
@old_projects_url = "https://www.trustie.net/users/#{current_user.try(:login)}/projects" if User.current.logged?
|
||||
get_navbar
|
||||
get_add_menu
|
||||
get_common_menu
|
||||
get_sub_competitions
|
||||
get_personal_menu
|
||||
get_third_party
|
||||
get_third_party_new
|
||||
get_top_system_notification
|
||||
end
|
||||
|
||||
private
|
||||
def get_navbar
|
||||
def get_navbar
|
||||
@navbar = default_laboratory.navbar
|
||||
if User.current.logged?
|
||||
pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false}
|
||||
@navbar << pernal_index
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def get_add_menu
|
||||
@add = []
|
||||
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
|
||||
|
@ -67,7 +69,25 @@ class SettingsController < ApplicationController
|
|||
url: EducoderOauth.oauth_url
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def get_third_party_new
|
||||
@third_party_new = []
|
||||
@third_party_new << {
|
||||
name: 'educoder',
|
||||
url: EducoderOauth.oauth_url,
|
||||
method: 'get'
|
||||
}
|
||||
platform_url = Rails.application.config_for(:configuration)['platform_url']
|
||||
config = Rails.application.config_for(:configuration)
|
||||
(config.dig("oauth").keys - ["educoder", "wechat"]).each do |provider|
|
||||
@third_party_new << {
|
||||
name: provider,
|
||||
url: "#{platform_url}/auth/#{provider}",
|
||||
method: 'get'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def get_top_system_notification
|
||||
@top_system_notification = SystemNotification.is_top.first
|
||||
end
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
class SponsorTiersController < ApplicationController
|
||||
before_action :set_sponsor_tier, only: [:show, :edit, :update, :destroy]
|
||||
before_action :check_sponsor, only: [:show]
|
||||
before_action :require_login, only: [:create, :update, :destroy]
|
||||
|
||||
# GET /sponsor_tiers
|
||||
# GET /sponsor_tiers.json
|
||||
def index
|
||||
# @sponsor_tiers = SponsorTier.all
|
||||
user = User.find_by_login(params[:login])
|
||||
@sponsor_tiers = user.sponsor_tier
|
||||
end
|
||||
|
||||
# GET /sponsor_tiers/1
|
||||
# GET /sponsor_tiers/1.json
|
||||
def show
|
||||
|
||||
end
|
||||
|
||||
# POST /sponsor_tiers
|
||||
# POST /sponsor_tiers.json
|
||||
def create
|
||||
# print("------------\n", sponsor_tier_params, "\n------------\n")
|
||||
@check_sponsorship = nil
|
||||
@sponsor_tier = SponsorTier.new(sponsor_tier_params)
|
||||
respond_to do |format|
|
||||
if @sponsor_tier.user_id == User.current.id && @sponsor_tier.save
|
||||
format.html { redirect_to @sponsor_tier, notice: 'Sponsor tier was successfully created.' }
|
||||
format.json { render :show, status: :created, location: @sponsor_tier }
|
||||
# render json: {status: 1, message: '创建成功' }
|
||||
else
|
||||
format.html { render :new }
|
||||
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /sponsor_tiers/1
|
||||
# PATCH/PUT /sponsor_tiers/1.json
|
||||
def update
|
||||
@check_sponsorship = nil
|
||||
old_value = old_value_to_hash(@sponsor_tier, params)
|
||||
respond_to do |format|
|
||||
if User.current.id == @sponsor_tier.user_id && @sponsor_tier.update(sponsor_tier_update_params)
|
||||
user_trace_update_log(old_value)
|
||||
format.html { redirect_to @sponsor_tier, notice: 'Sponsor tier was successfully updated.' }
|
||||
format.json { render :show, status: :ok, location: @sponsor_tier }
|
||||
# render json: {status: 1, message: '修改成功' }
|
||||
else
|
||||
format.html { render :edit }
|
||||
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
|
||||
# format.json { render status: :unprocessable_entity }
|
||||
# render json: {status: -1, message: '修改失败' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /sponsor_tiers/1
|
||||
# DELETE /sponsor_tiers/1.json
|
||||
def destroy
|
||||
if User.current.id == @sponsor_tier.user_id
|
||||
@sponsor_tier.destroy
|
||||
respond_to do |format|
|
||||
format.html { redirect_to sponsor_tiers_url, notice: 'Sponsor tier was successfully destroyed.' }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
else
|
||||
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def check_sponsor
|
||||
@check_sponsorship = Sponsorship.where("sponsor_id=? AND developer_id=?", current_user.id, @sponsor_tier.user.id)
|
||||
end
|
||||
|
||||
def set_sponsor_tier
|
||||
@sponsor_tier = SponsorTier.find(params[:id])
|
||||
end
|
||||
|
||||
def sponsor_tier_update_params
|
||||
params.require(:sponsor_tier).permit(:tier, :description)
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def sponsor_tier_params
|
||||
params.require(:sponsor_tier).permit(:tier, :user_id, :description)
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue