Compare commits

..

110 Commits

Author SHA1 Message Date
xiaoxiaoqiong fccaa476e4 educoder修改邮箱和密码同步 2021-12-17 10:46:13 +08:00
yystopf 807e91a839 fix 2021-11-05 17:37:55 +08:00
yystopf 13497ae6dc add: setting of engineer_url 2021-11-05 17:05:28 +08:00
jasder 9955619398 Merge pull request 'FIX WIP' (#221) from jasder/forgeplus:dev_educoder into dev_educoder 2021-10-23 16:10:32 +08:00
jasder ae2a2725f7 FIX conflict 2021-10-23 16:09:35 +08:00
jasder 6220d851ae FIX 合并主干分支代码以及解决代码冲突 2021-10-23 16:06:49 +08:00
yystopf d2e18d9c0c fix merge from develop 2021-09-18 10:43:35 +08:00
jasder 039ca21f30 Merge pull request 'FIX merge develop' (#144) from develop into dev_educoder 2021-09-09 09:44:44 +08:00
jasder cbc74e4709 Merge pull request 'Fix 路由规范化' (#141) from jasder/forgeplus:dev_educoder into dev_educoder 2021-09-06 14:18:33 +08:00
jasder fd4806012d FIX 合并develop主干代码(平台路由规范化) 2021-09-06 14:16:38 +08:00
jasder 4825c910f0 FIX merge develop conflict 2021-08-27 16:12:14 +08:00
viletyy ace13abe92 fix: 合并请求对比代码返回合并信息 2021-07-12 18:45:35 +08:00
jasder e8da6364d8 Merge branch 'develop' into dev_educoder 2021-07-12 16:16:59 +08:00
jasder a7e20dcae2 FIX 解决用户同步问题 2021-07-09 17:53:14 +08:00
jasder 06e24a8ea4 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-07-09 16:58:04 +08:00
jasder 070df3c9dd FIX 解决私有版本库库不能访问、下载图片的问题 2021-07-09 16:57:37 +08:00
viletyy 7c0bc5d444 add: create project owner login 2021-07-07 15:51:05 +08:00
jasder 6ebab1be66 FIX delete gantt、sonar tab 2021-07-07 09:13:40 +08:00
jasder 27f510e6c9 ADD loger info for create gitea user method 2021-07-07 00:07:01 +08:00
jasder d9a27b7728 ADD gantt, sonar menu for menu_list api 2021-07-06 15:49:26 +08:00
jasder 68f1d7f7f6 ADD 项目tab中添加 甘特图和质量分析/检测标识 2021-07-06 15:41:18 +08:00
jasder 7e3517d873 FIX show realname for create project 2021-07-06 11:04:25 +08:00
jasder 877ef54b24 FIX bug 2021-07-06 10:43:55 +08:00
jasder 133eed6afe FIX 合并代码、重构优化gitea 用户注册api 2021-07-05 16:19:23 +08:00
jasder eba2df5a2d Merge branch 'educoder_server' into dev_educoder 2021-07-05 15:21:23 +08:00
jasder 85a37fdbcc Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 10:05:01 +08:00
jasder a62b29a263 Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 10:00:10 +08:00
jasder 0eccafcb69 Merge branch 'feature/pull_conflict_files' into dev_educoder 2021-06-28 09:39:39 +08:00
jasder 0dbed862a7 Merge branch 'develop' into dev_educoder 2021-06-27 21:46:35 +08:00
jasder dfc998a9cc Merge branch 'develop' into dev_educoder 2021-06-18 17:47:59 +08:00
jasder 8be4bc823c Merge branch 'develop' into dev_educoder 2021-06-17 17:31:17 +08:00
jasder 7af6d8d754 FIX merge flick 2021-06-17 17:10:16 +08:00
jasder 5a8dc9d5e7 ADD merge develop branch 2021-06-17 14:09:59 +08:00
jasder ecdb79ee48 fix code bug 2021-06-11 17:40:55 +08:00
jasder 50e0ad9804 Merge branch 'dev_educoder' into educoder_server 2021-06-11 17:36:53 +08:00
jasder 953d6790d0 FIX create gitea user bug 2021-06-11 17:35:27 +08:00
jasder 136d1c1abd Merge branch 'educoder_server' of https://git.trustie.net/jasder/forgeplus into educoder_server 2021-06-11 16:51:30 +08:00
jasder e085ef374b Merge branch 'develop' into dev_educoder 2021-05-24 10:41:05 +08:00
jasder a557139ad0 Merge branch 'develop' into dev_educoder 2021-05-17 17:15:08 +08:00
jasder 6d0ac60d5a ADD phone query params for get list users api 2021-05-17 16:58:42 +08:00
jasder dda1868a72 Merge branch 'develop' into dev_educoder 2021-05-17 16:57:57 +08:00
jasder 93a1a08393 FIX merge develop branch adn fix confict 2021-05-17 16:26:51 +08:00
yystopf 4d4d8d1369 项目模块项目id重定向
项目模块项目id重定向
2021-05-03 19:50:21 +08:00
vilet.yy ab42fb7476 add: projects redirect to 2021-05-03 19:40:30 +08:00
jasder 11ac2f9c9d FIX delete log 2021-04-30 16:16:08 +08:00
jasder 8a9c3df2e5 Merge branch 'educoder_server' into dev_educoder 2021-04-30 16:09:40 +08:00
jasder e90f80255e FIX 完善项目添加成员流程 2021-04-30 16:09:02 +08:00
jasder 1b6c082480 fix merge develop 2021-04-07 11:40:29 +08:00
jasder ce1152cd4f Merge branch 'educoder_server' into dev_educoder 2021-04-02 15:54:07 +08:00
jasder c8a9094ad0 Merge branch 'develop' into dev_educoder 2021-04-02 15:53:48 +08:00
jasder 569088d846 Merge branch 'dev_educoder' into educoder_server 2021-04-01 21:00:41 +08:00
jasder 6159cda155 Merge branch 'develop' into dev_educoder 2021-04-01 21:00:22 +08:00
jasder d738ea432b Merge branch 'dev_educoder' into educoder_server 2021-04-01 15:08:32 +08:00
jasder 4a30e8c83f FIX conflict 2021-04-01 15:08:29 +08:00
jasder b3288937c9 fix merge 2021-04-01 15:07:12 +08:00
jasder 7520fa03c2 Merge branch 'develop' into dev_educoder 2021-03-28 20:05:52 +08:00
jasder f282d971e3 FIX get branches api bug and project menu list bug 2021-03-28 19:56:11 +08:00
jasder 56f01801ae Merge branch 'dev_educoder' into educoder_server 2021-03-28 19:45:24 +08:00
jasder 45e70367d5 Merge branch 'develop' into dev_educoder 2021-03-28 19:45:07 +08:00
jasder a0b376e70a Merge branch 'dev_educoder' into educoder_server 2021-03-27 23:55:11 +08:00
jasder d62d757c42 Merge branch 'develop' into dev_educoder 2021-03-27 23:54:55 +08:00
jasder 033c2607e2 Merge branch 'dev_educoder' into educoder_server 2021-03-25 21:30:46 +08:00
vilet.yy 0d6abdf7d0 fix: setting common arr 2021-03-25 20:59:24 +08:00
jasder 22c68f4c70 FIX bug 2021-03-25 20:29:36 +08:00
jasder fcd86fb01b Merge branch 'dev_educoder' into educoder_server 2021-03-25 19:58:28 +08:00
jasder faecb99136 Merge branch 'develop' into dev_educoder 2021-03-25 19:58:03 +08:00
jasder 15a002f601 Update defalut laboratory setting url 2021-03-23 16:36:35 +08:00
jasder 206d7bc159 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:58:47 +08:00
jasder 5e0006a830 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:47:13 +08:00
jasder 3abf993463 Merge branch 'trustie_server' into dev_educoder 2021-03-23 15:43:08 +08:00
jasder efbf6d627d FIX merge 2021-03-23 11:43:24 +08:00
jasder 6836907146 FIX code bug 2021-03-23 10:26:20 +08:00
jasder 6c4058cde5 Merge branch 'educoder_server' into dev_educoder 2021-03-23 10:22:12 +08:00
jasder 5a2e17abe2 FIX project and project_info aasion 2021-03-23 09:34:20 +08:00
jasder 9a8b89bcd8 FIX 解决实训作业关联项目的问题 2021-03-23 09:28:40 +08:00
jasder 4856da1607 Merge branch 'dev_educoder' into educoder_server 2021-03-22 21:02:56 +08:00
jasder 883a5f7e38 Merge branch 'develop' into dev_educoder 2021-03-22 21:02:35 +08:00
jasder 1658c1b923 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-22 17:58:29 +08:00
jasder 74f6a54d29 FIX update setting api for nav bar url 2021-03-22 17:58:15 +08:00
vilet.yy adb315521e fix 2021-03-22 14:20:03 +08:00
vilet.yy 01cad866b8 fix: laboratory 500
fix

fix
2021-03-22 14:17:03 +08:00
jasder 3447b17cdf FIX change password bug 2021-03-22 14:13:25 +08:00
jasder 0079255e98 Merge branch 'develop' into dev_educoder 2021-03-21 11:25:57 +08:00
vilet.yy 490bff5ded fix: form error 2021-03-19 16:18:09 +08:00
vilet.yy 008b8ac709 Merge branch 'develop' into dev_educoder 2021-03-19 15:07:34 +08:00
vilet.yy d0532a8f70 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-19 11:54:10 +08:00
vilet.yy a8c4cde350 add: user info sync_pwd 2021-03-19 11:50:35 +08:00
jasder 5de5974102 FIX remove email for gitea_register api 2021-03-19 10:54:56 +08:00
jasder 3d3e778078 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-19 10:31:12 +08:00
jasder f5ea8dc4a2 FIX change password api 2021-03-19 10:31:06 +08:00
vilet.yy c4b942a5f2 fix 2021-03-18 18:22:07 +08:00
jasder 13391b189a FIX conflict 2021-03-18 18:17:41 +08:00
jasder b116a72ce7 Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 18:15:22 +08:00
jasder f01aec94d6 FIX 2021-03-18 18:15:08 +08:00
jasder cc97f85a1e ADD has_ansenty 2021-03-18 18:11:06 +08:00
vilet.yy 133995080a add: user info email 2021-03-18 18:11:06 +08:00
vilet.yy 27304c35dc add: user info mark 2021-03-18 18:11:06 +08:00
vilet.yy d6bf85ef73 add: user gitea register 2021-03-18 18:11:06 +08:00
jasder be9c01bf1d ADD educoder api 2021-03-18 18:11:06 +08:00
jasder edeaaa5db7 FIX sync user for educoder 2021-03-18 18:11:06 +08:00
jasder 0e41b6cc9b FIX 整理表结构 2021-03-18 18:11:03 +08:00
jasder 5f3946f187 ADD has_ansenty 2021-03-18 18:07:56 +08:00
jasder b7be00f3ec Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 17:28:20 +08:00
jasder 9b21e29426 ADD educoder api 2021-03-18 17:27:18 +08:00
vilet.yy f37fccfdb3 add: user info email 2021-03-18 17:22:59 +08:00
vilet.yy 810d2dbac6 add: user info mark 2021-03-18 16:00:05 +08:00
vilet.yy 6af97d865f Merge branch 'dev_educoder' of https://git.trustie.net/jasder/forgeplus into dev_educoder 2021-03-18 15:28:09 +08:00
vilet.yy efba4b2b4f add: user gitea register 2021-03-18 15:28:03 +08:00
jasder aaf1f43cc2 FIX sync user for educoder 2021-03-18 13:46:19 +08:00
jasder 823c99bd71 FIX 整理表结构 2021-03-15 16:02:59 +08:00
2680 changed files with 1419589 additions and 299539 deletions

10
.gitignore vendored
View File

@ -10,8 +10,7 @@
# Ignore lock config file # Ignore lock config file
*.log *.log
.rubocop.yml
.env
# mac # mac
*.DS_Store *.DS_Store
.bashrc .bashrc
@ -38,11 +37,13 @@ public/react/yarn.lock
# Ignore react node_modules # Ignore react node_modules
public/system/* public/system/*
public/react/*
/public/react/.cache /public/react/.cache
/public/react/node_modules/ /public/react/node_modules/
/public/react/config/stats.json /public/react/config/stats.json
/public/react/stats.json /public/react/stats.json
/public/react/.idea/* /public/react/.idea/*
/public/react/build/*
/public/h5build /public/h5build
/public/npm-debug.log /public/npm-debug.log
@ -82,8 +83,7 @@ db/bak/
docker/ docker/
educoder.sql educoder.sql
redis_data/ redis_data/
Dockerfile
dump.rdb dump.rdb
.tags* .tags*
ceshi_user.xlsx ceshi_user.xlsx
public/trace_task_results
public/项目活跃度排行.xls

View File

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

View File

@ -1,59 +0,0 @@
FROM ubuntu:20.04
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt install -y tzdata
# basics
RUN apt-get install -y libssl-dev curl libmysqlclient-dev imagemagick nodejs mysql-server redis-server
RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# confirm openssl version
RUN openssl version
RUN which openssl
# install RVM, Ruby, and Bundler
RUN \curl -L https://get.rvm.io | bash -s stable
# rvm environment variable
RUN /bin/bash -l -c "source /etc/profile.d/rvm.sh"
RUN /bin/bash -l -c "rvm requirements"
# replace ruby mirror url, accelerate install ruby
RUN sed -i 's/rvm_remote_server_url2/#rvm_remote_server_url2/g' /usr/local/rvm/config/db
RUN sed -i 's/cache.ruby-lang.org/cache.ruby-china.com/g' /usr/local/rvm/config/db
# install ruby
RUN /bin/bash -l -c "rvm install 2.4.5"
# confirm ruby version
RUN /bin/bash -l -c "rvm list"
RUN /bin/bash -l -c "ruby -v"
#RUN apt-get install -y nodejs
WORKDIR /home/app/gitlink
ADD ./ /home/app/gitlink
RUN cd /home/app/gitlink
RUN /bin/bash -l -c 'gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/'
RUN /bin/bash -l -c 'gem update --system'
RUN /bin/bash -l -c 'gem install bundler -v 2.3.26'
RUN /bin/bash -l -c 'gem install rake'
RUN /bin/bash -l -c 'gem install puma -v 5.6.5'
RUN rm -rf Gemfile.lock
RUN cp config/configuration.yml.example config/configuration.yml
RUN cp config/database-docker.yml.example config/database.yml
RUN touch config/redis.yml
RUN touch config/elasticsearch.yml
RUN /bin/bash -l -c 'bundle install'
RUN redis-server &
RUN /bin/bash -l -c 'bundle exec rake sync_table_structure:import_csv'
RUN /bin/bash -l -c 'rails db:migrate RAILS_ENV=development'
RUN /bin/bash -l -c 'bundle exec sidekiq -C config/sidekiq.yml -e production -d'
EXPOSE 4000
RUN /bin/bash -l -c 'RAILS_ENV=production puma -C config/puma.rb'

View File

@ -1,19 +0,0 @@
FROM ubuntu:20.04
RUN apt-get update
# basics
RUN apt-get install -y libssl-dev curl libmysqlclient-dev imagemagick nodejs mysql-server redis-server tzdata
RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# confirm openssl version
RUN openssl version
RUN which openssl
# install RVM, Ruby, and Bundler
RUN \curl -L https://get.rvm.io | bash -s stable
RUN /bin/bash -l -c "rvm requirements"
# replace ruby mirror url, accelerate install ruby
RUN sed -i 's/rvm_remote_server_url2/#rvm_remote_server_url2/g' /usr/local/rvm/config/db
RUN sed -i 's/cache.ruby-lang.org/cache.ruby-china.com/g' /usr/local/rvm/config/db
# install ruby
RUN /bin/bash -l -c "rvm install 2.4.5"
# confirm ruby version
RUN /bin/bash -l -c "rvm list"
RUN /bin/bash -l -c "ruby -v"

277
Gemfile
View File

@ -1,147 +1,130 @@
#source 'https://gems.ruby-china.com' source 'https://gems.ruby-china.com'
source 'https://mirrors.cloud.tencent.com/rubygems/' git_source(:github) { |repo| "https://github.com/#{repo}.git" }
#source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'rails', '~> 5.2.0' gem 'puma', '~> 3.11'
gem 'mysql2', '>= 0.4.4', '< 0.6.0' gem 'sass-rails', '~> 5.0'
gem 'puma', '~> 5.6.5' gem 'uglifier', '>= 1.3.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0' # gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
# gem 'coffee-rails', '~> 4.2' gem 'jbuilder', '~> 2.5'
gem 'turbolinks', '~> 5' gem 'groupdate', '~> 4.1.0'
gem 'jbuilder', '~> 2.5' gem 'chartkick'
gem 'groupdate', '~> 4.1.0' gem 'grape-entity', '~> 0.7.1'
gem 'chartkick' gem 'kaminari', '~> 1.1', '>= 1.1.1'
gem 'grape-entity', '~> 0.7.1'
gem 'kaminari', '~> 1.1', '>= 1.1.1' gem 'bootsnap', '>= 1.1.0', require: false
gem 'bootsnap', '>= 1.1.0', require: false gem 'chinese_pinyin'
gem 'chinese_pinyin' gem 'rack-cors'
gem 'redis-rails'
gem 'rack-cors' gem 'roo-xls'
gem 'redis-rails' gem 'simple_xlsx_reader'
gem 'roo-xls'
gem 'simple_xlsx_reader', '~>1.0.4' gem 'rubyzip'
gem 'rubyzip' gem 'spreadsheet'
gem 'sonarqube', :git => 'https://gitlink.org.cn/KingChan/sonarqube.git' gem 'ruby-ole'
gem 'spreadsheet' # 导出为xlsx
gem 'ruby-ole' gem 'axlsx', '~> 3.0.0.pre'
# 导出为xlsx gem 'axlsx_rails', '~> 0.5.2'
gem 'axlsx', '~> 3.0.0.pre'
gem 'axlsx_rails', '~> 0.5.2' gem 'oauth2'
#导出为pdf
gem 'oauth2' gem 'pdfkit'
#导出为pdf gem 'wkhtmltopdf-binary'
gem 'pdfkit' # gem 'request_store'
gem 'wkhtmltopdf-binary' #gem 'iconv'
# gem 'request_store' # markdown 转html
#gem 'iconv' gem 'redcarpet', '~> 3.4'
# markdown 转html
gem 'redcarpet', '~> 3.4' gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png'
gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png' gem 'acts-as-taggable-on', '~> 6.0'
gem 'acts-as-taggable-on', '~> 6.0' # a tree structure
gem 'ancestry'
# a tree structure gem 'acts_as_list'
gem 'ancestry' gem 'omniauth-cas'
gem 'acts_as_list'
gem 'omniauth-cas' # profiler Middleware
gem 'rack-mini-profiler'
# profiler Middleware
# gem 'rack-mini-profiler' # object-based searching
gem 'ransack'
# object-based searching
gem 'ransack' group :development, :test do
gem 'rspec-rails', '~> 3.8'
group :development, :test do end
gem 'rspec-rails', '~> 3.8'
end group :development do
gem 'prettier'
group :development do gem 'rubocop', '~> 0.52.0'
gem 'prettier' gem 'solargraph', '~> 0.38.0'
gem 'rubocop', '~> 0.52.0' gem 'awesome_print'
gem 'solargraph', '~> 0.38.0' gem 'web-console', '>= 3.3.0'
gem 'awesome_print' gem 'listen', '>= 3.0.5', '< 3.2'
gem 'web-console', '>= 3.3.0' gem 'spring'
gem 'listen', '>= 3.0.5', '< 3.2' gem 'spring-watcher-listen', '~> 2.0.0'
gem 'spring' gem "annotate", "~> 2.6.0"
gem 'pry-rails' end
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0" group :test do
end gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver'
group :test do gem 'chromedriver-helper'
gem 'capybara', '>= 2.15', '< 4.0' end
gem 'selenium-webdriver'
gem 'chromedriver-helper' gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
end
#编码检测
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'rchardet', '~> 1.8'
#编码检测 # http client
gem 'rchardet', '~> 1.8' gem 'faraday', '~> 0.15.4'
# http client # view
gem 'faraday', '~> 0.15.4' gem 'active_decorator'
gem 'bootstrap', '~> 4.3.1'
# view gem 'jquery-rails'
gem 'active_decorator' gem 'simple_form'
gem 'bootstrap', '~> 4.3.1' gem 'font-awesome-sass', '4.7.0'
gem 'jquery-rails'
gem 'simple_form' # i18n
gem 'font-awesome-sass', '4.7.0' gem 'rails-i18n', '~> 5.1'
# i18n # job
gem 'rails-i18n', '~> 5.1' gem 'sidekiq'
gem 'sinatra'
# job gem "sidekiq-cron", "~> 1.1"
gem 'sidekiq',"5.2.8"
gem 'sinatra' # batch insert
gem "sidekiq-cron", "1.2.0" gem 'bulk_insert'
gem 'sidekiq-failures'
# elasticsearch
# batch insert gem 'searchkick'
gem 'bulk_insert'
gem 'aasm'
# elasticsearch gem 'enumerize'
gem 'searchkick'
gem 'diffy'
gem 'aasm'
gem 'enumerize' gem 'deep_cloneable', '~> 3.0.0'
gem 'diffy' # oauth2
gem 'deep_cloneable', '~> 3.0.0' gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'
# oauth2
gem 'omniauth', '~> 1.9.0' # global var
gem 'omniauth-oauth2', '~> 1.6.0' gem 'request_store'
gem "omniauth-github"
gem "omniauth-rails_csrf_protection" # 敏感词汇
gem 'omniauth-gitee', '~> 1.0.0' gem 'harmonious_dictionary', '~> 0.0.1'
gem "omniauth-wechat-oauth2"
gem 'parallel', '~> 1.19', '>= 1.19.1'
# global var
gem 'request_store' gem 'letter_avatar'
# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar'
gem 'jwt'
gem 'doorkeeper'
gem 'doorkeeper-jwt'
gem 'gitea-client', '~> 1.6.1'
gem 'loofah', '~> 2.20.0'

View File

@ -1,5 +1,5 @@
GEM GEM
remote: https://mirrors.cloud.tencent.com/rubygems/ remote: https://gems.ruby-china.com/
specs: specs:
aasm (5.0.6) aasm (5.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
@ -99,7 +99,6 @@ GEM
archive-zip (~> 0.10) archive-zip (~> 0.10)
nokogiri (~> 1.8) nokogiri (~> 1.8)
chunky_png (1.3.11) chunky_png (1.3.11)
coderay (1.1.3)
concurrent-ruby (1.1.6) concurrent-ruby (1.1.6)
connection_pool (2.2.2) connection_pool (2.2.2)
crass (1.0.6) crass (1.0.6)
@ -107,12 +106,6 @@ GEM
activerecord (>= 3.1.0, < 7) activerecord (>= 3.1.0, < 7)
diff-lcs (1.3) diff-lcs (1.3)
diffy (3.3.0) 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) e2mmap (0.1.0)
elasticsearch (7.5.0) elasticsearch (7.5.0)
elasticsearch-api (= 7.5.0) elasticsearch-api (= 7.5.0)
@ -136,8 +129,6 @@ GEM
fugit (1.4.1) fugit (1.4.1)
et-orbi (~> 1.1, >= 1.1.8) et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.4) raabro (~> 1.4)
gitea-client (1.5.9)
rest-client (~> 2.1.0)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
grape-entity (0.7.1) grape-entity (0.7.1)
@ -148,9 +139,6 @@ GEM
harmonious_dictionary (0.0.1) harmonious_dictionary (0.0.1)
hashie (3.6.0) hashie (3.6.0)
htmlentities (4.3.4) htmlentities (4.3.4)
http-accept (1.7.0)
http-cookie (1.0.8)
domain_name (~> 0.5)
i18n (1.8.2) i18n (1.8.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
io-like (0.3.1) io-like (0.3.1)
@ -179,8 +167,7 @@ GEM
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7) rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2) ruby_dep (~> 1.2)
logger (1.6.6) loofah (2.4.0)
loofah (2.20.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
@ -189,10 +176,6 @@ GEM
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
maruku (0.7.3) maruku (0.7.3)
method_source (0.9.2) method_source (0.9.2)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2015)
mime-types-data (3.2025.0220)
mimemagic (0.3.10) mimemagic (0.3.10)
nokogiri (~> 1) nokogiri (~> 1)
rake rake
@ -206,7 +189,6 @@ GEM
mustermann (1.1.1) mustermann (1.1.1)
ruby2_keywords (~> 0.0.1) ruby2_keywords (~> 0.0.1)
mysql2 (0.5.3) mysql2 (0.5.3)
netrc (0.11.0)
nio4r (2.5.2) nio4r (2.5.2)
nokogiri (1.10.8) nokogiri (1.10.8)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
@ -223,21 +205,9 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
nokogiri (~> 1.5) nokogiri (~> 1.5)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-gitee (1.0.0)
omniauth (>= 1.5, < 3.0)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-github (1.4.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-oauth2 (1.6.0) omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1) oauth2 (~> 1.1)
omniauth (~> 1.9) omniauth (~> 1.9)
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
omniauth-wechat-oauth2 (0.2.2)
omniauth (>= 1.3.2)
omniauth-oauth2 (>= 1.1.1)
parallel (1.19.1) parallel (1.19.1)
parser (2.7.1.1) parser (2.7.1.1)
ast (~> 2.4.0) ast (~> 2.4.0)
@ -247,18 +217,14 @@ GEM
popper_js (1.16.0) popper_js (1.16.0)
powerpack (0.1.2) powerpack (0.1.2)
prettier (0.18.2) prettier (0.18.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.3) public_suffix (4.0.3)
puma (5.6.5) puma (3.12.2)
nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
rack (2.0.9) rack (2.0.9)
rack-cors (1.1.1) rack-cors (1.1.1)
rack (>= 2.0.0) rack (>= 2.0.0)
rack-mini-profiler (2.0.1)
rack (>= 1.2.0)
rack-protection (2.0.8.1) rack-protection (2.0.8.1)
rack rack
rack-test (1.1.0) rack-test (1.1.0)
@ -322,11 +288,6 @@ GEM
regexp_parser (1.7.0) regexp_parser (1.7.0)
request_store (1.5.0) request_store (1.5.0)
rack (>= 1.4) 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) reverse_markdown (1.4.0)
nokogiri nokogiri
roo (2.8.3) roo (2.8.3)
@ -404,8 +365,6 @@ GEM
sidekiq-cron (1.2.0) sidekiq-cron (1.2.0)
fugit (~> 1.1) fugit (~> 1.1)
sidekiq (>= 4.2.1) sidekiq (>= 4.2.1)
sidekiq-failures (1.0.4)
sidekiq (>= 4.0.0)
simple_form (5.0.2) simple_form (5.0.2)
actionpack (>= 5.0) actionpack (>= 5.0)
activemodel (>= 5.0) activemodel (>= 5.0)
@ -455,7 +414,6 @@ GEM
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (4.2.0) uglifier (4.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unf (0.2.0)
unicode-display_width (1.6.1) unicode-display_width (1.6.1)
web-console (3.7.0) web-console (3.7.0)
actionview (>= 5.0) actionview (>= 5.0)
@ -492,37 +450,28 @@ DEPENDENCIES
chromedriver-helper chromedriver-helper
deep_cloneable (~> 3.0.0) deep_cloneable (~> 3.0.0)
diffy diffy
doorkeeper
doorkeeper-jwt
enumerize enumerize
faraday (~> 0.15.4) faraday (~> 0.15.4)
font-awesome-sass (= 4.7.0) font-awesome-sass (= 4.7.0)
gitea-client (~> 1.5.8)
grape-entity (~> 0.7.1) grape-entity (~> 0.7.1)
groupdate (~> 4.1.0) groupdate (~> 4.1.0)
harmonious_dictionary (~> 0.0.1) harmonious_dictionary (~> 0.0.1)
jbuilder (~> 2.5) jbuilder (~> 2.5)
jquery-rails jquery-rails
jwt
kaminari (~> 1.1, >= 1.1.1) kaminari (~> 1.1, >= 1.1.1)
letter_avatar letter_avatar
listen (>= 3.0.5, < 3.2) listen (>= 3.0.5, < 3.2)
loofah (~> 2.20.0)
mysql2 (>= 0.4.4, < 0.6.0) mysql2 (>= 0.4.4, < 0.6.0)
oauth2 oauth2
omniauth (~> 1.9.0) omniauth (~> 1.9.0)
omniauth-cas omniauth-cas
omniauth-gitee (~> 1.0.0)
omniauth-github
omniauth-oauth2 (~> 1.6.0) omniauth-oauth2 (~> 1.6.0)
omniauth-rails_csrf_protection
omniauth-wechat-oauth2
parallel (~> 1.19, >= 1.19.1) parallel (~> 1.19, >= 1.19.1)
pdfkit pdfkit
prettier prettier
pry-rails puma (~> 3.11)
puma (~> 5.6.5)
rack-cors rack-cors
rack-mini-profiler
rails (~> 5.2.0) rails (~> 5.2.0)
rails-i18n (~> 5.1) rails-i18n (~> 5.1)
ransack ransack
@ -540,11 +489,10 @@ DEPENDENCIES
sass-rails (~> 5.0) sass-rails (~> 5.0)
searchkick searchkick
selenium-webdriver selenium-webdriver
sidekiq (= 5.2.8) sidekiq
sidekiq-cron (= 1.2.0) sidekiq-cron (~> 1.1)
sidekiq-failures
simple_form simple_form
simple_xlsx_reader (~> 1.0.4) simple_xlsx_reader
sinatra sinatra
solargraph (~> 0.38.0) solargraph (~> 0.38.0)
spreadsheet spreadsheet

206
README.md
View File

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

View File

@ -51,51 +51,6 @@ http://localhost:3000/api/accounts/remote_register | jq
|-- token |string|用户token| |-- token |string|用户token|
返回值
```json
{
"status": 0,
"message": "success",
"user": {
"id": 36400,
"token": "8c87a80d9cfacc92fcb2451845104f35119eda96"
}
}
```
---
#### 独立注册接口
```
POST accounts/register
```
*示例*
```bash
curl -X POST \
-d "login=2456233122@qq.com" \
-d "password=djs_D_00001" \
-d "namespace=16895620" \
-d "code=forge" \
http://localhost:3000/api/accounts/remote_register | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
|-|-|-|-|
|login |是|string |邮箱或者手机号 |
|namespace |是|string |登录名 |
|password |是|string |密码 |
|code |是|string |验证码 |
*返回参数说明:*
|参数名|类型|说明|
|-|-|-|
|user|json object |返回数据|
|-- id |int |用户id |
|-- token |string|用户token|
返回值 返回值
```json ```json
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,137 +1,101 @@
//= require rails-ujs //= require rails-ujs
//= require activestorage //= require activestorage
//= require turbolinks //= require turbolinks
//= require jquery3 //= require jquery3
//= require popper //= require popper
//= require bootstrap-sprockets //= require bootstrap-sprockets
//= require jquery.validate.min //= require jquery.validate.min
//= require additional-methods.min //= require additional-methods.min
//= require bootstrap-notify //= require bootstrap-notify
//= require jquery.cookie.min //= require jquery.cookie.min
//= require select2 //= require select2
//= require moment.min //= require moment.min
//= require jquery.cxselect //= require jquery.cxselect
//= require bootstrap-datepicker //= require bootstrap-datepicker
//= require bootstrap-datetimepicker //= require bootstrap-datetimepicker
//= require bootstrap.viewer //= require bootstrap.viewer
//= require bootstrap/bootstrap-toggle //= require jquery.mloading
//= require jquery.mloading //= require jquery-confirm.min
//= require jquery-confirm.min //= require common
//= require common
//= require echarts
//= require echarts //= require codemirror/lib/codemirror
//= require codemirror/lib/codemirror //= require codemirror/mode/shell/shell
//= require codemirror/mode/shell/shell //= require editormd/editormd
//= require editormd/editormd //= require editormd/languages/zh-tw
//= require editormd/languages/zh-tw //= require dragula/dragula
//= require dragula/dragula
//= require_tree ./i18n
//= require_tree ./i18n //= require_tree ./admins
//= require_tree ./admins
$.ajaxSetup({
$.ajaxSetup({ beforeSend: function(xhr) {
beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); }
} });
});
// ******** select2 global config ********
// ******** select2 global config ******** $.fn.select2.defaults.set('theme', 'bootstrap4');
$.fn.select2.defaults.set('theme', 'bootstrap4'); $.fn.select2.defaults.set('language', 'zh-CN');
$.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
Turbolinks.setProgressBarDelay(200);
$.notifyDefaults({
$.notifyDefaults({ type: 'success',
type: 'success', z_index: 9999,
z_index: 9999, delay: 2000
delay: 2000 });
});
function show_success_flash(){
function show_success_flash(){ $.notify({
$.notify({ message: '操作成功'
message: '操作成功' },{
},{ type: 'success'
type: 'success' });
}); }
}
$(document).on('turbolinks:load', function(){
$(document).on('turbolinks:load', function(){ $('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); $('[data-toggle="popover"]').popover();
$('[data-toggle="popover"]').popover();
// 图片查看大图
// 图片查看大图 $('img.preview-image').bootstrapViewer();
$('img.preview-image').bootstrapViewer();
// flash alert提示框自动关闭
// flash alert提示框自动关闭 if($('.admin-alert-container .alert').length > 0){
if($('.admin-alert-container .alert').length > 0){ setTimeout(function(){
setTimeout(function(){ $('.admin-alert-container .alert:not(.alert-danger)').alert('close');
$('.admin-alert-container .alert:not(.alert-danger)').alert('close'); }, 2000);
}, 2000); setTimeout(function(){
setTimeout(function(){ $('.admin-alert-container .alert.alert-danger').alert('close');
$('.admin-alert-container .alert.alert-danger').alert('close'); }, 5000);
}, 5000); }
} });
});
$(document).on("turbolinks:before-cache", function () {
$(document).on("turbolinks:before-cache", function () { $('[data-toggle="tooltip"]').tooltip('hide');
$('[data-toggle="tooltip"]').tooltip('hide'); $('[data-toggle="popover"]').popover('hide');
$('[data-toggle="popover"]').popover('hide'); });
}); // var progressBar = new Turbolinks.ProgressBar();
// var progressBar = new Turbolinks.ProgressBar();
// $(document).on('ajax:send', function(event){
// $(document).on('ajax:send', function(event){ // console.log('ajax send', event);
// console.log('ajax send', event); // progressBar.setValue(0)
// progressBar.setValue(0) // progressBar.show()
// progressBar.show() // });
// }); //
// // $(document).on('ajax:complete', function(event){
// $(document).on('ajax:complete', function(event){ // console.log('ajax complete', event);
// console.log('ajax complete', event); // progressBar.setValue(1)
// progressBar.setValue(1) // progressBar.hide() // 分页时不触发,奇怪
// progressBar.hide() // 分页时不触发,奇怪 // });
// }); // $(document).on('ajax:success', function(event){
// $(document).on('ajax:success', function(event){ // console.log('ajax success', event);
// console.log('ajax success', event); // });
// }); // $(document).on('ajax:error', function(event){
// $(document).on('ajax:error', function(event){ // console.log('ajax error', event);
// console.log('ajax error', event); // });
// });
$(function () {
$(function () { });
});
$(document).on('turbolinks:load', function() {
$('.logo-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
})

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -63,7 +63,7 @@ $(document).on('turbolinks:load', function() {
if(!valid) return; if(!valid) return;
$.ajax({ $.ajax({
method: 'PUT', method: 'PATCH',
dataType: 'json', dataType: 'json',
url: $form.attr('action'), url: $form.attr('action'),
data: new FormData($form[0]), data: new FormData($form[0]),

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,65 +0,0 @@
$(document).on('turbolinks:load', function(){
if ($('body.admins-organizations-index-page').length > 0) {
var showSuccessNotify = function() {
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
// organizations open cla
$('.organizations-list-container').on('click', '.open-cla-action', function(){
var $openClaAction = $(this);
var $closeClaAction = $openClaAction.siblings('.close-cla-action');
var userId = $openClaAction.data('id');
customConfirm({
content: '确认开通吗?',
ok: function () {
$.ajax({
url: '/admins/organizations/' + userId + '/open_cla',
method: 'POST',
dataType: 'json',
success: function() {
showSuccessNotify();
$closeClaAction.show();
$openClaAction.hide();
},
error: function(res){
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
}
});
}
})
});
// organizations close cla
$('.organizations-list-container').on('click', '.close-cla-action', function(){
var $closeClaAction = $(this);
var $openClaAction= $closeClaAction.siblings('.open-cla-action');
var userId = $openClaAction.data('id');
customConfirm({
content: '确认关闭吗?',
ok: function () {
$.ajax({
url: '/admins/organizations/' + userId + '/close_cla',
method: 'POST',
dataType: 'json',
success: function() {
showSuccessNotify();
$openClaAction.show();
$closeClaAction.hide();
},
error: function(res){
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
}
});
}
})
});
}
});

View File

@ -1,3 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,141 +0,0 @@
/*
* @Description: Do not edit
* @Date: 2021-08-31 11:16:45
* @LastEditors: viletyy
* @Author: viletyy
* @LastEditTime: 2021-08-31 14:19:46
* @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
*/
$(document).on('turbolinks:load', function(){
var showSuccessNotify = function() {
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
// close user
$('.project-list-container').on('click', '.recommend-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unrecommend-action');
var $editAction = $closeAction.siblings('.edit-recommend-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认将该项目设置为推荐项目吗?',
ok: function(){
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
recommend: true,
recommend_index: 1
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$editAction.show();
$(".project-item-"+keywordID).children('td').eq(5).text("√")
}
});
}
});
});
// unclose user
$('.project-list-container').on('click', '.unrecommend-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.recommend-action');
var $editAction = $closeAction.siblings('.edit-recommend-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认取消该推荐项目吗?',
ok: function () {
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
recommend: false,
recommend_index: 0
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$editAction.hide();
$(".project-item-"+keywordID).children('td').eq(5).text("")
}
});
}
})
});
// close user
$('.project-list-container').on('click', '.pinned-action', function(){
var $closeAction = $(this);
var $uncloseAction = $closeAction.siblings('.unpinned-action');
var keywordID = $closeAction.data('id');
customConfirm({
content: '确认将该项目设置为精选项目吗?',
ok: function(){
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
is_pinned: true,
}
},
success: function() {
showSuccessNotify();
$closeAction.hide();
$uncloseAction.show();
$(".project-item-"+keywordID).children('td').eq(4).text("√")
}
});
}
});
});
// unclose user
$('.project-list-container').on('click', '.unpinned-action', function(){
var $uncloseAction = $(this);
var $closeAction = $uncloseAction.siblings('.pinned-action');
var keywordID = $uncloseAction.data('id');
customConfirm({
content: '确认取消该精选项目吗?',
ok: function () {
$.ajax({
url: '/admins/projects/' + keywordID,
method: 'PUT',
dataType: 'json',
data: {
project: {
is_pinned: false,
}
},
success: function() {
showSuccessNotify();
$closeAction.show();
$uncloseAction.hide();
$(".project-item-"+keywordID).children('td').eq(4).text("")
}
});
}
})
});
})

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -94,20 +94,6 @@ $(document).on('turbolinks:load', function(){
} }
}); });
}); });
// reset user login times
$('.users-list-container').on('click', '.fresh-gitea-token-action', function(){
var $action = $(this);
var userId = $action.data('id');
$.ajax({
url: '/admins/users/' + userId + '/fresh_gitea_token',
method: 'POST',
dataType: 'json',
success: function() {
showSuccessNotify();
}
});
});
// ***************** reward grade modal ***************** // ***************** reward grade modal *****************
var $rewardGradeModal = $('.admin-users-reward-grade-modal'); var $rewardGradeModal = $('.admin-users-reward-grade-modal');

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,180 +0,0 @@
/*! ========================================================================
* 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);

View File

@ -1,9 +0,0 @@
/*! ========================================================================
* 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

View File

@ -1 +0,0 @@
{"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"}

View File

@ -1,180 +0,0 @@
/*! ========================================================================
* 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);

View File

@ -1,9 +0,0 @@
/*! ========================================================================
* 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

View File

@ -1 +0,0 @@
{"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"}

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -8,7 +8,6 @@
@import "jquery.mloading"; @import "jquery.mloading";
@import "jquery-confirm.min"; @import "jquery-confirm.min";
@import "bootstrap-datetimepicker.min"; @import "bootstrap-datetimepicker.min";
@import "bootstrap/bootstrap-toggle.min";
@import "codemirror/lib/codemirror"; @import "codemirror/lib/codemirror";
@import "editormd/css/editormd.min"; @import "editormd/css/editormd.min";
@ -40,13 +39,6 @@ body {
} }
} }
} }
.editormd .CodeMirror{
margin-top: 35px!important;
}
.CodeMirror-gutter .CodeMirror-linenumbers {
width: 28px!important;
}
input.form-control { input.form-control {
font-size: 14px; font-size: 14px;
@ -66,159 +58,3 @@ input.form-control {
position: absolute; position: absolute;
} }
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #e9ecef;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #e9ecef;
border: 1px solid #ced4da;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #495057;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #495057;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 0.8rem;
}
&-title {
color: #23272B;
font-size: 1rem;
}
}
.attachment-item {
display: flex;
&-img {
display: block;
width: 160px;
height: 160px;
background: #e9ecef;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 160px;
height: 160px;
background: #e9ecef;
border: 1px solid #ced4da;
&::before {
content: '';
position: absolute;
top: 54px;
left: 78px;
width: 2px;
height: 52px;
background: #495057;
}
&::after {
content: '';
position: absolute;
top: 78px;
left: 54px;
width: 52px;
height: 2px;
background: #495057;
}
}
&-left {
position: relative;
width: 160px;
height: 160px;
&.has-img {
.attachment-item-upload {
display: none;
}
&:hover {
.attachment-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
padding-top: 100px;
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 0.8rem;
}
&-title {
color: #23272B;
font-size: 1rem;
}
}
.table th, .table td {
padding: 0.75rem 0.1rem;
vertical-align: top;
border-top: 1px solid #dee2e6;
}
.table .thead-light th{
white-space: nowrap;
}

View File

@ -1,3 +0,0 @@
// Place all the styles related to the admins/glcc_pr_check controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the admins/identity_verifications controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the admins/organizations controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the admins/page_themes controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the admins/site_pages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the api/pm/issue_links controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the api/pm/projects controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the api/v1/pm_issues controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the api/v1/sonarqube/issues controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the api/v1/sonarqubes controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,83 +0,0 @@
/*! ========================================================================
* 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; }

View File

@ -1,28 +0,0 @@
/*! ========================================================================
* 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}

View File

@ -1,85 +0,0 @@
/*! ========================================================================
* 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; }

View File

@ -1,28 +0,0 @@
/*! ========================================================================
* 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}

View File

@ -1,3 +0,0 @@
// Place all the styles related to the identity_verifications controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the organizations/clas controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the pages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the pm/journals controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the users/clas controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,453 +1,390 @@
class AccountsController < ApplicationController class AccountsController < ApplicationController
before_action :require_login, only: [:login_check, :simple_update, :change_password]
include ApplicationHelper #skip_before_action :check_account, :only => [:logout]
include AesCryptHelper
def index
#skip_before_action :check_account, :only => [:logout] render json: session
end
def simple_update
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, "")) # 为了同步平台上未注册gitea的用户
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, "")) def gitea_register
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, "")) user = User.find_by(login: sync_gitea_params[:login])
Register::RemoteForm.new(simple_update_params.merge(user_id: current_user.id)).validate! Users::SyncGiteaForm.new(sync_gitea_params.merge(user: user)).validate!
return render_error("该用户已同步协作平台") if user.gitea_token.present? && user.gitea_uid.present?
ActiveRecord::Base.transaction do
result = auto_update(current_user, simple_update_params) result = create_gitea_user!(user, sync_gitea_params[:login], sync_gitea_params[:email], sync_gitea_params[:password])
if result[:message].blank?
UserAction.create(:action_id => current_user.id, :action_type => "sync_educoder_user", :user_id => current_user.id, :ip => request.remote_ip) if params[:platform] == "educoder" result[:user] ? render_ok : render_error(result[:message])
render_ok rescue Exception => e
else uid_logger_error(e.message)
render_error(result[:message]) tip_exception(-1, e.message)
end end
end
end # 其他平台同步注册的用户
def remote_register
def index username = params[:username]&.gsub(/\s+/, "")
render json: session tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.is_reversed(username).present?
end email = params[:email]&.gsub(/\s+/, "")
password = params[:password]
# 其他平台同步注册的用户 platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
def remote_register
Register::RemoteForm.new(remote_register_params).validate! ActiveRecord::Base.transaction do
username = params[:username]&.gsub(/\s+/, "") result = autologin_register(username, email, password, platform)
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) if result[:message].blank?
email = params[:email]&.gsub(/\s+/, "") render_ok({user: result[:user]})
phone = params[:phone]&.gsub(/\s+/, "") else
password = params[:password] render_error(result[:message])
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") end
end
ActiveRecord::Base.transaction do rescue Exception => e
result = autologin_register(username, email, password, platform, phone) uid_logger_error(e.message)
if result[:message].blank? tip_exception(-1, e.message)
render_ok({user: result[:user]}) end
else
render_error(result[:message]) # 其他平台修改用户的信息,这边同步修改
end def remote_update
end ActiveRecord::Base.transaction do
rescue Exception => e user_params = params[:user_params]
uid_logger_error(e.message) user_extension_params = params[:user_extension_params]
tip_exception(-1, e.message)
end u = User.find_by(login: params[:old_user_login])
user_mail = u.try(:mail)
# 其他平台修改用户的信息,这边同步修改
def remote_update if u.present?
ActiveRecord::Base.transaction do ue = u.user_extension
user_params = params[:user_params] u.login = user_params["login"] if user_params["login"]
user_extension_params = params[:user_extension_params] u.mail = user_params["mail"] if user_params["mail"]
u.lastname = user_params["lastname"] if user_params["lastname"]
u = User.find_by(login: params[:old_user_login])
user_mail = u.try(:mail) ue.gender = user_extension_params["gender"]
ue.school_id = user_extension_params["school_id"]
if u.present? ue.location = user_extension_params["location"]
ue = u.user_extension ue.location_city = user_extension_params["location_city"]
u.login = user_params["login"] if user_params["login"] ue.identity = user_extension_params["identity"]
u.mail = user_params["mail"] if user_params["mail"] ue.technical_title = user_extension_params["technical_title"]
u.lastname = user_params["lastname"] if user_params["lastname"] ue.student_id = user_extension_params["student_id"]
ue.description = user_extension_params["description"]
ue.gender = user_extension_params["gender"] ue.save!
ue.school_id = user_extension_params["school_id"] u.save!
ue.location = user_extension_params["location"]
ue.location_city = user_extension_params["location_city"] sync_params = {}
ue.identity = user_extension_params["identity"]
ue.technical_title = user_extension_params["technical_title"] if (user_params["mail"] && user_params["mail"] != user_mail)
ue.student_id = user_extension_params["student_id"] sync_params = sync_params.merge(email: user_params["mail"])
ue.description = user_extension_params["description"] end
ue.save!
u.save! if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params)
sync_params = {} if interactor.success?
render_ok
if (user_params["mail"] && user_params["mail"] != user_mail) else
sync_params = sync_params.merge(email: user_params["mail"]) render_error(interactor.error)
end end
end
if sync_params.present? end
interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) end
if interactor.success? rescue Exception => e
render_ok uid_logger_error(e.message)
else tip_exception(-1, e.message)
render_error(interactor.error) end
end
end # 其他平台同步登录
end def remote_login
end @user = User.try_to_login(params[:login], params[:password])
rescue Exception => e if @user
uid_logger_error(e.message) successful_authentication(@user)
tip_exception(-1, e.message) render_ok({user: {id: @user.id, token: @user.gitea_token}})
end else
render_error("用户不存在")
# 其他平台同步登录 end
def remote_login end
@user = User.try_to_login(params[:login], params[:password])
if @user #修改密码
successful_authentication(@user) def remote_password
render_ok({user: {id: @user.id, token: @user.gitea_token}}) @user = User.find_by(login: params[:login])
else return render_error("未找到相关用户!") if @user.blank?
render_error("用户不存在")
end sync_params = {
end password: params[:password].to_s,
email: @user.mail
#修改密码 }
def remote_password
@user = User.find_by(login: params[:login]) interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
return render_error("未找到相关用户!") if @user.blank? if interactor.success?
@user.update_attribute(:password, params[:password])
sync_params = { render_ok
password: params[:password].to_s, else
email: @user.mail, render_error(interactor.error)
login_name: @user.login, end
source_id: 0 end
}
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
if interactor.success? # 用户注册
@user.update_attribute(:password, params[:password]) # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
render_ok # params[:login] 邮箱或者手机号
else # params[:code] 验证码
render_error(interactor.error) # code_type 1注册手机验证码 8邮箱注册验证码
end # 本地forge注册入口
end def register
begin
# 查询验证码是否正确;type只可能是1或者8
type = phone_mail_type(params[:login].strip)
# 用户注册 # code = params[:code].strip
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
# params[:login] 邮箱或者手机号 if type == 1
# params[:namespace] 登录名 uid_logger("start register by phone: type is #{type}")
# params[:code] 验证码 pre = 'p'
# code_type 1注册手机验证码 8邮箱注册验证码 email = nil
# 本地forge注册入口需要重新更改逻辑 phone = params[:login]
def register # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
# type只可能是1或者8 # TODO: 暂时限定邮箱注册
user = nil return normal_status(-1, '只支持邮箱注册')
begin else
Register::Form.new(register_params).validate! uid_logger("start register by email: type is #{type}")
pre = 'm'
user = Users::RegisterService.call(register_params) email = params[:login]
user.mail = "#{user.login}@example.org" if user.mail.blank? phone = nil
password = decrypt(register_params[:password]) rescue register_params[:password].to_s return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login])
password = password.strip return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL
# verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
# gitea用户注册, email, username, password end
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
if interactor.success? # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
gitea_user = interactor.result # todo 上线前请删除万能验证码"513231"
result = Gitea::User::GenerateTokenService.call(user.login, password) return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id'] code = generate_identifier User, 8, pre
if user.save! login = pre + code
UserExtension.create!(user_id: user.id) @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User")
# 绑定授权账号 @user.password = params[:password]
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]) @user.activate
end # 必须要用save操作密码的保存是在users中
successful_authentication(user)
render_ok interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]})
end if interactor.success?
elsif interactor.result[:message].to_s.include?("user already exists") gitea_user = interactor.result
UserAction.create(:action_id => 2, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};") result = Gitea::User::GenerateTokenService.new(login, params[:password]).call
normal_status(-1, "用户已注册,请勿连续操作。") @user.gitea_token = result['sha1']
else @user.gitea_uid = gitea_user[:body]['id']
tip_exception(-1, interactor.result[:message]) if @user.save!
end UserExtension.create!(user_id: @user.id)
rescue Register::BaseForm::EmailError => e successful_authentication(@user)
render_result(-2, e.message) normal_status("注册成功")
rescue Register::BaseForm::LoginError => e end
render_result(-3, e.message) else
rescue Register::BaseForm::PhoneError => e tip_exception(-1, interactor.error)
render_result(-4, e.message) end
rescue Register::BaseForm::PasswordFormatError => e rescue Exception => e
render_result(-5, e.message) uid_logger_error(e.message)
rescue Register::BaseForm::PasswordConfirmationError => e tip_exception(-1, e.message)
render_result(-7, e.message) end
rescue Register::BaseForm::VerifiCodeError => e end
render_result(-6, e.message)
rescue Exception => e # 用户登录
if user.present? && !e.message.to_s.include?("user already exists") def login
# Gitea::User::DeleteService.call(user.login) Users::LoginForm.new(account_params).validate!
# user.destroy @user = User.try_to_login(params[:login], params[:password])
end
Rails.logger.error("##:register error--#{user.try(:id)}message:#{e.message}") return normal_status(-2, "错误的账号或密码") if @user.blank?
UserAction.create(:action_id => 1, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};") # user is already in local database
logger_error(e) return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
tip_exception(-1, "注册失败")
end login_control = LimitForbidControl::UserLogin.new(@user)
end return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
# 用户登录 password_ok = @user.check_password?(params[:password].to_s)
def login unless password_ok
password = decrypt(login_params[:password]) rescue login_params[:password].to_s if login_control.remain_times-1 == 0
Users::LoginForm.new(login_params.merge!({password: password})).validate! normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
@user = User.try_to_login(params[:login], password) else
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
return normal_status(-2, "错误的账号或密码") if @user.blank? end
# user is already in local database login_control.increment!
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? return
end
login_control = LimitForbidControl::UserLogin.new(@user)
return normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? successful_authentication(@user)
sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步
password_ok = @user.check_password?(password.to_s)
unless password_ok # session[:user_id] = @user.id
if login_control.remain_times-1 == 0 end
normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
else def change_password
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") @user = User.find_by(login: params[:login])
end return render_error("未找到相关用户!") if @user.blank?
login_control.increment! return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
return
end sync_params = {
password: params[:password].to_s,
LimitForbidControl::UserLogin.new(@user).clear email: @user.mail
successful_authentication(@user) }
sync_pwd_to_gitea!(@user, {password: password.to_s}) # TODO用户密码未同步
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
# session[:user_id] = @user.id if interactor.success?
end @user.update_attribute(:password, params[:password])
render_ok
def change_password else
password = decrypt(params[:password]) rescue params[:password].to_s render_error(interactor.error)
new_password_repeat = decrypt(params[:new_password_repeat]) rescue params[:new_password_repeat].to_s end
old_password = decrypt(params[:old_password]) rescue params[:old_password] end
return render_error("两次输入的密码不一致") if password.to_s != new_password_repeat.to_s
@user = User.find_by(login: params[:login]) # 忘记密码
return render_forbidden unless User.current.login == @user&.login def reset_password
return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691 begin
return render_error("未找到相关用户!") if @user.blank? code = params[:code]
return render_error("旧密码不正确") unless @user.check_password?(old_password) login_type = phone_mail_type(params[:login].strip)
# 获取验证码
sync_params = { if login_type == 1
password: password.to_s, phone = params[:login]
email: @user.mail, verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last
login_name: @user.name, user = User.find_by_phone(phone)
source_id: 0 else
} email = params[:login]
verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) user = User.find_by_mail(email) #这里有问题应该是为email,而不是mail 6.13-hs
if interactor.success? end
@user.update_attribute(:password, password) return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
render_ok return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
else return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
render_error(interactor.error)
end user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
end ActiveRecord::Base.transaction do
user.save!
# 忘记密码 LimitForbidControl::UserLogin.new(user).clear
def reset_password end
begin sucess_status
Accounts::ResetPasswordForm.new(reset_password_params).validate! rescue Exception => e
uid_logger_error(e.message)
user = find_user tip_exception(e.message)
return render_error('未找到相关账号') if user.blank? end
end
user = Accounts::ResetPasswordService.call(user, reset_password_params)
LimitForbidControl::UserLogin.new(user).clear if user.save! def successful_authentication(user)
uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}")
render_ok # Valid user
rescue Register::BaseForm::EmailError => e self.logged_user = user
render_result(-2, e.message) # generate a key and set cookie if autologin
rescue Register::BaseForm::PhoneError => e
render_result(-4, e.message) set_autologin_cookie(user)
rescue Register::BaseForm::PasswordFormatError => e UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
render_result(-5, e.message) user.update_column(:last_login_on, Time.now)
rescue Register::BaseForm::PasswordConfirmationError => e session[:"#{default_yun_session}"] = user.id
render_result(-7, e.message) Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
rescue Register::BaseForm::VerifiCodeError => e # 注册完成后有一天的试用申请(先去掉)
render_result(-6, e.message) # UserDayCertification.create(user_id: user.id, status: 1)
rescue ActiveRecord::Rollback => e end
render_result(-1, "服务器异常")
rescue Exception => e def set_autologin_cookie(user)
uid_logger_error(e.message) token = Token.get_or_create_permanent_login_token(user, "autologin")
tip_exception(e.message) sync_user_token_to_trustie(user.login, token.value)
end
end cookie_options = {
:value => token.value,
def successful_authentication(user) :expires => 1.month.from_now,
uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") :path => '/',
# Valid user :secure => false,
self.logged_user = user :httponly => true
# generate a key and set cookie if autologin }
if edu_setting('cookie_domain').present?
set_autologin_cookie(user) cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) end
user.update_column(:last_login_on, Time.now) cookies[autologin_cookie_name] = cookie_options
session[:"#{default_yun_session}"] = user.id cookies.signed[:user_id] ||= user.id
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
# 注册完成后有一天的试用申请(先去掉) logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}")
# UserDayCertification.create(user_id: user.id, status: 1) end
end
def logout
def set_autologin_cookie(user) Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}")
token = Token.get_or_create_permanent_login_token(user, "autologin") UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
# sync_user_token_to_trustie(user.login, token.value) logout_user
render :json => {status: 1, message: "退出成功!"}
cookie_options = { end
:value => token.value,
:expires => 1.month.from_now, # 检验邮箱是否已被注册及邮箱或者手机号是否合法
:path => '/', # 参数type为事件类型 1注册2忘记密码3绑定
:secure => false, def valid_email_and_phone
:httponly => true check_mail_and_phone_valid(params[:login], params[:type])
} end
if edu_setting('cookie_domain').present?
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) # 发送验证码
end # params[:login] 手机号或者邮箱号
cookies[autologin_cookie_name] = cookie_options # params[:type]为事件通知类型 1用户注册注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
cookies.signed[:user_id] ||= user.id # 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效
logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") def get_verification_code
end code = %W(0 1 2 3 4 5 6 7 8 9)
value = params[:login]
def logout type = params[:type].strip.to_i
Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") login_type = phone_mail_type(value)
UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) send_type = verify_type(login_type, type)
logout_user verification_code = code.sample(6).join
render :json => {status: 1, message: "退出成功!"}
end sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
tip_exception(501, "请求不合理") if sign != params[:smscode]
# 检验邮箱是否已被注册及邮箱或者手机号是否合法
# 参数type为事件类型 1注册2忘记密码3绑定 logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ")
def valid_email_and_phone
check_mail_and_phone_valid(params[:login], params[:type]) # 记录验证码
end check_verification_code(verification_code, send_type, value)
sucess_status
# 发送验证码 end
# params[:login] 手机号或者邮箱号
# params[:type]为事件通知类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 # 1 手机类型0 邮箱类型
# 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 # 注意新版的login是自动名生成的
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效 def phone_mail_type value
def get_verification_code value =~ /^1\d{10}$/ ? 1 : 0
code = %W(0 1 2 3 4 5 6 7 8 9) end
value = params[:login]
type = params[:type].strip.to_i private
login_type = phone_mail_type(value)
send_type = verify_type(login_type, type) # type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
verification_code = code.sample(6).join # login_type 1手机类型 2邮箱类型
def verify_type login_type, type
status, message = InfoRiskControlService.call(value, request.remote_ip) case type
tip_exception(420, message) if status == 0 when 1
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") login_type == 1 ? 1 : 8
tip_exception(501, "请求不合理") if sign != params[:smscode] when 2
login_type == 1 ? 2 : 3
logger.info "########### 验证码:#{verification_code}" when 3
logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ") login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
when 4
# 记录验证码 login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
check_verification_code(verification_code, send_type, value) when 5
render_ok login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
end end
end
# check user's login or email or phone is used
# params[:value] 手机号或者邮箱号或者登录名 def generate_login(login)
# params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号) type = phone_mail_type(login.strip)
def check
Register::CheckColumnsForm.new(check_params).validate! if type == 1
render_ok uid_logger("start register by phone: type is #{type}")
end pre = 'p'
email = nil
def login_check phone = login
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate! else
render_ok uid_logger("start register by email: type is #{type}")
end pre = 'm'
email = login
def check_keywords phone = nil
text = params[:text].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') end
data = ! ReversedKeyword.check_exists?(text) code = generate_identifier User, 8, pre
result = {
status: 0, { login: pre + code, email: email, phone: phone }
data: data, end
message: data ? "" : "无法使用以下关键词:#{text},请重新命名"
} def sync_gitea_params
render_ok(result) params.permit(:login, :email, :password)
end end
private def user_params
params.require(:user).permit(:login, :email, :phone)
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 end
# login_type 1手机类型 2邮箱类型
def verify_type login_type, type def account_params
case type params.require(:account).permit(:login, :password)
when 1 end
login_type == 1 ? 1 : 8 end
when 2
login_type == 1 ? 2 : 3
when 3
login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
when 4
login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
when 5
login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
end
end
def generate_login(login)
type = phone_mail_type(login.strip)
if type == 1
uid_logger("start register by phone: type is #{type}")
pre = 'p'
email = nil
phone = login
else
uid_logger("start register by email: type is #{type}")
pre = 'm'
email = login
phone = nil
end
code = generate_identifier User, 8, pre
{ login: pre + code, email: email, phone: phone }
end
def user_params
params.require(:user).permit(:login, :email, :phone)
end
def login_params
params.require(:account).permit(:login, :password)
end
def check_params
params.permit(:type, :value)
end
def register_params
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
end
def remote_register_params
params.permit(:username, :email, :password, :platform)
end
def simple_update_params
params.permit(:username, :email, :password, :platform)
end
end

View File

@ -1,75 +0,0 @@
class Action::NodeInputsController < ApplicationController
before_action :require_admin, except: [:index]
before_action :find_action_node
def index
@node_inputs = @node.action_node_inputs
respond_to do |format|
format.html
format.json{ render_ok(data: @node_inputs.as_json) }
end
end
def create
@node_input = Action::NodeInput.new(node_input_params)
@node_input.action_node = @node
respond_to do |format|
if @node_input.save
format.html { redirect_to action_node_node_inputs_path(@node), notice: '创建成功.' }
format.json { render_ok(data: @node_input.as_json) }
else
format.html { render :new }
format.json { render json: @node_input.errors, status: -1 }
end
end
end
def new
end
def show
end
def edit
end
def update
@node_input.update(node_input_params)
respond_to do |format|
format.html { redirect_to action_node_node_inputs_path(@node), notice: '更新成功.' }
format.json { render_ok(data: @node_input.as_json) }
end
end
def destroy
if @node_input.destroy!
flash[:success] = '删除成功'
else
flash[:danger] = '删除失败'
end
redirect_to "api/actions/nodes"
end
private
def find_action_node
@node = Action::Node.find(params[:node_id])
if params[:id].present?
@node_input = @node.action_node_inputs.find(params[:id])
else
@node_input = Action::NodeInput.new
end
end
def node_input_params
if params.require(:action_node_input)
params.require(:action_node_input).permit(:name, :input_type, :description, :is_required, :sort_no, :default_value)
else
params.permit(:name, :input_type, :description, :is_required, :sort_no, :default_value)
end
end
end

View File

@ -1,76 +0,0 @@
class Action::NodeSelectsController < ApplicationController
before_action :require_admin, except: [:index]
before_action :find_action_node
def index
@node_selects = @node.action_node_selects
respond_to do |format|
format.html
format.json
end
end
def create
@node_select = Action::NodeSelect.new(node_select_params)
@node_select.action_node = @node
respond_to do |format|
if @node_select.save
format.html { redirect_to action_node_node_selects_path(@node), notice: '创建成功.' }
format.json { render_ok(data: @node_select.as_json) }
else
format.html { render :new }
format.json { render json: @node_select.errors, status: -1 }
end
end
end
def new
end
def show
end
def edit
end
def update
@node_select.update(node_select_params)
respond_to do |format|
format.html { redirect_to action_node_node_selects_path(@node), notice: '更新成功.' }
format.json { render_ok(data: @node_select.as_json) }
end
end
def destroy
if @node_select.destroy!
flash[:success] = '删除成功'
else
flash[:danger] = '删除失败'
end
redirect_to "api/actions/nodes"
end
private
def find_action_node
@node = Action::Node.find(params[:node_id])
if params[:id].present?
@node_select = @node.action_node_selects.find(params[:id])
else
@node_select = Action::NodeSelect.new
end
end
def node_select_params
if params.require(:action_node_select)
params.require(:action_node_select).permit(:name, :val, :val_ext, :description, :sort_no)
else
params.permit(:name, :val, :val_ext, :description, :sort_no)
end
end
end

View File

@ -1,74 +0,0 @@
class Action::NodeTypesController < ApplicationController
before_action :require_admin, except: [:index]
before_action :find_node_type, except: [:index, :create, :new]
def index
@node_types = Action::NodeType.all
respond_to do |format|
format.html
format.json { render_ok(data: @node_types.as_json) }
end
end
def create
@node_type = Action::NodeType.new(node_types_params)
respond_to do |format|
if @node_type.save
format.html { redirect_to action_node_types_path, notice: '创建成功.' }
format.json { render_ok(data: @node_type.as_json) }
else
format.html { render :new }
format.json { render json: @node_type.errors, status: -1 }
end
end
end
def show
respond_to do |format|
format.html
format.json { render_ok(data: @node_type.as_json) }
end
end
def new
@node_type = Action::NodeType.new
end
def edit
end
def update
@node_type.update(node_types_params)
respond_to do |format|
format.html { redirect_to action_node_types_path, notice: '更新成功.' }
format.json { render_ok(data: @node_type.as_json) }
end
end
def destroy
if @node_type.destroy!
flash[:success] = '删除成功'
else
flash[:danger] = '删除失败'
end
respond_to do |format|
format.html { redirect_to action_node_types_path }
format.json { render_ok }
end
end
private
def find_node_type
@node_type = Action::NodeType.find(params[:id])
end
def node_types_params
if params.require(:action_node_type)
params.require(:action_node_type).permit(:name, :description, :sort_no)
else
params.permit(:name, :description, :sort_no)
end
end
end

View File

@ -1,87 +0,0 @@
class Action::NodesController < ApplicationController
# before_action :require_admin, except: [:index]
before_action :require_login
before_action :find_action_node, except: [:index, :create, :new]
def index
@node_types = Action::NodeType.all
no_node_type = Action::NodeType.find_by(name: "未分类")
@no_type_nodes = Action::Node.where(action_node_types_id: nil)
@no_type_nodes = Action::Node.where(action_node_types_id: nil).or(Action::Node.where(action_node_types_id: no_node_type.id)) if no_node_type.present?
respond_to do |format|
format.html { @nodes = Action::Node.where("name LIKE :search OR full_name LIKE :search", :search => "%#{params[:search]}%") }
format.json
end
end
def create
@node = Action::Node.new(node_params)
if params.require(:node).present? && params.require(:node)[:link_type_array].present?
@node.link_type = (params.require(:node)[:link_type_array] - [""]).join(",")
end
@node.user_id = current_user.id
respond_to do |format|
if @node.save
format.html { redirect_to action_nodes_path, notice: '创建成功.' }
format.json { render_ok(data: @node.as_json) }
else
format.html { render :new }
format.json { render json: @node.errors, status: -1 }
end
end
end
def new
@node = Action::Node.new
end
def show
end
def edit
if @node.link_type.present?
@node.link_type_array = @node.link_type.to_s.split(",")
end
end
def update
if params.require(:node).present? && params.require(:node)[:link_type_array].present?
@node.link_type = (params.require(:node)[:link_type_array] - [""]).join(",")
end
@node.user_id = current_user.id if @node.user_id.blank?
@node.update(node_params)
respond_to do |format|
format.html { redirect_to action_nodes_path, notice: '更新成功.' }
format.json { render_ok(data: @node.as_json) }
end
end
def destroy
if @node.destroy!
flash[:success] = '删除成功'
else
flash[:danger] = '删除失败'
end
respond_to do |format|
format.html { redirect_to action_nodes_path }
format.json { render_ok() }
end
end
private
def find_action_node
@node = Action::Node.find(params[:id])
end
def node_params
if params.require(:action_node)
params.require(:action_node).permit(:name, :label, :full_name, :description, :icon, :action_node_types_id,
:is_local, :local_url, :yaml, :sort_no, :node_type, :is_mutil_link, :link_type, :link_type_array)
else
params.permit(:name, :label, :full_name, :description, :icon, :action_node_types_id, :is_local, :local_url,
:yaml, :sort_no, :node_type, :is_mutil_link, :link_type, :link_type_array)
end
end
end

View File

@ -1,71 +0,0 @@
class Action::TemplatesController < ApplicationController
before_action :require_admin, except: [:index]
before_action :find_action_template, except: [:index, :create, :new]
def index
@templates = Action::Template.all
respond_to do |format|
format.html
format.json
end
end
def create
@template = Action::Template.new(templates_params)
respond_to do |format|
if @template.save
format.html { redirect_to action_templates_path, notice: '创建成功.' }
format.json { render_ok(data: @template.as_json) }
else
format.html { render :new }
format.json { render json: @template.errors, status: -1 }
end
end
end
def show
end
def new
@template = Action::Template.new
end
def edit
end
def update
@template.update(templates_params)
respond_to do |format|
format.html { redirect_to action_templates_path, notice: '更新成功.' }
format.json { render_ok(data: @template.as_json) }
end
end
def destroy
if @template.destroy!
flash[:success] = '删除成功'
else
flash[:danger] = '删除失败'
end
respond_to do |format|
format.html { redirect_to action_templates_path }
format.json { render_ok }
end
end
private
def find_action_template
@template = Action::Template.find(params[:id])
end
def templates_params
if params.require(:action_template)
params.require(:action_template).permit(:name, :description, :img, :sort_no, :json, :yaml)
else
params.permit(:name, :description, :img, :sort_no, :json, :yaml)
end
end
end

View File

@ -23,23 +23,10 @@ class Admins::BaseController < ApplicationController
def require_admin! def require_admin!
return if current_user.blank? || !current_user.logged? return if current_user.blank? || !current_user.logged?
return if current_user.admin_or_business? return if current_user.admin_or_business?
return if current_user.admin_or_glcc_admin?
render_forbidden render_forbidden
end end
def require_admin
render_forbidden unless User.current.admin?
end
def require_business
render_forbidden unless admin_or_business?
end
def require_glcc_admin
render_forbidden unless admin_or_glcc_admin?
end
# 触发after ajax render partial hooks执行一些因为局部刷新后失效的绑定事件 # 触发after ajax render partial hooks执行一些因为局部刷新后失效的绑定事件
def rebind_event_if_ajax_render_partial def rebind_event_if_ajax_render_partial
return if request.format.symbol != :js return if request.format.symbol != :js

View File

@ -1,99 +1,10 @@
class Admins::DashboardsController < Admins::BaseController class Admins::DashboardsController < Admins::BaseController
def index def index
# 查询优化 @active_user_count = User.where(last_login_on: today).count
week_greater_id = CommitLog.where(created_at: current_week).limit(1)[0]&.id @weekly_active_user_count = User.where(last_login_on: current_week).count
#月份统计还需要优化 @month_active_user_count = User.where(last_login_on: current_month).count
month_greater_id = CommitLog.where(created_at: current_month).limit(1)[0]&.id
# 用户活跃数
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
weekly_user_ids = CommitLog.where(created_at: current_week).where("id>= ?", week_greater_id).distinct.pluck(:user_id)
month_user_ids = CommitLog.where(created_at: current_month).where("id>= ?", month_greater_id).distinct.pluck(:user_id)
@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)
# 新用户注册数
@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).where("id>= ?", week_greater_id).distinct.pluck(:project_id) + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
month_project_ids = (CommitLog.where(created_at: current_month).where("id>= ?", month_greater_id).distinct.pluck(:project_id) + 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 = Rails.cache.fetch("dashboardscontroller:weekly_active_project_count", expires_in: 10.minutes) do
Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
end
@month_active_project_count = Rails.cache.fetch("dashboardscontroller:month_active_project_count", expires_in: 1.hours) do
Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
end
# 新增项目数
@day_new_project_count = Rails.cache.fetch("dashboardscontroller:day_new_project_count", expires_in: 10.minutes) do
Project.where(created_on: today).count
end
@weekly_new_project_count = Rails.cache.fetch("dashboardscontroller:weekly_new_project_count", expires_in: 10.minutes) do
Project.where(created_on: current_week).count
end
@month_new_project_count = Rails.cache.fetch("dashboardscontroller:month_new_project_count", expires_in: 1.hours) do
Project.where(created_on: current_month).count
end
# 总的平台用户数
# 总的平台项目数
# 总的平台组织数
# 总的平台Issue数、评论数、PR数、Commit数
@user_count = Rails.cache.fetch("dashboardscontroller:platform:user_count", expires_in: 1.days) do
User.count
end
@project_count = Rails.cache.fetch("dashboardscontroller:platform:project_count", expires_in: 1.days) do
Project.count
end
@organization_count = Rails.cache.fetch("dashboardscontroller:platform:organization_count", expires_in: 1.days) do
Organization.count
end
@issue_count = Rails.cache.fetch("dashboardscontroller:platform:issue_count", expires_in: 1.days) do
Issue.count
end
@comment_count = Rails.cache.fetch("dashboardscontroller:platform:comment_count", expires_in: 1.days) do
Journal.count
end
@pr_count = Rails.cache.fetch("dashboardscontroller:platform:pr_count", expires_in: 1.days) do
PullRequest.count
end
@commit_count = Rails.cache.fetch("dashboardscontroller:platform:commit_count", expires_in: 1.days) do
CommitLog.count
end
@subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"]
@subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"]
@subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count]
if EduSetting.get("open_baidu_tongji").to_s == "true"
tongji_service = Baidu::TongjiService.new
@access_token = tongji_service.access_token
Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}"
# @overview_data = tongji_service.api_overview
last_date = DailyPlatformStatistic.order(:date).last || Time.now
start_date = last_date.date
end_date = Time.now
if @access_token.present?
@overview_data = Rails.cache.fetch("dashboardscontroller:baidu_tongji:overview_data", expires_in: 10.minutes) do
tongji_service.source_from_batch_add(start_date, end_date)
@overview_data = tongji_service.overview_batch_add(start_date, end_date)
@overview_data
end
end
@current_week_statistic = DailyPlatformStatistic.where(date: current_week)
@pre_week_statistic = DailyPlatformStatistic.where(date: pre_week)
end
@new_user_count = User.where(created_on: current_month).count
end end
def month_active_user def month_active_user
@ -105,22 +16,10 @@ class Admins::DashboardsController < Admins::BaseController
{ value: count['professional'].to_i, name: '专业人士' }, { value: count['professional'].to_i, name: '专业人士' },
{ value: count[nil].to_i, name: '未选职业' }, { value: count[nil].to_i, name: '未选职业' },
] ]
render_ok(data: data) render_ok(data: data)
end end
def baidu_tongji
tongji_service = Baidu::TongjiService.new
redirect_to tongji_service.code_url
end
def baidu_tongji_auth
if params[:code].present?
tongji_service = Baidu::TongjiService.new
tongji_service.get_access_token(params[:code])
end
redirect_to "/admins/"
end
def evaluate def evaluate
names = [] names = []
data = [] data = []
@ -142,20 +41,11 @@ class Admins::DashboardsController < Admins::BaseController
Time.now.beginning_of_day..Time.now.end_of_day Time.now.beginning_of_day..Time.now.end_of_day
end end
def pre_7_days
7.days.ago.end_of_day..Time.now.end_of_day
end
def current_week def current_week
Time.now.beginning_of_week..Time.now.end_of_day 7.days.ago.beginning_of_day..Time.now.end_of_day
end end
def current_month def current_month
30.days.ago.end_of_day..Time.now.end_of_day 30.days.ago.beginning_of_day..Time.now.end_of_day
end
def pre_week
# 14.days.ago.end_of_day..7.days.ago.end_of_day
Time.now.prev_week..Time.now.prev_week.end_of_week
end end
end end

View File

@ -1,5 +1,4 @@
class Admins::EduSettingsController < Admins::BaseController class Admins::EduSettingsController < Admins::BaseController
before_action :require_admin
before_action :find_setting, only: [:edit,:update, :destroy] before_action :find_setting, only: [:edit,:update, :destroy]
def index def index

View File

@ -1,5 +1,4 @@
class Admins::FaqsController < Admins::BaseController class Admins::FaqsController < Admins::BaseController
before_action :require_business
before_action :find_faq, only: [:edit,:update, :destroy] before_action :find_faq, only: [:edit,:update, :destroy]
def index def index

View File

@ -1,50 +0,0 @@
class Admins::FeedbacksController < Admins::BaseController
before_action :require_business
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

View File

@ -1,34 +0,0 @@
class Admins::GlccPrCheckController < Admins::BaseController
before_action :require_glcc_admin
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
examine_materials = Admins::GlccExamineMaterial.call(params)
@examine_materials = paginate examine_materials.includes(:glcc_student)
end
def send_mail
year = if params[:date].present?
params[:date][:year]
end
if year.nil?
return redirect_to admins_glcc_pr_check_index_path
flash[:error] = "时间不能为空"
end
if params[:term].blank?
return redirect_to admins_glcc_pr_check_index_path
flash[:error] = "考核选项不能为空"
end
examine_materials = GlccMediumTermExamineMaterial.where(\
term: params[:term],
created_on: [Time.now.change(year:year).beginning_of_year .. Time.now.change(year:year).end_of_year]
)
examine_materials.map{ |e|
e.send_mail
}
flash[:danger] = "#{year}#{params[:term].to_i == 1 ? "中期考核": "结项考核"} PR 检测邮件已全部发送完毕,一共#{examine_materials.count}封邮件"
redirect_to admins_glcc_pr_check_index_path
end
end

View File

@ -1,38 +0,0 @@
class Admins::IdentityVerificationsController < Admins::BaseController
before_action :require_business
before_action :finder_identity_verification, except: [:index]
def index
params[:sort_by] = params[:sort_by].presence || 'created_at'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
identity_verifications = Admins::IdentityVerificationQuery.call(params)
@identity_verifications = paginate identity_verifications.preload(:user)
end
def show
render 'edit'
end
def edit
end
def update
if update_params[:state] == "已拒绝" && update_params[:description].blank?
flash[:danger] = '拒绝理由不能为空'
render 'edit'
else
UserAction.create(action_id: @identity_verification.id, action_type: "UpdateIdentityVerifications", user_id: current_user.id, :ip => request.remote_ip, data_bank: @identity_verification.attributes.to_json)
@identity_verification.update(update_params)
redirect_to admins_identity_verifications_path
flash[:success] = "更新成功"
end
end
private
def finder_identity_verification
@identity_verification = IdentityVerification.find(params[:id])
@user = @identity_verification.user
end
def update_params
params.require(:identity_verification).permit(:state, :description)
end
end

View File

@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
def create def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportUserFromExcelService.call(params[:file].to_io) result = Admins::ImportUserService.call(params[:file].to_io)
render_ok(result) render_ok(result)
rescue Admins::ImportUserService::Error => ex rescue Admins::ImportUserService::Error => ex
render_error(ex) render_error(ex)

View File

@ -1,30 +0,0 @@
class Admins::IssuesRankController < Admins::BaseController
before_action :require_admin
def index
@statistics = DailyProjectStatistic.where('date >= ? AND date <= ?', begin_date, end_date)
@statistics = @statistics.group(:project_id).joins(:project).select("project_id,
sum(issues) as issues,
sum(closed_issues) as closed_issues,
projects.issues_count as issues_count")
@statistics = @statistics.order("#{sort_by} #{sort_direction}").limit(50)
end
private
def begin_date
params.fetch(:begin_date, (Date.yesterday-7.days).to_s)
end
def end_date
params.fetch(:end_date, Date.yesterday.to_s)
end
def sort_by
DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "issues")) ? params.fetch(:sort_by, "issues") : "issues"
end
def sort_direction
%w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc"
end
end

View File

@ -1,5 +1,4 @@
class Admins::LaboratoriesController < Admins::BaseController class Admins::LaboratoriesController < Admins::BaseController
before_action :require_admin
def index def index
default_sort('id', 'desc') default_sort('id', 'desc')

View File

@ -25,6 +25,6 @@ class Admins::LaboratorySettingsController < Admins::BaseController
params.permit(:identifier, :name, params.permit(:identifier, :name,
:nav_logo, :login_logo, :tab_logo, :oj_banner, :nav_logo, :login_logo, :tab_logo, :oj_banner,
:subject_banner, :course_banner, :competition_banner, :moop_cases_banner, :subject_banner, :course_banner, :competition_banner, :moop_cases_banner,
:footer, navbar: %i[name link hidden index]) :footer, navbar: %i[name link hidden])
end end
end end

View File

@ -1,26 +1,9 @@
class Admins::MessageTemplatesController < Admins::BaseController class Admins::MessageTemplatesController < Admins::BaseController
before_action :require_admin
before_action :get_template, only: [:edit, :update, :destroy] before_action :get_template, only: [:edit, :update, :destroy]
def index def index
message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result message_templates = MessageTemplate.group(:type).count.keys
@message_templates = kaminari_paginate(message_templates) @message_templates = kaminari_array_paginate(message_templates)
end
def new
@message_template = MessageTemplate::CustomTip.new
end
def create
@message_template = MessageTemplate::CustomTip.new
@message_template.attributes = message_template_params
if @message_template.save!
redirect_to admins_message_templates_path
flash[:success] = "创建消息模板成功"
else
render :new
flash[:danger] = "创建消息模板失败"
end
end end
def edit def edit

View File

@ -1,27 +0,0 @@
class Admins::NpsController < Admins::BaseController
before_action :require_business
def index
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
@user_nps = UserNp.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

View File

@ -1,45 +0,0 @@
class Admins::OrganizationsController < Admins::BaseController
before_action :require_admin
before_action :finder_org, except: [:index]
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
orgs = Admins::OrganizationQuery.call(params)
@orgs = paginate orgs
end
def open_cla
@org.open_cla!
render_ok
end
def close_cla
if @org.cla.nil?
@org.close_cla!
render_ok
else
render_error(' 该组织已创建CLA 不允许关闭')
end
end
def show
end
def destroy
@org.destroy!
Admins::DeleteOrganizationService.call(@org.login)
UserAction.create(action_id: @org.id, action_type: "DestroyOrganization", user_id: current_user.id, :ip => request.remote_ip, data_bank: @org.attributes.to_json)
render_delete_success
end
private
def finder_org
@org = Organization.find(params[:id])
end
end

View File

@ -1,80 +0,0 @@
class Admins::PageThemesController < Admins::BaseController
before_action :require_admin
before_action :finder_page_theme, only: [:edit, :update, :destroy]
def index
params[:sort_by] = params[:sort_by].presence || 'created_at'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
page_themes = Admins::PageThemesQuery.call(params)
@page_themes = paginate page_themes
end
def show
render 'edit'
end
def edit
end
def create
@page_theme = PageTheme.new theme_params
if @page_theme.save
save_image_file(params[:image])
redirect_to admins_page_themes_path
flash[:success] = "新增主题成功"
else
redirect_to admins_page_themes_path
flash[:danger] = "新增主题失败: #{@page_theme.errors.messages.values.flatten.join(',')}"
end
end
def destroy
if PageTheme.where(language_frame: @page_theme.language_frame).count <= 1
flash[:danger] = "删除主题失败,必须存在一个主题"
return redirect_to admins_page_themes_path
end
if @page_theme.destroy
redirect_to admins_page_themes_path
flash[:success] = "删除主题成功"
else
redirect_to admins_page_themes_path
flash[:danger] = "删除主题失败"
end
end
def new
@page_theme = PageTheme.new
end
def update
@page_theme.attributes = theme_params
if @page_theme.save
save_image_file(params[:image])
redirect_to admins_page_themes_path
flash[:success] = "更新成功"
else
redirect_to admins_page_themes_path
flash[:danger] = "更新失败"
end
end
private
def finder_page_theme
@page_theme = PageTheme.find(params[:id])
end
def theme_params
params.require(:page_theme).permit(:language_frame, :name, :cate, :image_url, :clone_url, :order_index)
end
def save_image_file(file)
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
file_path = Util::FileManage.source_disk_filename(@page_theme, "image")
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(file, file_path)
end
end

View File

@ -1,5 +1,4 @@
class Admins::ProjectCategoriesController < Admins::BaseController class Admins::ProjectCategoriesController < Admins::BaseController
before_action :require_admin
before_action :get_category, only: [:edit,:update, :destroy] before_action :get_category, only: [:edit,:update, :destroy]
before_action :validate_names, only: [:create, :update] before_action :validate_names, only: [:create, :update]
@ -23,7 +22,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
max_position_items = ProjectCategory.select(:id, :position).pluck(:position).reject!(&:blank?) max_position_items = ProjectCategory.select(:id, :position).pluck(:position).reject!(&:blank?)
max_position = max_position_items.present? ? max_position_items.max.to_i : 0 max_position = max_position_items.present? ? max_position_items.max.to_i : 0
@project_category = ProjectCategory.new(name: @name,position: max_position, pinned_index: params[:project_category][:pinned_index].to_i) @project_category = ProjectCategory.new(name: @name,position: max_position)
if @project_category.save if @project_category.save
redirect_to admins_project_categories_path redirect_to admins_project_categories_path
flash[:success] = '创建成功' flash[:success] = '创建成功'
@ -34,18 +33,17 @@ class Admins::ProjectCategoriesController < Admins::BaseController
end end
def update def update
if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i}) if @project_category.update_attribute(:name, @name)
save_image_file(params[:logo], 'logo')
redirect_to admins_project_categories_path redirect_to admins_project_categories_path
flash[:success] = '更新成功' flash[:success] = '更新成功'
else else
redirect_to admins_project_categories_path redirect_to admins_project_categories_path
flash[:danger] = '更新失败' flash[:success] = '更新失败'
end end
end end
def destroy def destroy
if @project_category.destroy if @project_language.destroy
redirect_to admins_project_categories_path redirect_to admins_project_categories_path
flash[:success] = "删除成功" flash[:success] = "删除成功"
else else
@ -82,12 +80,4 @@ class Admins::ProjectCategoriesController < Admins::BaseController
flash[:danger] = '分类已存在' flash[:danger] = '分类已存在'
end end
end end
def save_image_file(file, type)
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
file_path = Util::FileManage.source_disk_filename(@project_category, type)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(file, file_path)
end
end end

View File

@ -1,7 +1,6 @@
class Admins::ProjectIgnoresController < Admins::BaseController class Admins::ProjectIgnoresController < Admins::BaseController
before_action :require_admin
before_action :set_ignore, only: [:edit,:update, :destroy,:show] 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 def index
sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
@ -32,12 +31,12 @@ class Admins::ProjectIgnoresController < Admins::BaseController
# } # }
@project_ignore = Ignore.new(ignore_params) @project_ignore = Ignore.new(ignore_params)
if @project_ignore.save if @project_ignore.save!
redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
flash[:success] = "创建成功" flash[:success] = "创建成功"
else else
redirect_to admins_project_ignores_path render :new
flash[:danger] = @project_ignore.errors.full_messages.join(",") flash[:danger] = "创建失败"
end end
end end
@ -59,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController
redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
flash[:success] = "更新成功" flash[:success] = "更新成功"
else else
redirect_to admins_project_ignores_path render :edit
flash[:danger] = @project_ignore.errors.full_messages.join(",") flash[:danger] = "更新失败"
end end
end end
@ -99,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController
params.require(:ignore).permit(:name,:content) params.require(:ignore).permit(:name,:content)
end end
# def validate_params def validate_params
# name = params[:ignore][:name] name = params[:ignore][:name]
# if name.blank? if name.blank?
# flash[:danger] = "名称不允许为空" flash[:danger] = "名称不允许为空"
# redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
# elsif check_ignore_present?(name) && @project_ignore.blank? elsif check_ignore_present?(name) && @project_ignore.blank?
# flash[:danger] = "创建失败:名称已存在" flash[:danger] = "创建失败:名称已存在"
# redirect_to admins_project_ignores_path redirect_to admins_project_ignores_path
# end end
# end end
# def check_ignore_present?(name) def check_ignore_present?(name)
# return true if name.blank? return true if name.blank?
# name_downcase = name.downcase name_downcase = name.downcase
# name_upcase = name.upcase name_upcase = name.upcase
# name_first_big = name.capitalize name_first_big = name.capitalize
# Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big) Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
# end end
end end

View File

@ -1,5 +1,4 @@
class Admins::ProjectLanguagesController < Admins::BaseController class Admins::ProjectLanguagesController < Admins::BaseController
before_action :require_admin
before_action :get_language, only: [:edit,:update, :destroy] before_action :get_language, only: [:edit,:update, :destroy]
before_action :validate_names, only: [:create, :update] before_action :validate_names, only: [:create, :update]
@ -28,18 +27,17 @@ class Admins::ProjectLanguagesController < Admins::BaseController
flash[:success] = '创建成功' flash[:success] = '创建成功'
else else
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:danger] = @project_language.errors.full_messages.join(",") flash[:danger] = '创建失败'
end end
end end
def update def update
@project_language.attributes = {name: @name} if @project_language.update_attribute(:name, @name)
if @project_language.save
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:success] = '更新成功' flash[:success] = '更新成功'
else else
redirect_to admins_project_languages_path redirect_to admins_project_languages_path
flash[:danger] = @project_language.errors.full_messages.join(",") flash[:success] = '更新失败'
end end
end end

View File

@ -1,13 +1,12 @@
class Admins::ProjectLicensesController < Admins::BaseController class Admins::ProjectLicensesController < Admins::BaseController
before_action :require_admin
before_action :set_license, only: [:edit,:update, :destroy,:show] 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 def index
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc' sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
q = License.ransack(name_cont: params[:search]) q = License.ransack(name_cont: params[:search])
project_licenses = q.result(distinct: true).reorder("#{sort_by} #{sort_direction}") project_licenses = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
@project_licenses = paginate(project_licenses) @project_licenses = paginate(project_licenses)
end end
@ -31,12 +30,13 @@ class Admins::ProjectLicensesController < Admins::BaseController
# position: max_position # position: max_position
# } # }
@project_license = License.new(license_params) @project_license = License.new(license_params)
if @project_license.save
if @project_license.save!
redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
flash[:success] = "创建成功" flash[:success] = "创建成功"
else else
redirect_to admins_project_licenses_path render :new
flash[:danger] = @project_license.errors.full_messages.join(",") flash[:danger] = "创建失败"
end end
end end
@ -54,13 +54,12 @@ class Admins::ProjectLicensesController < Admins::BaseController
# permissions: permissions.to_s, # permissions: permissions.to_s,
# limitations: limitations.to_s # limitations: limitations.to_s
# } # }
@project_license.attributes = license_params if @project_license.update_attributes(license_params)
if @project_license.save
redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
flash[:success] = "更新成功" flash[:success] = "更新成功"
else else
render admins_project_licenses_path render :edit
flash[:danger] = @project_license.errors.full_messages.join(",") flash[:danger] = "更新失败"
end end
end end
@ -96,26 +95,26 @@ class Admins::ProjectLicensesController < Admins::BaseController
end end
def license_params def license_params
params.require(:license).permit(:name,:content,:position) params.require(:license).permit(:name,:content)
end end
# def validate_params def validate_params
# name = params[:license][:name] name = params[:license][:name]
# if name.blank? if name.blank?
# flash[:danger] = "名称不允许为空" flash[:danger] = "名称不允许为空"
# redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
# elsif check_license_present?(name) && @project_license.blank? elsif check_license_present?(name) && @project_license.blank?
# flash[:danger] = "创建失败:名称已存在" flash[:danger] = "创建失败:名称已存在"
# redirect_to admins_project_licenses_path redirect_to admins_project_licenses_path
# end end
# end end
# def check_license_present?(name) def check_license_present?(name)
# return true if name.blank? return true if name.blank?
# name_downcase = name.downcase name_downcase = name.downcase
# name_upcase = name.upcase name_upcase = name.upcase
# name_first_big = name.capitalize name_first_big = name.capitalize
# License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big) License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
# end end
end end

View File

@ -1,56 +1,19 @@
class Admins::ProjectsController < Admins::BaseController class Admins::ProjectsController < Admins::BaseController
before_action :require_admin
before_action :find_project, only: [:edit, :update]
def index def index
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on' sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc' sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
search = params[:search].to_s.strip search = params[:search].to_s.strip
projects = Project.where("id = ? OR name like ? OR identifier LIKE ?", search, "%#{search}%", "%#{search}%").order("#{sort_by} #{sort_direction}") projects = Project.where("name like ?", "%#{search}%").order("#{sort_by} #{sort_direction}")
case params[:category]
when 'public'
projects = projects.where(is_public: true)
when 'private'
projects = projects.where(is_public: false)
when 'fork'
projects = projects.where.not(forked_from_project_id: nil)
when 'original'
projects = projects.where(forked_from_project_id: nil, project_type: 'common')
end
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score) @projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
end end
def edit ;end
def update
respond_to do |format|
if @project.update_attributes(project_update_params)
format.html do
redirect_to admins_projects_path
flash[:sucess] = "更新成功"
end
format.js {render_ok}
else
format.html do
redirect_to admins_projects_path
flash[:danger] = "更新失败"
end
format.js {render_js_error}
end
end
end
def destroy def destroy
project = Project.find_by!(id: params[:id]) project = Project.find_by!(id: params[:id])
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
close_fork_pull_requests_by(project) Gitea::Repository::DeleteService.new(project.owner, project.identifier).call
Gitea::Repository::DeleteService.new(project.owner, project.identifier, current_user.gitea_token).call
project.destroy! 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_delete_success # render_delete_success
UserAction.create(action_id: project.id, action_type: "DestroyProject", user_id: current_user.id, :ip => request.remote_ip, data_bank: project.attributes.to_json)
redirect_to admins_projects_path redirect_to admins_projects_path
flash[:success] = "删除成功" flash[:success] = "删除成功"
end end
@ -58,28 +21,4 @@ class Admins::ProjectsController < Admins::BaseController
redirect_to admins_projects_path redirect_to admins_projects_path
flash[:danger] = "删除失败" flash[:danger] = "删除失败"
end end
private
def find_project
@project = Project.find_by_id(params[:id])
end
def project_update_params
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
end
def close_fork_pull_requests_by(project)
open_pull_requests = PullRequest.where(fork_project_id: project.id)
if open_pull_requests.present?
open_pull_requests.each do |pull_request|
closed = PullRequests::CloseService.call(pull_request&.project.owner, pull_request&.project.repository, pull_request, current_user)
if closed === true
pull_request.project_trends.create!(user: current_user, project: pull_request&.project,action_type: ProjectTrend::CLOSE)
# 合并请求下issue处理为关闭
pull_request.issue&.update_attributes!({status_id:5})
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
end
end
end
end
end end

View File

@ -1,60 +0,0 @@
class Admins::ProjectsRankController < Admins::BaseController
before_action :require_admin
def index
@statistics = DailyProjectStatistic.where("date >= ? AND date <= ?", begin_date, end_date)
@statistics = @statistics.group(:project_id).select("project_id,
sum(score) as score,
sum(visits) as visits,
sum(watchers) as watchers,
sum(praises) as praises,
sum(forks) as forks,
sum(issues) as issues,
sum(pullrequests) as pullrequests,
sum(commits) as commits").includes(:project)
@statistics = paginate @statistics.order("#{sort_by} #{sort_direction}")
export_excel(@statistics.limit(50))
end
private
def begin_date
params.fetch(:begin_date, (Date.yesterday-7.days).to_s)
end
def end_date
params.fetch(:end_date, Date.yesterday.to_s)
end
def sort_by
DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "score")) ? params.fetch(:sort_by, "score") : "score"
end
def sort_direction
%w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc"
end
def export_excel(data)
book = Spreadsheet::Workbook.new
sheet = book.create_worksheet :name => "项目活跃度排行"
sheet.row(0).concat %w(排名 项目全称 项目地址 项目分类 首次创建时间 外部迁移/独立创建 得分 访问数 关注数 点赞数 fork数 疑修数 合并请求数 提交数)
data.each_with_index do |d, index|
sheet[index+1,0] = index+1
sheet[index+1,1] = "#{d&.project&.owner&.real_name}/#{d&.project&.name}"
sheet[index+1,2] = "#{Rails.application.config_for(:configuration)['platform_url']}/#{d&.project&.owner&.login}/#{d&.project&.identifier}"
sheet[index+1,3] = d&.project&.project_category&.name
sheet[index+1,4] = d&.project&.created_on.present? ? d&.project&.created_on.strftime("%Y-%m-%d %H:%M:%S") : ""
sheet[index+1,5] = d&.project&.common? ? "独立创建" : "外部迁移"
sheet[index+1,6] = d.score
sheet[index+1,7] = d.visits
sheet[index+1,8] = d.watchers
sheet[index+1,9] = d.praises
sheet[index+1,10] = d.forks
sheet[index+1,11] = d.issues
sheet[index+1,12] = d.pullrequests
sheet[index+1,13] = d.commits
end
book.write "#{Rails.root}/public/项目活跃度排行.xls"
end
end

View File

@ -1,5 +1,4 @@
class Admins::ReversedKeywordsController < Admins::BaseController class Admins::ReversedKeywordsController < Admins::BaseController
before_action :require_admin
before_action :get_keyword, only: [:edit,:update, :destroy] before_action :get_keyword, only: [:edit,:update, :destroy]
# before_action :validate_identifer, only: [:create, :update] # before_action :validate_identifer, only: [:create, :update]

View File

@ -1,51 +0,0 @@
class Admins::SitePagesController < Admins::BaseController
before_action :require_admin
before_action :finder_site_page, except: [:index]
def index
params[:sort_by] = params[:sort_by].presence || 'created_at'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
pages = Admins::SitePagesQuery.call(params)
@site_pages = paginate pages.preload(:user)
end
def show
render 'edit'
end
def edit
end
def destroy
if @site_page.destroy
redirect_to admins_site_pages_path
flash[:success] = "删除站点成功"
else
redirect_to admins_site_pages_path
flash[:danger] = "删除站点失败"
end
end
def update
if update_params[:state] == "false" && update_params[:state_description].blank?
flash[:danger] = '关闭站点理由不能为空'
else
@site_page.update(update_params)
flash[:success] = '保存成功'
end
render 'edit'
end
private
def finder_site_page
@site_page = Page.find(params[:id])
@user = @site_page.user
end
def update_params
params.require(:page).permit(:state, :state_description)
end
end

View File

@ -1,5 +1,4 @@
class Admins::SitesController < Admins::BaseController class Admins::SitesController < Admins::BaseController
before_action :require_admin
before_action :find_site, only: [:edit,:update, :destroy] before_action :find_site, only: [:edit,:update, :destroy]
def index def index

View File

@ -1,5 +1,4 @@
class Admins::SystemNotificationsController < Admins::BaseController class Admins::SystemNotificationsController < Admins::BaseController
before_action :require_business
before_action :get_notification, only: [:history, :edit,:update, :destroy] before_action :get_notification, only: [:history, :edit,:update, :destroy]
# before_action :validate_identifer, only: [:create, :update] # before_action :validate_identifer, only: [:create, :update]
@ -11,10 +10,6 @@ class Admins::SystemNotificationsController < Admins::BaseController
@notifications = paginate(notifications) @notifications = paginate(notifications)
end end
def history
@users = @notification.users
end
def new def new
@notification = SystemNotification.new @notification = SystemNotification.new
end end
@ -26,7 +21,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
@notification = SystemNotification.new(notification_params) @notification = SystemNotification.new(notification_params)
if @notification.save if @notification.save
redirect_to admins_system_notifications_path redirect_to admins_system_notifications_path
flash[:success] = '系统公告创建成功' flash[:success] = '系统消息创建成功'
else else
redirect_to admins_system_notifications_path redirect_to admins_system_notifications_path
flash[:danger] = @notification.errors.full_messages.join(",") flash[:danger] = @notification.errors.full_messages.join(",")
@ -38,7 +33,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
if @notification.update_attributes(notification_params) if @notification.update_attributes(notification_params)
format.html do format.html do
redirect_to admins_system_notifications_path redirect_to admins_system_notifications_path
flash[:success] = '系统公告更新成功' flash[:success] = '系统消息更新成功'
end end
format.js {render_ok} format.js {render_ok}
else else
@ -54,10 +49,10 @@ class Admins::SystemNotificationsController < Admins::BaseController
def destroy def destroy
if @notification.destroy if @notification.destroy
redirect_to admins_system_notifications_path redirect_to admins_system_notifications_path
flash[:success] = "系统公告删除成功" flash[:success] = "系统消息删除成功"
else else
redirect_to admins_system_notifications_path redirect_to admins_system_notifications_path
flash[:danger] = "系统公告删除失败" flash[:danger] = "系统消息删除失败"
end end
end end

View File

@ -1,58 +0,0 @@
class Admins::Topic::ActivityForumsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_activity_forum, only: [:edit, :update, :destroy]
def index
q = ::Topic::ActivityForum.ransack(title_cont: params[:search])
activity_forums = q.result(distinct: true)
@activity_forums = paginate(activity_forums)
end
def new
@activity_forum = ::Topic::ActivityForum.new
end
def create
@activity_forum = ::Topic::ActivityForum.new(activity_forum_params)
if @activity_forum.save
redirect_to admins_topic_activity_forums_path
flash[:success] = "新增平台动态成功"
else
redirect_to admins_topic_activity_forums_path
flash[:danger] = "新增平台动态失败"
end
end
def edit
end
def update
@activity_forum.attributes = activity_forum_params
if @activity_forum.save
redirect_to admins_topic_activity_forums_path
flash[:success] = "更新平台动态成功"
else
redirect_to admins_topic_activity_forums_path
flash[:danger] = "更新平台动态失败"
end
end
def destroy
if @activity_forum.destroy
redirect_to admins_topic_activity_forums_path
flash[:success] = "删除平台动态成功"
else
redirect_to admins_topic_activity_forums_path
flash[:danger] = "删除平台动态失败"
end
end
private
def find_activity_forum
@activity_forum = ::Topic::ActivityForum.find_by_id(params[:id])
end
def activity_forum_params
params.require(:topic_activity_forum).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -1,59 +0,0 @@
class Admins::Topic::BannersController < Admins::Topic::BaseController
before_action :require_business
before_action :find_banner, only: [:edit, :update, :destroy]
def index
@banners = paginate(::Topic::Banner)
@banners = paginate(::Topic::Banner.where("title like ?", "%#{params[:search]}%")) if params[:search].present?
end
def new
@banner = ::Topic::Banner.new
end
def create
@banner = ::Topic::Banner.new(banner_params)
if @banner.save
save_image_file(params[:image], @banner)
redirect_to admins_topic_banners_path
flash[:success] = "新增banner成功"
else
redirect_to admins_topic_banners_path
flash[:danger] = "新增banner失败"
end
end
def edit
end
def update
@banner.attributes = banner_params
if @banner.save
save_image_file(params[:image], @banner)
redirect_to admins_topic_banners_path
flash[:success] = "更新banner成功"
else
redirect_to admins_topic_banners_path
flash[:danger] = "更新banner失败"
end
end
def destroy
if @banner.destroy
redirect_to admins_topic_banners_path
flash[:success] = "删除banner成功"
else
redirect_to admins_topic_banners_path
flash[:danger] = "删除banner失败"
end
end
private
def find_banner
@banner = ::Topic::Banner.find_by_id(params[:id])
end
def banner_params
params.require(:topic_banner).permit(:title, :order_index, :url)
end
end

View File

@ -1,11 +0,0 @@
class Admins::Topic::BaseController < Admins::BaseController
protected
def save_image_file(file, topic)
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
file_path = Util::FileManage.source_disk_filename(topic, 'image')
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(file, file_path)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::CardsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_card, only: [:edit, :update, :destroy]
def index
q = ::Topic::Card.ransack(title_cont: params[:search])
cards = q.result(distinct: true)
@cards = paginate(cards)
end
def new
@card = ::Topic::Card.new
end
def create
@card = ::Topic::Card.new(card_params)
if @card.save
redirect_to admins_topic_cards_path
flash[:success] = "新增合作单位成功"
else
redirect_to admins_topic_cards_path
flash[:danger] = "新增合作单位失败"
end
end
def edit
end
def update
@card.attributes = card_params
if @card.save
redirect_to admins_topic_cards_path
flash[:success] = "更新合作单位成功"
else
redirect_to admins_topic_cards_path
flash[:danger] = "更新合作单位失败"
end
end
def destroy
if @card.destroy
redirect_to admins_topic_cards_path
flash[:success] = "删除合作单位成功"
else
redirect_to admins_topic_cards_path
flash[:danger] = "删除合作单位失败"
end
end
private
def find_card
@card = ::Topic::Card.find_by_id(params[:id])
end
def card_params
params.require(:topic_card).permit(:title, :url, :order_index)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::CooperatorsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_cooperator, only: [:edit, :update, :destroy]
def index
@cooperators = paginate(::Topic::Cooperator)
end
def new
@cooperator = ::Topic::Cooperator.new
end
def create
@cooperator = ::Topic::Cooperator.new(cooperator_params)
if @cooperator.save
save_image_file(params[:image], @cooperator)
redirect_to admins_topic_cooperators_path
flash[:success] = "新增合作单位成功"
else
redirect_to admins_topic_cooperators_path
flash[:danger] = "新增合作单位失败"
end
end
def edit
end
def update
@cooperator.attributes = cooperator_params
if @cooperator.save
save_image_file(params[:image], @cooperator)
redirect_to admins_topic_cooperators_path
flash[:success] = "更新合作单位成功"
else
redirect_to admins_topic_cooperators_path
flash[:danger] = "更新合作单位失败"
end
end
def destroy
if @cooperator.destroy
redirect_to admins_topic_cooperators_path
flash[:success] = "删除合作单位成功"
else
redirect_to admins_topic_cooperators_path
flash[:danger] = "删除合作单位失败"
end
end
private
def find_cooperator
@cooperator = ::Topic::Cooperator.find_by_id(params[:id])
end
def cooperator_params
params.require(:topic_cooperator).permit(:title, :url, :order_index)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::ExcellentProjectsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_excellent_project, only: [:edit, :update, :destroy]
def index
q = ::Topic::ExcellentProject.ransack(title_cont: params[:search])
excellent_projects = q.result(distinct: true)
@excellent_projects = paginate(excellent_projects)
end
def new
@excellent_project = ::Topic::ExcellentProject.new
end
def create
@excellent_project = ::Topic::ExcellentProject.new(excellent_project_params)
if @excellent_project.save
redirect_to admins_topic_excellent_projects_path
flash[:success] = "新增优秀仓库成功"
else
redirect_to admins_topic_excellent_projects_path
flash[:danger] = "新增优秀仓库失败"
end
end
def edit
end
def update
@excellent_project.attributes = excellent_project_params
if @excellent_project.save
redirect_to admins_topic_excellent_projects_path
flash[:success] = "更新优秀仓库成功"
else
redirect_to admins_topic_excellent_projects_path
flash[:danger] = "更新优秀仓库失败"
end
end
def destroy
if @excellent_project.destroy
redirect_to admins_topic_excellent_projects_path
flash[:success] = "删除优秀仓库成功"
else
redirect_to admins_topic_excellent_projects_path
flash[:danger] = "删除优秀仓库失败"
end
end
private
def find_excellent_project
@excellent_project = ::Topic::ExcellentProject.find_by_id(params[:id])
end
def excellent_project_params
params.require(:topic_excellent_project).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::ExperienceForumsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_experience_forum, only: [:edit, :update, :destroy]
def index
q = ::Topic::ExperienceForum.ransack(title_cont: params[:search])
experience_forums = q.result(distinct: true)
@experience_forums = paginate(experience_forums)
end
def new
@experience_forum = ::Topic::ExperienceForum.new
end
def create
@experience_forum = ::Topic::ExperienceForum.new(experience_forum_params)
if @experience_forum.save
redirect_to admins_topic_experience_forums_path
flash[:success] = "新增经验分享成功"
else
redirect_to admins_topic_experience_forums_path
flash[:danger] = "新增经验分享失败"
end
end
def edit
end
def update
@experience_forum.attributes = experience_forum_params
if @experience_forum.save
redirect_to admins_topic_experience_forums_path
flash[:success] = "更新经验分享成功"
else
redirect_to admins_topic_experience_forums_path
flash[:danger] = "更新经验分享失败"
end
end
def destroy
if @experience_forum.destroy
redirect_to admins_topic_experience_forums_path
flash[:success] = "删除经验分享成功"
else
redirect_to admins_topic_experience_forums_path
flash[:danger] = "删除经验分享失败"
end
end
private
def find_experience_forum
@experience_forum = ::Topic::ExperienceForum.find_by_id(params[:id])
end
def experience_forum_params
params.require(:topic_experience_forum).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
before_action :require_glcc_admin
before_action :find_glcc, only: [:edit, :update, :destroy]
def index
q = ::Topic::GlccNews.ransack(title_cont: params[:search])
glcc_news = q.result(distinct: true)
@glcc_news = paginate(glcc_news)
end
def new
@glcc = ::Topic::GlccNews.new
end
def create
@glcc = ::Topic::GlccNews.new(glcc_params)
if @glcc.save
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "新增新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "新增新闻稿失败"
end
end
def edit
end
def update
@glcc.attributes = glcc_params
if @glcc.save
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "更新新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "更新新闻稿失败"
end
end
def destroy
if @glcc.destroy
redirect_to admins_topic_glcc_news_index_path
flash[:success] = "删除新闻稿成功"
else
redirect_to admins_topic_glcc_news_index_path
flash[:danger] = "删除新闻稿失败"
end
end
private
def find_glcc
@glcc = ::Topic::GlccNews.find_by_id(params[:id])
end
def glcc_params
params.require(:topic_glcc_news).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -1,58 +0,0 @@
class Admins::Topic::PinnedForumsController < Admins::Topic::BaseController
before_action :require_business
before_action :find_pinned_forum, only: [:edit, :update, :destroy]
def index
q = ::Topic::PinnedForum.ransack(title_cont: params[:search])
pinned_forums = q.result(distinct: true)
@pinned_forums = paginate(pinned_forums)
end
def new
@pinned_forum = ::Topic::PinnedForum.new
end
def create
@pinned_forum = ::Topic::PinnedForum.new(pinned_forum_params)
if @pinned_forum.save
redirect_to admins_topic_pinned_forums_path
flash[:success] = "新增精选文章成功"
else
redirect_to admins_topic_pinned_forums_path
flash[:danger] = "新增精选文章失败"
end
end
def edit
end
def update
@pinned_forum.attributes = pinned_forum_params
if @pinned_forum.save
redirect_to admins_topic_pinned_forums_path
flash[:success] = "更新精选文章成功"
else
redirect_to admins_topic_pinned_forums_path
flash[:danger] = "更新精选文章失败"
end
end
def destroy
if @pinned_forum.destroy
redirect_to admins_topic_pinned_forums_path
flash[:success] = "删除精选文章成功"
else
redirect_to admins_topic_pinned_forums_path
flash[:danger] = "删除精选文章失败"
end
end
private
def find_pinned_forum
@pinned_forum = ::Topic::PinnedForum.find_by_id(params[:id])
end
def pinned_forum_params
params.require(:topic_pinned_forum).permit(:title, :uuid, :url, :order_index)
end
end

View File

@ -1,14 +0,0 @@
class Admins::UserActionsController < Admins::BaseController
before_action :require_admin
def index
@user_actions = UserAction.order(created_at: :desc)
@user_actions = @user_actions.where(action_type: params[:action_type]) if params[:action_type].present?
keyword = params[:keyword].to_s.strip.presence
if keyword
sql = 'login LIKE :keyword OR phone LIKE :keyword OR email LIKE :keyword'
@user_actions = @user_actions.where(sql, keyword: "%#{keyword}%")
end
@user_actions = paginate @user_actions
end
end

View File

@ -1,7 +1,4 @@
class Admins::UsersController < Admins::BaseController class Admins::UsersController < Admins::BaseController
before_action :require_admin
before_action :finder_user, except: [:index]
def index def index
params[:sort_by] = params[:sort_by].presence || 'created_on' params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc' params[:sort_direction] = params[:sort_direction].presence || 'desc'
@ -11,9 +8,12 @@ class Admins::UsersController < Admins::BaseController
end end
def edit def edit
@user = User.find(params[:id])
end end
def update def update
@user = User.find(params[:id])
Admins::UpdateUserService.call(@user, update_params) Admins::UpdateUserService.call(@user, update_params)
flash[:success] = '保存成功' flash[:success] = '保存成功'
redirect_to edit_admins_user_path(@user) redirect_to edit_admins_user_path(@user)
@ -26,74 +26,43 @@ class Admins::UsersController < Admins::BaseController
end end
def destroy def destroy
UserAction.create(action_id: @user.id, action_type: "DestroyUser", user_id: current_user.id, :ip => request.remote_ip, data_bank: @user.attributes.to_json) User.find(params[:id]).destroy!
# org_ids = TeamUser.where(user_id: @user.id).pluck(:organization_id) | OrganizationUser.where(user_id: @user.id).pluck(:organization_id)
# organizations = Organization.where(id: org_ids)
# organizations.each do |org|
# # org.team_users.joins(:team).where(user_id: @user.id, teams: {authorize: %w(owner)})
# owner_count = org.team_users.joins(:team).where(teams: {authorize: %w(owner)}).count
# # 多个owner时,仅将用户从组织移除, 一个时直接删除
# if owner_count > 1
# org.team_users.joins(:team).where(user_id: @user.id, teams: {authorize: %w(owner)}).destroy_all
# org.organization_users.where(user_id: @user.id, organization_id: org.id).destroy_all
# else
# org.destroy
# end
# end
# @user.destroy!
# Gitea::User::DeleteService.call(@user.login, true)
#
# render_delete_success
@result_object = Api::V1::Users::DeleteUserService.call(@user) render_delete_success
if @result_object
render_delete_success
else
render_js_error('删除失败!')
end
end end
def lock def lock
@user.lock! User.find(params[:id]).lock!
UserAction.create(action_id: @user.id, action_type: "LockUser", user_id: current_user.id, :ip => request.remote_ip)
render_ok render_ok
end end
def unlock def unlock
@user.activate! User.find(params[:id]).activate!
render_ok render_ok
end end
def reward_grade def reward_grade
user = User.find(params[:user_id])
return render_unprocessable_entity('金币数量必须大于0') if params[:grade].to_i <= 0 return render_unprocessable_entity('金币数量必须大于0') if params[:grade].to_i <= 0
RewardGradeService.call(@user, container_id: @user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true) RewardGradeService.call(user, container_id: user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
render_ok(grade: @user.grade) render_ok(grade: user.grade)
end end
def reset_login_times def reset_login_times
@user.reset_login_times! User.find(params[:id]).reset_login_times!
render_ok render_ok
end end
def fresh_gitea_token
@user.fresh_gitea_token
render_ok
end
private private
def finder_user
@user = User.find(params[:id])
end
def update_params def update_params
params.require(:user).permit(%i[lastname nickname gender technical_title is_shixun_marker params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
mail phone location location_city school_id department_id admin mail phone location location_city school_id department_id admin business is_test
password login website_permission business glcc_admin]) password professional_certification authentication])
end end
end end

View File

@ -1,16 +0,0 @@
class Admins::UsersRankController < Admins::BaseController
before_action :require_admin
def index
@rank_date = rank_date
@date_rank = $redis_cache.zrevrange("v2-user-rank-#{rank_date}", 0, -1, withscores: true)
end
private
def rank_date
params.fetch(:date, Date.today.to_s)
end
end

View File

@ -1,45 +0,0 @@
class Api::Pm::ActionRunsController < Api::Pm::BaseController
before_action :require_login
def index
tip_exception('请输入workflows') if params[:workflows].blank?
@owner = Owner.find_by(login: params[:owner_id].to_s) || Owner.find_by(id: params[:owner_id].to_s)
tip_exception('组织未找到') if @owner.blank?
action_runs = Gitea::ActionRun.where(owner_id: @owner.gitea_uid)
group_data = action_runs.where(workflow_id: params[:workflows].to_s.split(",")).where(status: [1,2]).group(:workflow_id, :status).count
@result = []
params[:workflows].to_s.split(",").each do |file|
last_action_run = action_runs.where(workflow_id: file).order(updated: :desc).first
last_action_run_json = last_action_run.present? ? {
id: last_action_run.id,
schedule: last_action_run.schedule_id > 0,
title: last_action_run.title,
index: last_action_run.index,
status: last_action_run.status,
started: last_action_run.started,
stopped: last_action_run.stopped,
length: last_action_run.stopped - last_action_run.started,
created: last_action_run.created,
updated: last_action_run.updated,
} : {}
total = 0
success = 0
failure = 0
group_data.each do |k,v|
total += v if k[0] == file
success += v if k[0] == file && k[1] == 1
failure += v if k[0] == file && k[1] == 2
end
@result << {
name: file,
total: total,
success: success,
failure: failure
}.merge(last_action_run_json)
end
render :json => {data: @result}
end
end

View File

@ -1,60 +0,0 @@
class Api::Pm::BaseController < ApplicationController
include Api::ProjectHelper
include Api::UserHelper
include Api::PullHelper
# before_action :doorkeeper_authorize!
# skip_before_action :user_setup
protected
def kaminary_select_paginate(relation)
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 200) ? 200 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
relation.page(page).per(limit)
end
def limit
params.fetch(:limit, 15)
end
def page
params.fetch(:page, 1)
end
def load_project
@project = Project.find_by_id(params[:project_id]) || Project.new(id: 0, user_id: 0, name: 'pm_mm', identifier: 'pm_mm', is_public:true)
end
def load_issue
# return render_parameter_missing if params[:pm_project_id].blank?
@issue = Issue.issue_issue.find_by_id(params[:issue_id])
render_not_found('疑修不存在!') if @issue.blank?
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
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

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