| @@ -1,47 +1,47 @@ | |||
| GEM | |||
| remote: https://mirrors.cloud.tencent.com/rubygems/ | |||
| specs: | |||
| aasm (5.5.0) | |||
| aasm (5.0.6) | |||
| concurrent-ruby (~> 1.0) | |||
| actioncable (5.2.8.1) | |||
| actionpack (= 5.2.8.1) | |||
| actioncable (5.2.4.1) | |||
| actionpack (= 5.2.4.1) | |||
| nio4r (~> 2.0) | |||
| websocket-driver (>= 0.6.1) | |||
| actionmailer (5.2.8.1) | |||
| actionpack (= 5.2.8.1) | |||
| actionview (= 5.2.8.1) | |||
| activejob (= 5.2.8.1) | |||
| actionmailer (5.2.4.1) | |||
| actionpack (= 5.2.4.1) | |||
| actionview (= 5.2.4.1) | |||
| activejob (= 5.2.4.1) | |||
| mail (~> 2.5, >= 2.5.4) | |||
| rails-dom-testing (~> 2.0) | |||
| actionpack (5.2.8.1) | |||
| actionview (= 5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| actionpack (5.2.4.1) | |||
| actionview (= 5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| rack (~> 2.0, >= 2.0.8) | |||
| rack-test (>= 0.6.3) | |||
| rails-dom-testing (~> 2.0) | |||
| rails-html-sanitizer (~> 1.0, >= 1.0.2) | |||
| actionview (5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| actionview (5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| builder (~> 3.1) | |||
| erubi (~> 1.4) | |||
| rails-dom-testing (~> 2.0) | |||
| rails-html-sanitizer (~> 1.0, >= 1.0.3) | |||
| active_decorator (1.4.0) | |||
| active_decorator (1.3.2) | |||
| activesupport | |||
| activejob (5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| activejob (5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| globalid (>= 0.3.6) | |||
| activemodel (5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| activerecord (5.2.8.1) | |||
| activemodel (= 5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| activemodel (5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| activerecord (5.2.4.1) | |||
| activemodel (= 5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| arel (>= 9.0) | |||
| activestorage (5.2.8.1) | |||
| actionpack (= 5.2.8.1) | |||
| activerecord (= 5.2.8.1) | |||
| marcel (~> 1.0.0) | |||
| activesupport (5.2.8.1) | |||
| activestorage (5.2.4.1) | |||
| actionpack (= 5.2.4.1) | |||
| activerecord (= 5.2.4.1) | |||
| marcel (~> 0.3.1) | |||
| activesupport (5.2.4.1) | |||
| concurrent-ruby (~> 1.0, >= 1.0.2) | |||
| i18n (>= 0.7, < 2) | |||
| minitest (~> 5.1) | |||
| @@ -50,20 +50,20 @@ GEM | |||
| activerecord (>= 5.0, < 6.1) | |||
| acts_as_list (0.9.19) | |||
| activerecord (>= 3.0) | |||
| addressable (2.8.4) | |||
| public_suffix (>= 2.0.2, < 6.0) | |||
| ancestry (4.0.0) | |||
| activerecord (>= 5.2.4.5) | |||
| annotate (2.6.7) | |||
| addressable (2.7.0) | |||
| public_suffix (>= 2.0.2, < 5.0) | |||
| ancestry (3.0.7) | |||
| activerecord (>= 3.2.0) | |||
| annotate (2.6.5) | |||
| activerecord (>= 2.3.0) | |||
| rake (~> 10.4.2, >= 10.4.2) | |||
| rake (>= 0.8.7) | |||
| archive-zip (0.12.0) | |||
| io-like (~> 0.3.0) | |||
| arel (9.0.0) | |||
| ast (2.4.2) | |||
| autoprefixer-rails (10.4.13.0) | |||
| execjs (~> 2) | |||
| awesome_print (1.9.2) | |||
| ast (2.4.0) | |||
| autoprefixer-rails (9.7.4) | |||
| execjs | |||
| awesome_print (1.8.0) | |||
| axlsx (3.0.0.pre) | |||
| htmlentities (~> 4.3, >= 4.3.4) | |||
| mimemagic (~> 0.3) | |||
| @@ -72,40 +72,40 @@ GEM | |||
| axlsx_rails (0.5.2) | |||
| actionpack (>= 3.1) | |||
| axlsx (>= 2.0.1) | |||
| backport (1.2.0) | |||
| benchmark (0.2.1) | |||
| backport (1.1.2) | |||
| benchmark (0.1.0) | |||
| bindex (0.8.1) | |||
| bootsnap (1.12.0) | |||
| msgpack (~> 1.2) | |||
| bootsnap (1.4.6) | |||
| msgpack (~> 1.0) | |||
| bootstrap (4.3.1) | |||
| autoprefixer-rails (>= 9.1.0) | |||
| popper_js (>= 1.14.3, < 2) | |||
| sassc-rails (>= 2.0.0) | |||
| builder (3.2.4) | |||
| bulk_insert (1.9.0) | |||
| bulk_insert (1.7.0) | |||
| activerecord (>= 3.2.0) | |||
| capybara (3.32.2) | |||
| capybara (3.15.1) | |||
| addressable | |||
| mini_mime (>= 0.1.3) | |||
| nokogiri (~> 1.8) | |||
| rack (>= 1.6.0) | |||
| rack-test (>= 0.6.3) | |||
| regexp_parser (~> 1.5) | |||
| regexp_parser (~> 1.2) | |||
| xpath (~> 3.2) | |||
| chartkick (3.4.2) | |||
| chartkick (3.3.1) | |||
| childprocess (3.0.0) | |||
| chinese_pinyin (1.1.0) | |||
| chinese_pinyin (1.0.2) | |||
| chromedriver-helper (2.1.1) | |||
| archive-zip (~> 0.10) | |||
| nokogiri (~> 1.8) | |||
| chunky_png (1.4.0) | |||
| concurrent-ruby (1.2.2) | |||
| connection_pool (2.2.5) | |||
| chunky_png (1.3.11) | |||
| concurrent-ruby (1.1.6) | |||
| connection_pool (2.2.2) | |||
| crass (1.0.6) | |||
| deep_cloneable (3.0.0) | |||
| activerecord (>= 3.1.0, < 7) | |||
| diff-lcs (1.5.0) | |||
| diffy (3.4.2) | |||
| diff-lcs (1.3) | |||
| diffy (3.3.0) | |||
| domain_name (0.5.20190701) | |||
| unf (>= 0.0.5, < 1.0.0) | |||
| doorkeeper (5.5.1) | |||
| @@ -121,19 +121,19 @@ GEM | |||
| elasticsearch-transport (7.5.0) | |||
| faraday (>= 0.14, < 1) | |||
| multi_json | |||
| enumerize (2.5.0) | |||
| enumerize (2.3.1) | |||
| activesupport (>= 3.2) | |||
| erubi (1.12.0) | |||
| et-orbi (1.2.7) | |||
| erubi (1.9.0) | |||
| et-orbi (1.2.4) | |||
| tzinfo | |||
| execjs (2.8.1) | |||
| execjs (2.7.0) | |||
| faraday (0.15.4) | |||
| multipart-post (>= 1.2, < 3) | |||
| ffi (1.15.5) | |||
| ffi (1.12.2) | |||
| font-awesome-sass (4.7.0) | |||
| sass (>= 3.2) | |||
| fugit (1.8.1) | |||
| et-orbi (~> 1, >= 1.2.7) | |||
| fugit (1.4.1) | |||
| et-orbi (~> 1.1, >= 1.1.8) | |||
| raabro (~> 1.4) | |||
| gitea-client (1.4.2) | |||
| rest-client (~> 2.1.0) | |||
| @@ -145,78 +145,78 @@ GEM | |||
| groupdate (4.1.2) | |||
| activesupport (>= 4.2) | |||
| harmonious_dictionary (0.0.1) | |||
| hashie (5.0.0) | |||
| hashie (3.6.0) | |||
| htmlentities (4.3.4) | |||
| http-accept (1.7.0) | |||
| http-cookie (1.0.5) | |||
| domain_name (~> 0.5) | |||
| i18n (1.13.0) | |||
| i18n (1.8.2) | |||
| concurrent-ruby (~> 1.0) | |||
| io-like (0.3.1) | |||
| jaro_winkler (1.5.5) | |||
| jbuilder (2.11.5) | |||
| actionview (>= 5.0.0) | |||
| jaro_winkler (1.5.4) | |||
| jbuilder (2.10.0) | |||
| activesupport (>= 5.0.0) | |||
| jquery-rails (4.5.1) | |||
| jquery-rails (4.3.5) | |||
| rails-dom-testing (>= 1, < 3) | |||
| railties (>= 4.2.0) | |||
| thor (>= 0.14, < 2.0) | |||
| jwt (2.3.0) | |||
| kaminari (1.2.2) | |||
| jwt (2.2.1) | |||
| kaminari (1.2.0) | |||
| activesupport (>= 4.1.0) | |||
| kaminari-actionview (= 1.2.2) | |||
| kaminari-activerecord (= 1.2.2) | |||
| kaminari-core (= 1.2.2) | |||
| kaminari-actionview (1.2.2) | |||
| kaminari-actionview (= 1.2.0) | |||
| kaminari-activerecord (= 1.2.0) | |||
| kaminari-core (= 1.2.0) | |||
| kaminari-actionview (1.2.0) | |||
| actionview | |||
| kaminari-core (= 1.2.2) | |||
| kaminari-activerecord (1.2.2) | |||
| kaminari-core (= 1.2.0) | |||
| kaminari-activerecord (1.2.0) | |||
| activerecord | |||
| kaminari-core (= 1.2.2) | |||
| kaminari-core (1.2.2) | |||
| letter_avatar (0.3.9) | |||
| kaminari-core (= 1.2.0) | |||
| kaminari-core (1.2.0) | |||
| letter_avatar (0.3.8) | |||
| listen (3.1.5) | |||
| rb-fsevent (~> 0.9, >= 0.9.4) | |||
| rb-inotify (~> 0.9, >= 0.9.7) | |||
| ruby_dep (~> 1.2) | |||
| loofah (2.20.0) | |||
| loofah (2.4.0) | |||
| crass (~> 1.0.2) | |||
| nokogiri (>= 1.5.9) | |||
| mail (2.7.1) | |||
| mini_mime (>= 0.1.1) | |||
| marcel (1.0.2) | |||
| marcel (0.3.3) | |||
| mimemagic (~> 0.3.2) | |||
| maruku (0.7.3) | |||
| method_source (1.0.0) | |||
| method_source (0.9.2) | |||
| mime-types (3.4.1) | |||
| mime-types-data (~> 3.2015) | |||
| mime-types-data (3.2023.0218.1) | |||
| mimemagic (0.4.3) | |||
| mimemagic (0.3.10) | |||
| nokogiri (~> 1) | |||
| rake | |||
| mini_mime (1.1.2) | |||
| mini_mime (1.0.2) | |||
| mini_portile2 (2.4.0) | |||
| minitest (5.15.0) | |||
| msgpack (1.6.1) | |||
| multi_json (1.15.0) | |||
| minitest (5.14.0) | |||
| msgpack (1.3.3) | |||
| multi_json (1.14.1) | |||
| multi_xml (0.6.0) | |||
| multipart-post (2.3.0) | |||
| mustermann (1.1.2) | |||
| multipart-post (2.1.1) | |||
| mustermann (1.1.1) | |||
| ruby2_keywords (~> 0.0.1) | |||
| mysql2 (0.5.5) | |||
| mysql2 (0.5.3) | |||
| netrc (0.11.0) | |||
| nio4r (2.5.9) | |||
| nokogiri (1.10.10) | |||
| nio4r (2.5.2) | |||
| nokogiri (1.10.8) | |||
| mini_portile2 (~> 2.4.0) | |||
| oauth2 (1.4.8) | |||
| faraday (>= 0.8, < 3.0) | |||
| oauth2 (1.4.4) | |||
| faraday (>= 0.8, < 2.0) | |||
| jwt (>= 1.0, < 3.0) | |||
| multi_json (~> 1.3) | |||
| multi_xml (~> 0.5) | |||
| rack (>= 1.2, < 3) | |||
| omniauth (1.9.2) | |||
| hashie (>= 3.4.6) | |||
| omniauth (1.9.0) | |||
| hashie (>= 3.4.6, < 3.7.0) | |||
| rack (>= 1.6.2, < 3) | |||
| omniauth-cas (2.0.0) | |||
| omniauth-cas (1.1.1) | |||
| addressable (~> 2.3) | |||
| nokogiri (~> 1.5) | |||
| omniauth (~> 1.2) | |||
| @@ -235,81 +235,85 @@ GEM | |||
| omniauth-wechat-oauth2 (0.2.2) | |||
| omniauth (>= 1.3.2) | |||
| omniauth-oauth2 (>= 1.1.1) | |||
| parallel (1.20.1) | |||
| parser (2.7.2.0) | |||
| ast (~> 2.4.1) | |||
| pdfkit (0.8.4.3.2) | |||
| popper_js (1.16.1) | |||
| powerpack (0.1.3) | |||
| prettier (2.1.0) | |||
| public_suffix (4.0.7) | |||
| puma (5.6.5) | |||
| nio4r (~> 2.0) | |||
| parallel (1.19.1) | |||
| parser (2.7.1.1) | |||
| ast (~> 2.4.0) | |||
| pdfkit (0.8.4.1) | |||
| polyamorous (2.3.2) | |||
| activerecord (>= 5.2.1) | |||
| popper_js (1.16.0) | |||
| powerpack (0.1.2) | |||
| prettier (0.18.2) | |||
| public_suffix (4.0.3) | |||
| puma (3.12.2) | |||
| raabro (1.4.0) | |||
| rack (2.0.9.3) | |||
| rack-cors (2.0.1) | |||
| rack (2.0.9) | |||
| rack-cors (1.1.1) | |||
| rack (>= 2.0.0) | |||
| rack-mini-profiler (2.0.1) | |||
| rack (>= 1.2.0) | |||
| rack-protection (2.0.8.1) | |||
| rack | |||
| rack-test (2.1.0) | |||
| rack (>= 1.3) | |||
| rails (5.2.8.1) | |||
| actioncable (= 5.2.8.1) | |||
| actionmailer (= 5.2.8.1) | |||
| actionpack (= 5.2.8.1) | |||
| actionview (= 5.2.8.1) | |||
| activejob (= 5.2.8.1) | |||
| activemodel (= 5.2.8.1) | |||
| activerecord (= 5.2.8.1) | |||
| activestorage (= 5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| rack-test (1.1.0) | |||
| rack (>= 1.0, < 3) | |||
| rails (5.2.4.1) | |||
| actioncable (= 5.2.4.1) | |||
| actionmailer (= 5.2.4.1) | |||
| actionpack (= 5.2.4.1) | |||
| actionview (= 5.2.4.1) | |||
| activejob (= 5.2.4.1) | |||
| activemodel (= 5.2.4.1) | |||
| activerecord (= 5.2.4.1) | |||
| activestorage (= 5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| bundler (>= 1.3.0) | |||
| railties (= 5.2.8.1) | |||
| railties (= 5.2.4.1) | |||
| sprockets-rails (>= 2.0.0) | |||
| rails-dom-testing (2.0.3) | |||
| activesupport (>= 4.2.0) | |||
| nokogiri (>= 1.6) | |||
| rails-html-sanitizer (1.5.0) | |||
| loofah (~> 2.19, >= 2.19.1) | |||
| rails-html-sanitizer (1.3.0) | |||
| loofah (~> 2.3) | |||
| rails-i18n (5.1.3) | |||
| i18n (>= 0.7, < 2) | |||
| railties (>= 5.0, < 6) | |||
| railties (5.2.8.1) | |||
| actionpack (= 5.2.8.1) | |||
| activesupport (= 5.2.8.1) | |||
| railties (5.2.4.1) | |||
| actionpack (= 5.2.4.1) | |||
| activesupport (= 5.2.4.1) | |||
| method_source | |||
| rake (>= 0.8.7) | |||
| thor (>= 0.19.0, < 2.0) | |||
| rainbow (3.1.1) | |||
| rake (10.4.2) | |||
| ransack (2.4.1) | |||
| activerecord (>= 5.2.4) | |||
| activesupport (>= 5.2.4) | |||
| rainbow (3.0.0) | |||
| rake (13.0.1) | |||
| ransack (2.3.2) | |||
| activerecord (>= 5.2.1) | |||
| activesupport (>= 5.2.1) | |||
| i18n | |||
| rb-fsevent (0.11.2) | |||
| polyamorous (= 2.3.2) | |||
| rb-fsevent (0.10.3) | |||
| rb-inotify (0.10.1) | |||
| ffi (~> 1.0) | |||
| rchardet (1.8.0) | |||
| redcarpet (3.6.0) | |||
| redis (4.8.1) | |||
| redis-actionpack (5.3.0) | |||
| actionpack (>= 5, < 8) | |||
| redcarpet (3.5.0) | |||
| redis (4.1.3) | |||
| redis-actionpack (5.2.0) | |||
| actionpack (>= 5, < 7) | |||
| redis-rack (>= 2.1.0, < 3) | |||
| redis-store (>= 1.1.0, < 2) | |||
| redis-activesupport (5.3.0) | |||
| activesupport (>= 3, < 8) | |||
| redis-activesupport (5.2.0) | |||
| activesupport (>= 3, < 7) | |||
| redis-store (>= 1.3, < 2) | |||
| redis-rack (2.1.4) | |||
| redis-rack (2.1.2) | |||
| rack (>= 2.0.8, < 3) | |||
| redis-store (>= 1.2, < 2) | |||
| redis-rails (5.0.2) | |||
| redis-actionpack (>= 5.0, < 6) | |||
| redis-activesupport (>= 5.0, < 6) | |||
| redis-store (>= 1.2, < 2) | |||
| redis-store (1.9.2) | |||
| redis (>= 4, < 6) | |||
| regexp_parser (1.8.2) | |||
| request_store (1.5.1) | |||
| redis-store (1.8.2) | |||
| redis (>= 4, < 5) | |||
| regexp_parser (1.7.0) | |||
| request_store (1.5.0) | |||
| rack (>= 1.4) | |||
| rest-client (2.1.0) | |||
| http-accept (>= 1.7.0, < 2.0) | |||
| @@ -330,15 +334,15 @@ GEM | |||
| rqrcode_png (0.1.5) | |||
| chunky_png | |||
| rqrcode | |||
| rspec-core (3.9.3) | |||
| rspec-support (~> 3.9.3) | |||
| rspec-expectations (3.9.4) | |||
| rspec-core (3.9.1) | |||
| rspec-support (~> 3.9.1) | |||
| rspec-expectations (3.9.0) | |||
| diff-lcs (>= 1.2.0, < 2.0) | |||
| rspec-support (~> 3.9.0) | |||
| rspec-mocks (3.9.1) | |||
| diff-lcs (>= 1.2.0, < 2.0) | |||
| rspec-support (~> 3.9.0) | |||
| rspec-rails (3.9.1) | |||
| rspec-rails (3.9.0) | |||
| actionpack (>= 3.0) | |||
| activesupport (>= 3.0) | |||
| railties (>= 3.0) | |||
| @@ -346,7 +350,7 @@ GEM | |||
| rspec-expectations (~> 3.9.0) | |||
| rspec-mocks (~> 3.9.0) | |||
| rspec-support (~> 3.9.0) | |||
| rspec-support (3.9.4) | |||
| rspec-support (3.9.2) | |||
| rubocop (0.52.1) | |||
| parallel (~> 1.10) | |||
| parser (>= 2.4.0.2, < 3.0) | |||
| @@ -355,8 +359,8 @@ GEM | |||
| ruby-progressbar (~> 1.7) | |||
| unicode-display_width (~> 1.0, >= 1.0.1) | |||
| ruby-ole (1.2.12.2) | |||
| ruby-progressbar (1.13.0) | |||
| ruby2_keywords (0.0.5) | |||
| ruby-progressbar (1.10.1) | |||
| ruby2_keywords (0.0.2) | |||
| ruby_dep (1.5.0) | |||
| rubyzip (1.3.0) | |||
| sass (3.7.4) | |||
| @@ -364,13 +368,13 @@ GEM | |||
| sass-listen (4.0.0) | |||
| rb-fsevent (~> 0.9, >= 0.9.4) | |||
| rb-inotify (~> 0.9, >= 0.9.7) | |||
| sass-rails (5.1.0) | |||
| railties (>= 5.2.0) | |||
| sass-rails (5.0.7) | |||
| railties (>= 4.0.0, < 6) | |||
| sass (~> 3.1) | |||
| sprockets (>= 2.8, < 4.0) | |||
| sprockets-rails (>= 2.0, < 4.0) | |||
| tilt (>= 1.1, < 3) | |||
| sassc (2.4.0) | |||
| sassc (2.2.1) | |||
| ffi (~> 1.9) | |||
| sassc-rails (2.1.2) | |||
| railties (>= 4.0.0) | |||
| @@ -378,9 +382,9 @@ GEM | |||
| sprockets (> 3.0) | |||
| sprockets-rails | |||
| tilt | |||
| searchkick (4.6.3) | |||
| activemodel (>= 5) | |||
| elasticsearch (>= 6, < 7.14) | |||
| searchkick (3.1.3) | |||
| activemodel (>= 4.2) | |||
| elasticsearch (>= 5) | |||
| hashie | |||
| selenium-webdriver (3.142.7) | |||
| childprocess (>= 0.5, < 4.0) | |||
| @@ -395,10 +399,10 @@ GEM | |||
| sidekiq (>= 4.2.1) | |||
| sidekiq-failures (1.0.4) | |||
| sidekiq (>= 4.0.0) | |||
| simple_form (5.0.3) | |||
| simple_form (5.0.2) | |||
| actionpack (>= 5.0) | |||
| activemodel (>= 5.0) | |||
| simple_xlsx_reader (1.0.5) | |||
| simple_xlsx_reader (1.0.4) | |||
| nokogiri | |||
| rubyzip | |||
| sinatra (2.0.8.1) | |||
| @@ -420,45 +424,46 @@ GEM | |||
| thor (~> 1.0) | |||
| tilt (~> 2.0) | |||
| yard (~> 0.9) | |||
| spreadsheet (1.3.0) | |||
| ruby-ole | |||
| spring (2.1.1) | |||
| spreadsheet (1.2.6) | |||
| ruby-ole (>= 1.0) | |||
| spring (2.0.2) | |||
| activesupport (>= 4.2) | |||
| spring-watcher-listen (2.0.1) | |||
| listen (>= 2.7, < 4.0) | |||
| spring (>= 1.2, < 3.0) | |||
| sprockets (3.7.2) | |||
| concurrent-ruby (~> 1.0) | |||
| rack (> 1, < 3) | |||
| sprockets-rails (3.2.2) | |||
| sprockets-rails (3.2.1) | |||
| actionpack (>= 4.0) | |||
| activesupport (>= 4.0) | |||
| sprockets (>= 3.0.0) | |||
| thor (1.2.2) | |||
| thor (1.0.1) | |||
| thread_safe (0.3.6) | |||
| tilt (2.1.0) | |||
| tilt (2.0.10) | |||
| turbolinks (5.2.1) | |||
| turbolinks-source (~> 5.2) | |||
| turbolinks-source (5.2.0) | |||
| tzinfo (1.2.11) | |||
| tzinfo (1.2.6) | |||
| thread_safe (~> 0.1) | |||
| uglifier (4.2.0) | |||
| execjs (>= 0.3.0, < 3) | |||
| unf (0.1.4) | |||
| unf_ext | |||
| unf_ext (0.0.8.2) | |||
| unicode-display_width (1.8.0) | |||
| unicode-display_width (1.6.1) | |||
| web-console (3.7.0) | |||
| actionview (>= 5.0) | |||
| activemodel (>= 5.0) | |||
| bindex (>= 0.4.0) | |||
| railties (>= 5.0) | |||
| websocket-driver (0.7.5) | |||
| websocket-driver (0.7.1) | |||
| websocket-extensions (>= 0.1.0) | |||
| websocket-extensions (0.1.5) | |||
| wkhtmltopdf-binary (0.12.6.6) | |||
| websocket-extensions (0.1.4) | |||
| wkhtmltopdf-binary (0.12.5.4) | |||
| xpath (3.2.0) | |||
| nokogiri (~> 1.8) | |||
| yard (0.9.34) | |||
| yard (0.9.24) | |||
| PLATFORMS | |||
| ruby | |||
| @@ -497,7 +502,6 @@ DEPENDENCIES | |||
| kaminari (~> 1.1, >= 1.1.1) | |||
| letter_avatar | |||
| listen (>= 3.0.5, < 3.2) | |||
| loofah (~> 2.20.0) | |||
| mysql2 (>= 0.4.4, < 0.6.0) | |||
| oauth2 | |||
| omniauth (~> 1.9.0) | |||
| @@ -510,8 +514,9 @@ DEPENDENCIES | |||
| parallel (~> 1.19, >= 1.19.1) | |||
| pdfkit | |||
| prettier | |||
| puma (~> 5.6.5) | |||
| puma (~> 3.11) | |||
| rack-cors | |||
| rack-mini-profiler | |||
| rails (~> 5.2.0) | |||
| rails-i18n (~> 5.1) | |||
| ransack | |||
| @@ -533,7 +538,7 @@ DEPENDENCIES | |||
| sidekiq-cron (= 1.2.0) | |||
| sidekiq-failures | |||
| simple_form | |||
| simple_xlsx_reader (~> 1.0.4) | |||
| simple_xlsx_reader | |||
| sinatra | |||
| solargraph (~> 0.38.0) | |||
| spreadsheet | |||
| @@ -546,4 +551,4 @@ DEPENDENCIES | |||
| wkhtmltopdf-binary | |||
| BUNDLED WITH | |||
| 1.17.3 | |||
| 2.1.4 | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -63,7 +63,7 @@ $(document).on('turbolinks:load', function() { | |||
| if(!valid) return; | |||
| $.ajax({ | |||
| method: 'PATCH', | |||
| method: 'PUT', | |||
| dataType: 'json', | |||
| url: $form.attr('action'), | |||
| data: new FormData($form[0]), | |||
| @@ -0,0 +1,65 @@ | |||
| $(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' }); | |||
| } | |||
| }); | |||
| } | |||
| }) | |||
| }); | |||
| } | |||
| }); | |||
| @@ -0,0 +1,3 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,2 @@ | |||
| // Place all the behaviors and hooks related to the matching controller here. | |||
| // All this logic will automatically be available in application.js. | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -0,0 +1,3 @@ | |||
| // 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/ | |||
| @@ -4,15 +4,16 @@ class AccountsController < ApplicationController | |||
| #skip_before_action :check_account, :only => [:logout] | |||
| def simple_update | |||
| def simple_update | |||
| simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, "")) | |||
| simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, "")) | |||
| simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, "")) | |||
| Register::RemoteForm.new(simple_update_params).validate! | |||
| Register::RemoteForm.new(simple_update_params.merge(user_id: current_user.id)).validate! | |||
| ActiveRecord::Base.transaction do | |||
| result = auto_update(current_user, simple_update_params) | |||
| 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" | |||
| render_ok | |||
| else | |||
| render_error(result[:message]) | |||
| @@ -160,8 +161,11 @@ class AccountsController < ApplicationController | |||
| successful_authentication(user) | |||
| render_ok | |||
| end | |||
| elsif interactor.result[:message].to_s.include?("user already exists") | |||
| 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};") | |||
| normal_status(-1, "用户已注册,请勿连续操作。") | |||
| else | |||
| tip_exception(-1, interactor.error) | |||
| tip_exception(-1, interactor.result[:message]) | |||
| end | |||
| rescue Register::BaseForm::EmailError => e | |||
| render_result(-2, e.message) | |||
| @@ -176,9 +180,14 @@ class AccountsController < ApplicationController | |||
| rescue Register::BaseForm::VerifiCodeError => e | |||
| render_result(-6, e.message) | |||
| rescue Exception => e | |||
| Gitea::User::DeleteService.call(user.login) unless user.nil? | |||
| uid_logger_error(e.message) | |||
| tip_exception(-1, e.message) | |||
| if user.present? && !e.message.to_s.include?("user already exists") | |||
| # Gitea::User::DeleteService.call(user.login) | |||
| # user.destroy | |||
| end | |||
| Rails.logger.error("##:register error--#{user.try(:id)},message:#{e.message}") | |||
| 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};") | |||
| logger_error(e) | |||
| tip_exception(-1, "注册失败") | |||
| end | |||
| end | |||
| @@ -350,6 +359,17 @@ class AccountsController < ApplicationController | |||
| Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate! | |||
| render_ok | |||
| end | |||
| def check_keywords | |||
| text = params[:text].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') | |||
| data = ! ReversedKeyword.check_exists?(text) | |||
| result = { | |||
| status: 0, | |||
| data: data, | |||
| message: data ? "" : "无法使用以下关键词:#{text},请重新命名" | |||
| } | |||
| render_ok(result) | |||
| end | |||
| private | |||
| @@ -0,0 +1,32 @@ | |||
| class Admins::GlccPrCheckController < Admins::BaseController | |||
| 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 | |||
| @@ -0,0 +1,35 @@ | |||
| class Admins::IdentityVerificationsController < Admins::BaseController | |||
| 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 @identity_verification.update(update_params) | |||
| redirect_to admins_identity_verifications_path | |||
| flash[:success] = "更新成功" | |||
| else | |||
| redirect_to admins_identity_verifications_path | |||
| flash[:danger] = "更新失败" | |||
| 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 | |||
| @@ -25,6 +25,6 @@ class Admins::LaboratorySettingsController < Admins::BaseController | |||
| params.permit(:identifier, :name, | |||
| :nav_logo, :login_logo, :tab_logo, :oj_banner, | |||
| :subject_banner, :course_banner, :competition_banner, :moop_cases_banner, | |||
| :footer, navbar: %i[name link hidden]) | |||
| :footer, navbar: %i[name link hidden index]) | |||
| end | |||
| end | |||
| @@ -49,7 +49,7 @@ class Admins::MessageTemplatesController < Admins::BaseController | |||
| def message_template_params | |||
| # type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip" | |||
| # params.require(type.split("::").join("_").underscore.to_sym).permit! | |||
| params.require(:message_template).permit! | |||
| params.require(:message_template_custom_tip).permit! | |||
| end | |||
| def get_template | |||
| @@ -9,12 +9,29 @@ class Admins::OrganizationsController < Admins::BaseController | |||
| @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 | |||
| @@ -0,0 +1,79 @@ | |||
| class Admins::PageThemesController < Admins::BaseController | |||
| 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 | |||
| @@ -35,6 +35,7 @@ class Admins::ProjectsController < Admins::BaseController | |||
| Gitea::Repository::DeleteService.new(project.owner, project.identifier).call | |||
| project.destroy! | |||
| # 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 | |||
| flash[:success] = "删除成功" | |||
| end | |||
| @@ -0,0 +1,46 @@ | |||
| class Admins::SitePagesController < Admins::BaseController | |||
| 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 | |||
| @site_page.update(update_params) | |||
| flash[:success] = '保存成功' | |||
| 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 | |||
| @@ -1,5 +1,5 @@ | |||
| class Admins::UsersController < Admins::BaseController | |||
| before_action :finder_user, except: [:index] | |||
| before_action :finder_user, except: [:index] | |||
| def index | |||
| params[:sort_by] = params[:sort_by].presence || 'created_on' | |||
| @@ -25,15 +25,16 @@ class Admins::UsersController < Admins::BaseController | |||
| end | |||
| 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.destroy! | |||
| Gitea::User::DeleteService.call(@user.login) | |||
| render_delete_success | |||
| end | |||
| def lock | |||
| @user.lock! | |||
| UserAction.create(action_id: @user.id, action_type: "LockUser", user_id: current_user.id, :ip => request.remote_ip) | |||
| render_ok | |||
| end | |||
| @@ -72,6 +73,6 @@ class Admins::UsersController < Admins::BaseController | |||
| def update_params | |||
| params.require(:user).permit(%i[lastname nickname gender technical_title is_shixun_marker | |||
| mail phone location location_city school_id department_id admin | |||
| password login]) | |||
| password login website_permission]) | |||
| end | |||
| end | |||
| @@ -17,7 +17,16 @@ class Api::V1::Projects::BranchesController < Api::V1::BaseController | |||
| def destroy | |||
| @result_object = Api::V1::Projects::Branches::DeleteService.call(@project, params[:name], current_user&.gitea_token) | |||
| if @result_object | |||
| if @result_object | |||
| # 有开启的pr需要一同关闭 | |||
| # 1、删除本仓库中存在未关闭的pr,即本仓库分支1->分支2 | |||
| # 2、如果是fork仓库,考虑删除主仓库中存在未关闭的pr,即本仓库:分支1->主:分支2,同时分两种删除:1删除本仓库分支1,2删除主仓库分支2 | |||
| close_pull_requests_by(@project, params[:name]) | |||
| if @project.forked_from_project_id.present? | |||
| # fork项目中删除分支 | |||
| close_pull_requests_by(@project.fork_project, params[:name]) | |||
| end | |||
| return render_ok | |||
| else | |||
| return render_error('删除分支失败!') | |||
| @@ -39,4 +48,19 @@ class Api::V1::Projects::BranchesController < Api::V1::BaseController | |||
| def branch_params | |||
| params.require(:branch).permit(:new_branch_name, :old_branch_name) | |||
| end | |||
| def close_pull_requests_by(project, branch_name) | |||
| open_pull_requests = project.pull_requests.opening.where(head: branch_name).or(project.pull_requests.opening.where(base: branch_name)) | |||
| if open_pull_requests.present? | |||
| open_pull_requests.each do |pull_request| | |||
| closed = PullRequests::CloseService.call(project.owner, project.repository, pull_request, current_user) | |||
| if closed === true | |||
| pull_request.project_trends.create!(user: current_user, project: 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 | |||
| @@ -81,7 +81,7 @@ class ApplicationController < ActionController::Base | |||
| # 判断用户的邮箱或者手机是否可用 | |||
| # params[:type] 1: 注册;2:忘记密码;3:绑定 | |||
| def check_mail_and_phone_valid login, type | |||
| unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ | |||
| unless login =~ /\A[a-zA-Z0-9]+([._\-\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ || login =~ /^1\d{10}$/ | |||
| tip_exception(-2, "请输入正确的手机号或邮箱") | |||
| end | |||
| @@ -1103,7 +1103,7 @@ class ApplicationController < ActionController::Base | |||
| "author_time": commit['commit']['author']['date'], | |||
| "committer_time": commit['commit']['committer']['date'], | |||
| "content": commit['commit']['message'], | |||
| "commit_diff": commit_diff['Files'].to_s | |||
| "commit_diff": commit_diff.present? ? commit_diff['Files'].to_s : "" | |||
| }.to_json | |||
| resp_body = Blockchain::InvokeBlockchainApi.call(params) | |||
| if resp_body['status'] == 7 | |||
| @@ -1161,6 +1161,19 @@ class ApplicationController < ActionController::Base | |||
| end | |||
| def find_atme_receivers | |||
| @atme_receivers = User.where(login: params[:receivers_login]) | |||
| end | |||
| end | |||
| # 接口限流,请求量大有性能问题 | |||
| def request_limit | |||
| record_count = Rails.cache.read("request/#{controller_name}/#{Time.now.strftime('%Y%m%d%H%M')}/#{request.remote_ip}") | |||
| if record_count.present? | |||
| record_count = record_count + 1 | |||
| else | |||
| record_count = 1 | |||
| end | |||
| tip_exception("请求太快,请稍后再试。") if record_count > 100 | |||
| Rails.cache.write("request/#{controller_name}/#{Time.now.strftime('%Y%m%d%H%M')}/#{request.remote_ip}", record_count, expires_in: 1.minute) | |||
| end | |||
| end | |||
| @@ -38,12 +38,13 @@ class AttachmentsController < ApplicationController | |||
| url = ("/repos"+url.split(base_url + "/api")[1]) | |||
| filepath, ref = url.split("/")[-1].split("?") | |||
| url.gsub!(url.split("/")[-1], '') | |||
| puts filepath | |||
| request_url = [domain, api_url, url, CGI.escape(filepath), "?ref=#{CGI.escape(ref.split('ref=')[1])}&access_token=#{User.where(admin: true).take&.gitea_token}"].join | |||
| Rails.logger.info("url===#{url}") | |||
| request_url = [domain, api_url, URI.encode(url), CGI.escape(filepath), "?ref=#{CGI.escape(ref.split('ref=')[1])}&access_token=#{User.where(admin: true).take&.gitea_token}"].join | |||
| Rails.logger.info("request_url===#{request_url}") | |||
| response = Faraday.get(request_url) | |||
| filename = filepath | |||
| else | |||
| response = Faraday.get(url) | |||
| response = Faraday.get(URI.encode(url)) | |||
| filename = params[:download_url].to_s.split("/").pop() | |||
| end | |||
| send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment') | |||
| @@ -5,13 +5,17 @@ class ForksController < ApplicationController | |||
| before_action :authenticate_project!, :authenticate_user! | |||
| def create | |||
| @new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call | |||
| @new_project = Projects::ForkService.new(current_user, @project, params[:organization], params[:new_name], params[:new_identifier]).call | |||
| end | |||
| private | |||
| def authenticate_project! | |||
| if current_user&.id == @project.user_id | |||
| render_result(-1, "自己不能fork自己的项目") | |||
| elsif @project.fork_users.where(user_id: current_user.id).present? | |||
| fork = @project.fork_users.find_by(user_id: current_user.id) | |||
| render json: { status: 0, id: fork.fork_project_id, identifier: fork.fork_project&.identifier, message: "fork失败,你已拥有了这个项目 #{fork.fork_project&.identifier}" } | |||
| return | |||
| elsif Project.exists?(user_id: current_user.id, identifier: @project.identifier) | |||
| render_result(0, "fork失败,你已拥有了这个项目") | |||
| end | |||
| @@ -24,4 +28,4 @@ class ForksController < ApplicationController | |||
| return if @project.member?(current_user) || current_user.admin? | |||
| render_forbidden('你没有权限操作') | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,29 @@ | |||
| class IdentityVerificationsController < ApplicationController | |||
| before_action :require_login | |||
| before_action :require_profile_completed, only: [:create] | |||
| def index | |||
| @id_verify = current_user.identity_verification | |||
| return render_ok({data:nil}) unless @id_verify | |||
| end | |||
| def create | |||
| return tip_exception(-1, "您已提交过身份审核,请勿重复提交") if IdentityVerification.exists?(user:current_user) | |||
| return tip_exception(-1, "身份证输入有误")unless create_params[:number] =~ User::VALID_NUMBER_REGEX | |||
| @id_verify = IdentityVerification.new(create_params) | |||
| @id_verify.user = current_user | |||
| @id_verify.save | |||
| end | |||
| def update | |||
| return tip_exception(-1, "身份证输入有误")unless create_params[:number] =~ User::VALID_NUMBER_REGEX | |||
| current_user.identity_verification.update(create_params.merge({ state: 0 })) | |||
| current_user.update(id_card_verify: false) | |||
| @id_verify = current_user.identity_verification | |||
| end | |||
| private | |||
| def create_params | |||
| params.permit(:number, :name, :card_front, :card_back, :hold_card_front, :hold_card_back) | |||
| end | |||
| end | |||
| @@ -1,12 +1,12 @@ | |||
| class IssuesController < ApplicationController | |||
| before_action :require_login, except: [:index, :show, :index_chosen] | |||
| before_action :require_login, except: [:index, :show, :index_chosen, :index_to_name] | |||
| before_action :require_profile_completed, only: [:create] | |||
| before_action :load_project | |||
| before_action :set_user | |||
| before_action :check_menu_authorize, except: [:index_chosen] | |||
| before_action :check_issue_permission | |||
| before_action :operate_issue_permission, only:[:create, :update, :destroy, :clean, :series_update, :copy] | |||
| before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue] | |||
| before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue, :index_to_name] | |||
| before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue] | |||
| before_action :check_token_enough, :find_atme_receivers, only: [:create, :update] | |||
| @@ -49,6 +49,27 @@ class IssuesController < ApplicationController | |||
| @issue_chosen = issue_left_chosen(@project, nil) | |||
| end | |||
| def index_to_name | |||
| issues_index = params[:index].map(&:to_i) | |||
| exit_index = [] | |||
| issues_result = @project.issues.where(project_issues_index:issues_index).map{ |e| | |||
| exit_index << e.project_issues_index | |||
| { | |||
| id:e.id, | |||
| project_issues_index:e.project_issues_index, | |||
| subject:e.subject | |||
| } | |||
| } | |||
| not_exit = issues_index - exit_index | |||
| not_exit.map{|e| | |||
| issues_result << {id: nil, | |||
| project_issues_index:e, | |||
| subject: nil} | |||
| } | |||
| render json: issues_result | |||
| end | |||
| def commit_issues | |||
| issues = @project.issues.issue_issue.includes(:user,:tracker) | |||
| issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user)) | |||
| @@ -8,6 +8,18 @@ class MainController < ApplicationController | |||
| render :json => { status: 0, message: Time.now.to_i } | |||
| end | |||
| def test_404 | |||
| status_code = 404 | |||
| status = status_code.to_s | |||
| fname = %w[404 403 422 500].include?(status) ? status : "unknown" | |||
| respond_to do |format| | |||
| format.html { render template: "/shared/#{fname}", handler: [:erb], status: status } | |||
| format.xml { render :xml => Laboratory.limit(1).to_xml, status: status } | |||
| format.all { render body: nil, status: status } | |||
| end | |||
| end | |||
| def index | |||
| domain_session = params[:_educoder_session] | |||
| if domain_session | |||
| @@ -24,6 +36,8 @@ class MainController < ApplicationController | |||
| # TODO: 这块之后需要整合,者架构重新变化,统一跳转到index后再路由分发 | |||
| if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild" | |||
| render file: 'public/h5educoderbuild/index.html', :layout => false, :content_type=> 'text/html' | |||
| elsif params[:path].to_s.include?("test_404") | |||
| test_404 | |||
| else | |||
| render file: 'public/react/build/index.html', :layout => false, :content_type=> 'text/html' | |||
| end | |||
| @@ -0,0 +1,70 @@ | |||
| class Organizations::ClasController < Organizations::BaseController | |||
| before_action :load_organization | |||
| before_action :load_cla, only: [:show, :update, :destroy] | |||
| before_action :check_user_can_edit_org, only: [:create, :update, :destroy] | |||
| def index | |||
| @cla = @organization.cla | |||
| end | |||
| def show | |||
| @is_admin = can_edit_org? | |||
| @is_member = @organization.is_member?(current_user.id) | |||
| @is_sign = @organization.is_sign?(current_user.id) | |||
| @cla_sign_email = if @is_sign | |||
| @organization.cla_sign_email(current_user.id) | |||
| end | |||
| end | |||
| def create | |||
| tip_exception("您的组织还未拥有创建CLA权限,请联系管理员") if @organization.enabling_cla == false | |||
| ActiveRecord::Base.transaction do | |||
| if @organization.cla.present? | |||
| return tip_exception("组织已存在CLA!") | |||
| else | |||
| Organizations::CreateClaForm.new(cla_params).validate! | |||
| @cla = Cla.build(cla_params,@organization.id) | |||
| end | |||
| end | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def update | |||
| ActiveRecord::Base.transaction do | |||
| Organizations::CreateClaForm.new(cla_params).validate! | |||
| @cla.update(cla_params) | |||
| end | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def destroy | |||
| tip_exception("组织CLA已被签署,无法删除") if @cla.user_clas.size > 0 | |||
| ActiveRecord::Base.transaction do | |||
| @cla.destroy! | |||
| end | |||
| render_ok | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| private | |||
| def cla_params | |||
| params.permit(:name, :key, :content, :pr_need) | |||
| end | |||
| def load_organization | |||
| @organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id]) | |||
| return render_not_found("组织不存在") if @organization.nil? | |||
| end | |||
| def load_cla | |||
| @cla = Cla.find_by!(organization:@organization, key: params[:id]) | |||
| end | |||
| end | |||
| @@ -4,11 +4,12 @@ class ProjectsController < ApplicationController | |||
| include ProjectsHelper | |||
| include Acceleratorable | |||
| before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list] | |||
| before_action :require_profile_completed, only: [:create, :migrate] | |||
| before_action :load_repository, except: %i[index group_type_list migrate create recommend banner_recommend] | |||
| before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list verify_auth_token] | |||
| before_action :require_profile_completed, only: [:create, :migrate,:page_migrate,:verify_auth_token] | |||
| before_action :load_repository, except: %i[index group_type_list migrate page_migrate create recommend banner_recommend verify_auth_token] | |||
| before_action :authorizate_user_can_edit_project!, only: %i[update] | |||
| before_action :project_public?, only: %i[fork_users praise_users watch_users] | |||
| before_action :request_limit, only: %i[index] | |||
| def menu_list | |||
| menu = [] | |||
| @@ -42,11 +43,11 @@ class ProjectsController < ApplicationController | |||
| if category_id.blank? && params[:search].blank? && params[:topic_id].blank? | |||
| # 默认查询时count性能问题处理 | |||
| ProjectCategory.sum("projects_count") - Project.visible.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id").where("organization_extensions.visibility =2").count | |||
| elsif params[:search].present? || params[:topic_id].present? | |||
| elsif params[:search].present? || params[:topic_id].present? | |||
| @projects.total_count | |||
| else | |||
| cate = ProjectCategory.find_by(id: category_id) | |||
| cate&.projects_count || 0 | |||
| cate = ProjectCategory.find_by(id: category_id) | |||
| cate&.projects_count || 0 | |||
| end | |||
| end | |||
| @@ -54,26 +55,32 @@ class ProjectsController < ApplicationController | |||
| ActiveRecord::Base.transaction do | |||
| Projects::CreateForm.new(project_params).validate! | |||
| @project = Projects::CreateService.new(current_user, project_params).call | |||
| # OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(@project&.id, current_user.id) | |||
| #OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(@project&.id, current_user.id) | |||
| UpdateProjectTopicJob.perform_later(@project.id) if @project.id.present? | |||
| end | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def verify_auth_token | |||
| data = Projects::VerifyAuthTokenService.call(params[:clone_addr], params[:auth_token]) | |||
| render_ok({data: data}) | |||
| end | |||
| def migrate | |||
| Projects::MigrateForm.new(mirror_params).validate! | |||
| @project = | |||
| @project = | |||
| if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr]) | |||
| source_clone_url = mirror_params[:clone_addr] | |||
| uid_logger("########## 已动加速器 ##########") | |||
| result = Gitea::Accelerator::MigrateService.call(mirror_params) | |||
| if result[:status] == :success | |||
| Rails.logger.info "########## 加速镜像成功 ########## " | |||
| Projects::MigrateService.call(current_user, | |||
| mirror_params.merge(source_clone_url: source_clone_url, | |||
| clone_addr: accelerator_url(mirror_params[:repository_name]))) | |||
| Projects::MigrateService.call(current_user, | |||
| mirror_params.merge(source_clone_url: source_clone_url, | |||
| clone_addr: accelerator_url(mirror_params[:repository_name]))) | |||
| else | |||
| Projects::MigrateService.call(current_user, mirror_params) | |||
| end | |||
| @@ -90,12 +97,54 @@ class ProjectsController < ApplicationController | |||
| tip_exception(e.message) | |||
| end | |||
| def page_migrate | |||
| return normal_status(-1, "您还未开通Page服务,无法进行新建站点") unless current_user.id_card_verify | |||
| return normal_status(-1, "你已使用了 #{page_site_params[:identifier]} 作为page标识") if Page.exists?(identifier: page_site_params[:identifier], user: current_user) | |||
| Projects::MigrateForm.new(mirror_params).validate! | |||
| @project = | |||
| if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr]) | |||
| source_clone_url = mirror_params[:clone_addr] | |||
| uid_logger("########## 已动加速器 ##########") | |||
| result = Gitea::Accelerator::MigrateService.call(mirror_params) | |||
| if result[:status] == :success | |||
| Rails.logger.info "########## 加速镜像成功 ########## " | |||
| Projects::MigrateService.call(current_user, | |||
| mirror_params.merge(source_clone_url: source_clone_url, | |||
| clone_addr: accelerator_url(mirror_params[:repository_name]))) | |||
| else | |||
| Projects::MigrateService.call(current_user, mirror_params) | |||
| end | |||
| elsif EduSetting.get("mirror_address").to_s.include?("cnpmjs") && mirror_params[:clone_addr].include?("github.com") | |||
| source_clone_url = mirror_params[:clone_addr] | |||
| clone_url = source_clone_url.gsub('github.com', 'github.com.cnpmjs.org') | |||
| uid_logger("########## 更改clone_addr ##########") | |||
| Projects::MigrateService.call(current_user, mirror_params.merge(source_clone_url: source_clone_url, clone_addr: clone_url)) | |||
| else | |||
| Projects::MigrateService.call(current_user, mirror_params) | |||
| end | |||
| if @project.present? | |||
| page = Page.new page_site_params | |||
| page.user = current_user | |||
| page.project = @project | |||
| end | |||
| if page.save | |||
| render json: page | |||
| end | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def branches | |||
| return @branches = [] unless @project.forge? | |||
| # result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier) | |||
| result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name]) | |||
| @branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result) : result | |||
| @branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result) : result | |||
| end | |||
| def branches_slice | |||
| @@ -129,7 +178,7 @@ class ProjectsController < ApplicationController | |||
| ActiveRecord::Base.transaction do | |||
| # TODO: | |||
| # 临时特殊处理修改website、lesson_url操作方法 | |||
| if project_params.has_key?("website") | |||
| if project_params.has_key?("website") | |||
| if params[:project_topic_names].is_a?(Array) | |||
| ProjectTopicRalate.where(project: @project).destroy_all | |||
| params[:project_topic_names].each do |name| | |||
| @@ -145,11 +194,11 @@ class ProjectsController < ApplicationController | |||
| } | |||
| Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params) | |||
| else | |||
| validate_params = project_params.slice(:name, :description, | |||
| :project_category_id, :project_language_id, :private, :identifier) | |||
| validate_params = project_params.slice(:name, :description, | |||
| :project_category_id, :project_language_id, :private, :identifier) | |||
| Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier, project_name: @project.name)).validate! | |||
| private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false | |||
| new_project_params = project_params.except(:private).merge(is_public: !private) | |||
| @@ -162,7 +211,7 @@ class ProjectsController < ApplicationController | |||
| name: @project.identifier | |||
| } | |||
| gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params) | |||
| @project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]}) | |||
| @project.repository.update_attributes({ hidden: gitea_repo["private"], identifier: gitea_repo["name"] }) | |||
| # 更新对应所属分类下的项目数量(私有) | |||
| before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public | |||
| after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public | |||
| @@ -203,13 +252,13 @@ class ProjectsController < ApplicationController | |||
| def quit | |||
| user_is_admin = current_user.admin? || @project.manager?(current_user) | |||
| if !user_is_admin && @project.member(current_user.id) && @project.forge? | |||
| if !user_is_admin && @project.member(current_user.id) && @project.forge? | |||
| ActiveRecord::Base.transaction do | |||
| Projects::DeleteMemberInteractor.call(@project.owner, @project, current_user) | |||
| SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, current_user.id, @project.id) if Site.has_notice_menu? | |||
| render_ok | |||
| end | |||
| else | |||
| else | |||
| render_forbidden('你不能退出该仓库') | |||
| end | |||
| rescue Exception => e | |||
| @@ -238,6 +287,13 @@ class ProjectsController < ApplicationController | |||
| def simple | |||
| # 为了缓存活跃项目的基本信息,后续删除 | |||
| Cache::V2::ProjectCommonService.new(@project.id).read | |||
| # 项目名称,标识,所有者变化时重置缓存 | |||
| project_common = $redis_cache.hgetall("v2-project-common:#{@project.id}") | |||
| if project_common.present? | |||
| if project_common["name"] != @project.name || project_common["identifier"] != @project.identifier || project_common["owner_id"] != @project.user_id | |||
| Cache::V2::ProjectCommonService.new(@project.id).reset | |||
| end | |||
| end | |||
| json_response(@project, current_user) | |||
| end | |||
| @@ -266,7 +322,7 @@ class ProjectsController < ApplicationController | |||
| if @project_detail.save! | |||
| attachment_ids = Array(params[:attachment_ids]) | |||
| logger.info "=============> #{Array(params[:attachment_ids])}" | |||
| @attachments = Attachment.where(id: attachment_ids) | |||
| @attachments = Attachment.where(id: attachment_ids) | |||
| @attachments.update_all( | |||
| container_id: @project_detail.id, | |||
| container_type: @project_detail.model_name.name, | |||
| @@ -279,17 +335,22 @@ class ProjectsController < ApplicationController | |||
| private | |||
| def project_params | |||
| params.permit(:user_id, :name, :description, :repository_name, :website, :lesson_url, :default_branch, :identifier, | |||
| :project_category_id, :project_language_id, :license_id, :ignore_id, :private, | |||
| :blockchain, :blockchain_token_all, :blockchain_init_token) | |||
| :blockchain, :blockchain_token_all, :blockchain_init_token, :pr_view_admin) | |||
| end | |||
| def mirror_params | |||
| params.permit(:user_id, :name, :description, :repository_name, :is_mirror, :auth_username, | |||
| params.permit(:user_id, :name, :description, :repository_name, :is_mirror, :auth_username, :auth_token, | |||
| :auth_password, :project_category_id, :project_language_id, :clone_addr, :private) | |||
| end | |||
| def page_site_params | |||
| params.permit(:site_name, :identifier,:language_frame,:theme) | |||
| end | |||
| def project_public? | |||
| return if @project.is_public? | |||
| @@ -67,6 +67,7 @@ class PullRequestsController < ApplicationController | |||
| Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate! | |||
| @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) | |||
| if @gitea_pull_request[:status] == :success | |||
| PullRequests::SendJournalService.call(@project, @pull_request, current_user) | |||
| @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"]) | |||
| reviewers = User.where(id: params[:reviewer_ids]) | |||
| @pull_request.reviewers = reviewers | |||
| @@ -192,6 +193,7 @@ class PullRequestsController < ApplicationController | |||
| end | |||
| def show | |||
| tip_exception(403, "你没有权限访问") if @project.pr_view_admin? && !@project.manager?(current_user) | |||
| @issue_user = @issue.user | |||
| @issue_assign_to = @issue.get_assign_user | |||
| @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, | |||
| @@ -176,6 +176,9 @@ class RepositoriesController < ApplicationController | |||
| result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier, {page: params[:page], limit: params[:limit]}) | |||
| @total_count = result[:total_count] | |||
| @contributors = result.is_a?(Hash) ? result[:body] : [] | |||
| add_contributors_count = EduSetting.get("ProjectAddContributors-#{@project.id}") | |||
| @total_count = @total_count + add_contributors_count.to_i | |||
| end | |||
| rescue | |||
| @contributors = [] | |||
| @@ -263,8 +266,9 @@ class RepositoriesController < ApplicationController | |||
| end | |||
| @path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" | |||
| @readme = result[:status] === :success ? result[:body] : nil | |||
| @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) | |||
| # replace_content 前置,防止被content改写 | |||
| @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path) | |||
| @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) | |||
| render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content") | |||
| rescue | |||
| render json: nil | |||
| @@ -2,6 +2,7 @@ class SettingsController < ApplicationController | |||
| def show | |||
| @old_projects_url = nil | |||
| get_navbar | |||
| site_page_deploy_domain | |||
| get_add_menu | |||
| get_common_menu | |||
| get_sub_competitions | |||
| @@ -11,15 +12,33 @@ class SettingsController < ApplicationController | |||
| get_top_system_notification | |||
| end | |||
| def check_url | |||
| url = params[:url] | |||
| task_id = params[:task] | |||
| term = params[:term] | |||
| return normal_status(-1, "缺少url参数") unless url.present? | |||
| return normal_status(-1, "缺少term参数") unless term.present? | |||
| return normal_status(-1, "缺少task参数") unless task_id.present? | |||
| glcc_mate = GlccMediumTermExamineMaterial.new(code_or_pr_url: url, task_id: task_id, term: term, created_on:Time.now) | |||
| state = glcc_mate.check_pr_url | |||
| errors = glcc_mate.gennerate_content(state) | |||
| render_ok({ state:state, state_html: errors}) | |||
| end | |||
| private | |||
| def get_navbar | |||
| @navbar = default_laboratory.navbar | |||
| if User.current.logged? | |||
| pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false} | |||
| @navbar << pernal_index | |||
| end | |||
| @navbar = default_laboratory.navbar.sort_by{|e| e["index"].to_i } | |||
| # if User.current.logged? | |||
| # pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false} | |||
| # @navbar << pernal_index | |||
| # end | |||
| end | |||
| def site_page_deploy_domain | |||
| @deploy_domain = EduSetting.find_by_name("site_page_deploy_domain").try(:value) | |||
| end | |||
| def get_add_menu | |||
| @add = [] | |||
| Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site| | |||
| @@ -0,0 +1,94 @@ | |||
| class SitePagesController < ApplicationController | |||
| before_action :require_login, except: [:softbot_build, :themes] | |||
| before_action :require_profile_completed, only: [:create] | |||
| before_action :load_project, except: [:softbot_build, :index, :themes] | |||
| before_action :authenticate_user!, except: [:softbot_build, :index, :themes, :show] | |||
| before_action :authenticate_member!, only: [:show] | |||
| def index | |||
| pages = PageQuery.call(params,current_user) | |||
| @total_count = pages.size | |||
| @pages = paginate(pages) | |||
| end | |||
| def show | |||
| @page = Page.find_by(project_id: @project.id) | |||
| return render_ok({data:nil}) unless @page.present? | |||
| end | |||
| def create | |||
| return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission | |||
| return normal_status(-1, "你已使用了 #{params[:identifier]} 作为page标识") if Page.exists?(identifier: params[:identifier], user: current_user) | |||
| return normal_status(-1, "该仓库已开通Page服务") if Page.exists?(project: @project) | |||
| @page = Page.new(create_params) | |||
| @page.user = current_user | |||
| @page.project = @project | |||
| @page.save | |||
| end | |||
| def build | |||
| return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission | |||
| return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") unless Page.exists?(project: @project) | |||
| @page = Page.find params[:id] | |||
| return normal_status(-1, @page.state_description) unless @page.state | |||
| response_str = @page.deploy_page(params[:branch]) | |||
| data = JSON.parse(response_str)["result"] || data = JSON.parse(response_str)["error"] | |||
| if data.to_s.include?("部署成功") | |||
| @page.update(last_build_at: Time.now, build_state: true, last_build_info: data) | |||
| else | |||
| @page.update(build_state:false, last_build_info: data) | |||
| end | |||
| render_ok({data: data.nil? ? nil : data.split("\n") }) | |||
| end | |||
| def softbot_build | |||
| branch = params[:ref].split("/").last | |||
| user = User.find_by_login params[:repository][:owner][:login] | |||
| return normal_status(-1, "你还未开通Page服务,无法进行部署") unless user.website_permission | |||
| project = Project.where(identifier: params[:repository][:name],user_id: user.id) | |||
| return normal_status(-1, "你没有权限操作") if project.owner?(user) | |||
| return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") if Page.exists?(user: user, project: project) | |||
| @page = Page.find_by(user: user, project: project) | |||
| response_str = @page.deploy_page(branch) | |||
| data = JSON.parse(response_str)["result"] | |||
| if data.nil? | |||
| data = JSON.parse(response_str)["error"] | |||
| end | |||
| if data.include?("部署成功") | |||
| @page.update(last_build_at: Time.now, build_state: true, last_build_info: data) | |||
| else | |||
| @page.update(build_state:false, last_build_info: data) | |||
| end | |||
| render_ok | |||
| end | |||
| def themes | |||
| # data = YAML.load_file(Rails.root.join('config/admins', 'page_themes.yml')) | |||
| # render_ok({themes:data[theme_params.downcase]}) | |||
| @themes = PageTheme.where(language_frame:theme_params).order(order_index: :asc) | |||
| end | |||
| private | |||
| def authenticate_user! | |||
| unless @project.manager?(current_user) || current_user.admin? | |||
| return render_forbidden('你不是管理员,没有权限操作') | |||
| end | |||
| end | |||
| def authenticate_member! | |||
| unless @project.member?(current_user) || current_user.admin? | |||
| return render_forbidden('你不是成员,没有权限操作') | |||
| end | |||
| end | |||
| def theme_params | |||
| params[:language_frame] || "hugo" | |||
| end | |||
| def create_params | |||
| params.permit(:identifier, :language_frame, :theme, :site_name) | |||
| end | |||
| end | |||
| @@ -0,0 +1,43 @@ | |||
| class Users::ClasController < Users::BaseController | |||
| before_action :require_login | |||
| before_action :private_user_resources! | |||
| def index | |||
| @user_clas = UserCla.where(user: current_user) | |||
| end | |||
| def show | |||
| @user_cla = current_user.user_clas.find params[:id] | |||
| end | |||
| def create | |||
| @user_cla = current_user.user_clas.find_by(cla_id: params[:cla_id]) | |||
| if @user_cla.nil? | |||
| ActiveRecord::Base.transaction do | |||
| Users::UserClaForm.new(user_cla_params).validate! | |||
| @user_cla = UserCla.build(user_cla_params, current_user.id) | |||
| end | |||
| elsif @user_cla.state == "failed" | |||
| @user_cla.update_by_params(user_cla_params) | |||
| elsif @user_cla.state == "signed" | |||
| return render_error('协议生效中,请勿重复签署') | |||
| end | |||
| render_ok | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def destroy | |||
| @user_cla = current_user.user_clas.find params[:id] | |||
| @user_cla.update_attributes(state: 2) | |||
| render_ok | |||
| end | |||
| private | |||
| def user_cla_params | |||
| params.permit(:email, :real_name, :cla_id) | |||
| end | |||
| end | |||
| @@ -6,6 +6,7 @@ class Users::ProjectTrendsController < Users::BaseController | |||
| else | |||
| @project_trends = observed_user.project_trends | |||
| end | |||
| @project_trends = @project_trends.left_joins(:project).where("projects.is_public = TRUE") | |||
| @project_trends = kaminari_paginate(@project_trends.includes(:trend, :project).order(created_at: :desc)) | |||
| end | |||
| end | |||
| @@ -212,6 +212,10 @@ class UsersController < ApplicationController | |||
| def update | |||
| return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id]) | |||
| return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id) | |||
| if user_params[:nickname].present? | |||
| keywords = user_params[:nickname].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') | |||
| return normal_status(-1, "昵称中包含关键词:#{keywords},请重新命名") if ReversedKeyword.check_exists?(keywords) | |||
| end | |||
| Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? | |||
| @user.attributes = user_params.except(:image) | |||
| unless @user.save | |||
| @@ -759,10 +763,11 @@ class UsersController < ApplicationController | |||
| password = "12345678" | |||
| # 没有用户时,新建用户并登录 | |||
| user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first | |||
| user = phone.present? ? User.find_by(phone: phone) : nil | |||
| user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first if user.nil? | |||
| if user.present? | |||
| # 手机号先记录,后续用 | |||
| user.update_column(:phone, "#{phone}") if phone.present? | |||
| user.update_column(:phone, "#{phone}") if phone.present? && user.phone.blank? | |||
| else | |||
| ActiveRecord::Base.transaction do | |||
| email = "#{login}@gitlink.org.cn" if email.blank? | |||
| @@ -0,0 +1,6 @@ | |||
| class Organizations::CreateClaForm < BaseForm | |||
| KEY_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | |||
| attr_accessor :name, :key, :content, :pr_need | |||
| validates :name , :key, presence: true | |||
| validates :key, format: { with: KEY_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | |||
| end | |||
| @@ -1,5 +1,5 @@ | |||
| class Projects::MigrateForm < BaseForm | |||
| attr_accessor :user_id, :name, :repository_name, :project_category_id, :description, | |||
| attr_accessor :user_id, :name, :repository_name, :project_category_id, :description, :auth_token, | |||
| :project_language_id, :clone_addr, :private, :is_mirror, :auth_username, :auth_password, :owner | |||
| validates :user_id, :name, :repository_name, :clone_addr, presence: true | |||
| @@ -1,15 +1,16 @@ | |||
| module Register | |||
| class RemoteForm < Register::BaseForm | |||
| # login 登陆方式,支持邮箱、登陆、手机号等 | |||
| attr_accessor :username, :email, :password, :platform | |||
| attr_accessor :username, :email, :password, :platform, :user_id | |||
| validates :username, :email, :password, presence: true | |||
| validate :check! | |||
| def check! | |||
| Rails.logger.info "Register::RemoteForm params: username: #{username}; email: #{email}; password: #{password}; platform: #{platform}" | |||
| check_login(username) | |||
| check_mail(email) | |||
| user = User.find_by(id: user_id) | |||
| Rails.logger.info "Register::RemoteForm params: id: #{user&.id}; username: #{username}; email: #{email}; password: #{password}; platform: #{platform}" | |||
| check_login(username, user) | |||
| check_mail(email,user) | |||
| check_password(password) | |||
| end | |||
| end | |||
| @@ -0,0 +1,6 @@ | |||
| class Users::UserClaForm | |||
| include ActiveModel::Model | |||
| attr_accessor :email, :real_name, :cla_id | |||
| validates :email, presence: true, format: { with: CustomRegexp::EMAIL } | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module Admins::GlccPrCheckHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module Admins::IdentityVerificationsHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module Admins::PageThemesHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module Admins::SitePagesHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module IdentityVerificationsHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module Organizations::ClasHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module PagesHelper | |||
| end | |||
| @@ -16,7 +16,11 @@ module RepositoriesHelper | |||
| def image_type?(str) | |||
| default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd) | |||
| default_type.include?(str&.downcase) | |||
| default_type.include?(str.to_s.gsub("\r", "").downcase) | |||
| end | |||
| def is_text_file?(entry) | |||
| entry['is_text_file'] | |||
| end | |||
| def is_readme?(type, str) | |||
| @@ -36,18 +40,26 @@ module RepositoriesHelper | |||
| end | |||
| def render_cache_commit_author(author_json) | |||
| user = nil | |||
| if author_json["name"].present? && author_json["email"].present? | |||
| return find_user_in_redis_cache(author_json['name'], author_json['email']) | |||
| user = find_user_in_redis_cache(author_json['name'], author_json['email']) | |||
| end | |||
| if author_json["Name"].present? && author_json["Email"].present? | |||
| return find_user_in_redis_cache(author_json['Name'], author_json['Email']) | |||
| user = find_user_in_redis_cache(author_json['Name'], author_json['Email']) | |||
| end | |||
| if user.blank? && author_json["email"].present? | |||
| user = User.find_by(mail: author_json["email"]) | |||
| end | |||
| if user.blank? && author_json["Email"].present? | |||
| user = User.find_by(mail: author_json["Email"]) | |||
| end | |||
| user | |||
| end | |||
| def readme_render_decode64_content(str, owner, repo, ref, path) | |||
| return nil if str.blank? | |||
| begin | |||
| content = Base64.decode64(str).force_encoding('UTF-8') | |||
| content = Base64.decode64(content).force_encoding('UTF-8').valid_encoding? ? Base64.decode64(str).force_encoding('UTF-8') : Base64.decode64(str).force_encoding("GBK").encode("UTF-8") | |||
| c_regex = /\!\[.*?\]\((.*?)\)/ | |||
| src_regex = /src=\"(.*?)\"/ | |||
| @@ -107,19 +119,30 @@ module RepositoriesHelper | |||
| def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name) | |||
| file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '') | |||
| return nil if str.blank? | |||
| content = Base64.decode64(str).force_encoding('UTF-8') | |||
| content = Base64.decode64(str).force_encoding('UTF-8').valid_encoding? ? Base64.decode64(str).force_encoding('UTF-8') : Base64.decode64(str).force_encoding("GBK").encode("UTF-8") | |||
| # s_regex = /\s\!\[.*?\]\((.*?)\)\s/ | |||
| s_regex_c = /`{1,2}[^`](.*?)`{1,2}/ | |||
| s_regex = /```([\s\S]*?)```[\s]?/ | |||
| s_regex_1 = /\[.*?\]\((.*?)\)/ | |||
| # 变量图片相对路径 | |||
| s_regex_2 = /\[.*?\]:(.*?)\n/ | |||
| src_regex = /src=\"(.*?)\"/ | |||
| src_regex_1 = /src=\'(.*?)\'/ | |||
| src_regex_2 = /src = (.*?) / | |||
| src_regex_3 = /src= (.*?) / | |||
| src_regex_4 = /src =(.*?) / | |||
| src_regex_5 = /src =(.*?) / | |||
| ss_c = content.to_s.scan(s_regex_c) | |||
| ss = content.to_s.scan(s_regex) | |||
| ss_1 = content.to_s.scan(s_regex_1) | |||
| ss_2 = content.to_s.scan(s_regex_2) | |||
| ss_src = content.to_s.scan(src_regex) | |||
| ss_src_1 = content.to_s.scan(src_regex_1) | |||
| total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_src: ss_src, ss_src_1: ss_src_1} | |||
| ss_src_2 = content.to_s.scan(src_regex_2) | |||
| ss_src_3 = content.to_s.scan(src_regex_3) | |||
| ss_src_4 = content.to_s.scan(src_regex_4) | |||
| ss_src_5 = content.to_s.scan(src_regex_5) | |||
| total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_2: ss_2, ss_src: ss_src, ss_src_1: ss_src_1, ss_src_2: ss_src_2, ss_src_3: ss_src_3, ss_src_4: ss_src_4, ss_src_5: ss_src_5} | |||
| # total_sources.uniq! | |||
| total_sources.except(:ss, :ss_c).each do |k, sources| | |||
| sources.each do |s| | |||
| @@ -128,17 +151,29 @@ module RepositoriesHelper | |||
| # 链接直接跳过不做替换 | |||
| next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank? | |||
| ext = File.extname(s_content)[1..-1] | |||
| ext = ext.split("?")[0] if ext.include?("?") | |||
| if (image_type?(ext) || download_type(ext)) && !ext.blank? | |||
| s_content = File.expand_path(s_content, file_path) | |||
| s_content = s_content.split("#{Rails.root}/")[1] | |||
| # content = content.gsub(s[0], "/#{s_content}") | |||
| s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw/#{s_content}?ref=#{ref}"].join | |||
| case k.to_s | |||
| join_xxx = s_content.include?("?") ? "&" : "?" | |||
| s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw/#{s_content}#{join_xxx}ref=#{ref}"].join | |||
| case k.to_s | |||
| when 'ss_src' | |||
| content = content.gsub("src=\"#{s[0]}\"", "src=\"#{s_content}\"") | |||
| when 'ss_src_1' | |||
| content = content.gsub("src=\'#{s[0]}\'", "src=\'#{s_content}\'") | |||
| else | |||
| when 'ss_src_2' | |||
| content = content.gsub("src = #{s[0]}", "src=\'#{s_content}\'") | |||
| when 'ss_src_3' | |||
| content = content.gsub("src= #{s[0]}", "src=\'#{s_content}\'") | |||
| when 'ss_src_4' | |||
| content = content.gsub("src =#{s[0]}", "src=\'#{s_content}\'") | |||
| when 'ss_src_5' | |||
| content = content.gsub("src=#{s[0]}", "src=\'#{s_content}\'") | |||
| when 'ss_2' | |||
| content = content.gsub(/]:#{s[0]}/, "]: #{s_content.to_s.gsub(" ","").gsub("\r", "")}") | |||
| else | |||
| content = content.gsub("(#{s[0]})", "(#{s_content})") | |||
| end | |||
| else | |||
| @@ -150,7 +185,9 @@ module RepositoriesHelper | |||
| content = content.gsub("src=\"#{s[0]}\"", "src=\"/#{s_content}\"") | |||
| when 'ss_src_1' | |||
| content = content.gsub("src=\'#{s[0]}\'", "src=\'/#{s_content}\'") | |||
| else | |||
| when 'ss_2' | |||
| content = content.gsub(/]:#{s[0]}/, "]: /#{s_content.to_s.gsub(" ","").gsub("\r", "")}") | |||
| else | |||
| content = content.gsub("(#{s[0]})", "(/#{s_content})") | |||
| end | |||
| end | |||
| @@ -168,9 +205,10 @@ module RepositoriesHelper | |||
| after_ss_c_souces.each_with_index do |s, index| | |||
| content = content.gsub("#{s[0]}","#{total_sources[:ss_c][index][0]}") | |||
| end | |||
| return content | |||
| rescue | |||
| rescue Exception => e | |||
| Rails.logger.error("===================#{readme_path}:#{readme_name}:error:#{e}") | |||
| # e.backtrace.each { |msg| Rails.logger.error(msg) } | |||
| return str | |||
| end | |||
| @@ -186,8 +224,7 @@ module RepositoriesHelper | |||
| def readme_decode64_content(entry, owner, repo, ref, path=nil) | |||
| Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}") | |||
| content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] | |||
| # Rails.logger.info("content===#{content}") | |||
| content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] | |||
| # readme_render_decode64_content(content, owner, repo, ref) | |||
| new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name']) | |||
| end | |||
| @@ -195,10 +232,12 @@ module RepositoriesHelper | |||
| def decode64_content(entry, owner, repo, ref, path=nil) | |||
| if is_readme?(entry['type'], entry['name']) | |||
| Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}") | |||
| content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] | |||
| content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] | |||
| # Rails.logger.info("content===#{content}") | |||
| # readme_render_decode64_content(content, owner, repo, ref) | |||
| return Base64.decode64(content).force_encoding("GBK").encode("UTF-8") unless Base64.decode64(content).force_encoding('UTF-8').valid_encoding? | |||
| return Base64.decode64(content).force_encoding('UTF-8') | |||
| elsif entry['is_text_file'] == true | |||
| return render_decode64_content(entry['content']) | |||
| else | |||
| file_type = File.extname(entry['name'].to_s)[1..-1] | |||
| if image_type?(file_type) | |||
| @@ -0,0 +1,2 @@ | |||
| module Users::ClasHelper | |||
| end | |||
| @@ -42,6 +42,9 @@ module Gitea | |||
| def render_result(response) | |||
| if response.status == 200 | |||
| @result = JSON.parse(response.body) | |||
| else | |||
| Rails.logger.error("Gitea::Repository::Entries::DeleteService error[#{response.status}]======#{response.body}") | |||
| @error = "删除失败,请确认该分支是否是保护分支。" | |||
| end | |||
| end | |||
| @@ -42,6 +42,9 @@ module Gitea | |||
| def render_result(response) | |||
| if response.status == 200 | |||
| @result = JSON.parse(response.body) | |||
| else | |||
| Rails.logger.error("Gitea::Repository::Entries::UpdateService error[#{response.status}]======#{response.body}") | |||
| @error = "更新失败,请确认该分支是否是保护分支。" | |||
| end | |||
| end | |||
| @@ -15,11 +15,13 @@ class MigrateRemoteRepositoryJob < ApplicationJob | |||
| ## open jianmu devops | |||
| project_id = repo&.project&.id | |||
| puts "############ mirror project_id,user_id: #{project_id},#{user_id} ############" | |||
| # OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present? | |||
| OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present? | |||
| UpdateProjectTopicJob.set(wait: 1.seconds).perform_later(project_id) if project_id.present? | |||
| puts "############ mirror status: #{repo.mirror.status} ############" | |||
| else | |||
| repo&.mirror&.failed! | |||
| end | |||
| BroadcastMirrorRepoMsgJob.perform_later(repo.id) unless repo&.mirror.waiting? | |||
| # UpdateProjectTopicJob 中语言要延迟1S才能获取 | |||
| BroadcastMirrorRepoMsgJob.set(wait: 1.seconds).perform_later(repo.id) unless repo&.mirror.waiting? | |||
| end | |||
| end | |||
| @@ -8,7 +8,7 @@ class SendTemplateMessageJob < ApplicationJob | |||
| receivers_id, template_id, props = args[0], args[1], args[2] | |||
| template = MessageTemplate.find_by_id(template_id) | |||
| return unless template.present? | |||
| receivers = User.where(id: receivers_id).or(User.where(mail: receivers_id)) | |||
| receivers = User.where("id in(?)", receivers_id).or(User.where(mail: receivers_id)) | |||
| not_exists_receivers = receivers_id - receivers.pluck(:id) - receivers.pluck(:mail) | |||
| receivers_string, content, notification_url = MessageTemplate::CustomTip.get_message_content(receivers, template, props) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {receivers_id: receivers_id, template_id: template_id, props: props}) | |||
| @@ -3,9 +3,9 @@ class SyncRepoUpdateTimeJob < ApplicationJob | |||
| def perform(*args) | |||
| # Do something later | |||
| Project.forge.find_each do |project| | |||
| update_repo_time!(project) | |||
| end | |||
| # Project.forge.find_each do |project| | |||
| # update_repo_time!(project) | |||
| # end | |||
| end | |||
| private | |||
| @@ -49,9 +49,9 @@ class TouchWebhookJob < ApplicationJob | |||
| when 'IssueComment' | |||
| issue_id, sender_id, comment_id, action_type, comment_json = args[0], args[1], args[2], args[3], args[4] | |||
| issue = Issue.find_by_id issue_id | |||
| comment = issue.comment_journals.find_by_id comment_id | |||
| sender = User.find_by_id sender_id | |||
| return if issue.nil? || sender.nil? | |||
| return if issue.nil? || sender.nil? | |||
| comment = issue.comment_journals.find_by_id comment_id | |||
| return if action_type == 'edited' && comment_json.blank? | |||
| issue.project.webhooks.each do |webhook| | |||
| @@ -63,10 +63,10 @@ class TouchWebhookJob < ApplicationJob | |||
| when 'PullRequestComment' | |||
| issue_id, sender_id, comment_id, action_type, comment_json = args[0], args[1], args[2], args[3], args[4] | |||
| issue = Issue.find_by_id(issue_id) | |||
| comment = issue.comment_journals.find_by_id comment_id | |||
| sender = User.find_by_id sender_id | |||
| pull = issue.try(:pull_request) | |||
| return if pull.nil? || sender.nil? | |||
| return if issue.nil? || pull.nil? || sender.nil? | |||
| comment = issue.comment_journals.find_by_id comment_id | |||
| return if action_type == 'edited' && comment_json.blank? | |||
| pull.project.webhooks.each do |webhook| | |||
| @@ -0,0 +1,33 @@ | |||
| class UpdateProjectTopicJob < ApplicationJob | |||
| include ProjectsHelper | |||
| queue_as :message | |||
| def perform(project_id) | |||
| project = Project.find_by(id: project_id) | |||
| return if project.blank? | |||
| begin | |||
| languages = $gitea_client.get_repos_languages_by_owner_repo(project.owner.login, project.identifier) | |||
| puts "#{project.owner.login}/#{project.identifier} get_repos_languages:#{languages}" | |||
| topic_count = 0 | |||
| if project.project_category_id.present? | |||
| project_topic = ProjectTopic.find_or_create_by!(name: project.project_category.name.downcase) | |||
| project_topic_ralate = project_topic.project_topic_ralates.find_or_create_by!(project_id: project.id) | |||
| if project_topic.present? && project_topic_ralate.present? | |||
| topic_count +=1 | |||
| end | |||
| end | |||
| languages.each do |k, _| | |||
| next if topic_count >= 3 | |||
| project_topic = ProjectTopic.find_or_create_by!(name: k.downcase) | |||
| project_topic_ralate = project_topic.project_topic_ralates.find_or_create_by!(project_id: project.id) | |||
| if project_topic.present? && project_topic_ralate.present? | |||
| topic_count +=1 | |||
| end | |||
| end | |||
| rescue => e | |||
| puts "get_repos_languages: error:#{e.message}" | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,20 @@ | |||
| module Getway | |||
| class << self | |||
| def getway_config | |||
| getway_config = {} | |||
| begin | |||
| config = Rails.application.config_for(:configuration).symbolize_keys! | |||
| getway_config = config[:getway].symbolize_keys! | |||
| raise 'getway config missing' if getway_config.blank? | |||
| rescue => ex | |||
| raise ex if Rails.env.production? | |||
| puts %Q{\033[33m [warning] getway config or configuration.yml missing, | |||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||
| getway_config = {} | |||
| end | |||
| getway_config | |||
| end | |||
| end | |||
| end | |||
| @@ -30,4 +30,11 @@ class UserMailer < ApplicationMailer | |||
| def feedback_email(mail, title, content) | |||
| mail(to: mail, subject: title, content_type: "text/html", body: content) | |||
| end | |||
| def glcc_pr_check_email(mail, title, name, content) | |||
| @content = content | |||
| @name = name | |||
| mail(to: mail, subject: title) | |||
| end | |||
| end | |||
| @@ -1,41 +1,44 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: attachments | |||
| # | |||
| # id :integer not null, primary key | |||
| # container_id :integer | |||
| # container_type :string(30) | |||
| # filename :string(255) default(""), not null | |||
| # disk_filename :string(255) default(""), not null | |||
| # filesize :integer default("0"), not null | |||
| # content_type :string(255) default("") | |||
| # digest :string(60) default(""), not null | |||
| # downloads :integer default("0"), not null | |||
| # author_id :integer default("0"), not null | |||
| # created_on :datetime | |||
| # description :text(65535) | |||
| # disk_directory :string(255) | |||
| # attachtype :integer default("1") | |||
| # is_public :integer default("1") | |||
| # copy_from :string(255) | |||
| # quotes :integer default("0") | |||
| # is_publish :integer default("1") | |||
| # publish_time :datetime | |||
| # resource_bank_id :integer | |||
| # unified_setting :boolean default("1") | |||
| # cloud_url :string(255) default("") | |||
| # course_second_category_id :integer default("0") | |||
| # delay_publish :boolean default("0") | |||
| # link :string(255) | |||
| # clone_id :integer | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_attachments_on_author_id (author_id) | |||
| # index_attachments_on_clone_id (clone_id) | |||
| # index_attachments_on_container_id_and_container_type (container_id,container_type) | |||
| # index_attachments_on_created_on (created_on) | |||
| # | |||
| # == Schema Information | |||
| # | |||
| # Table name: attachments | |||
| # | |||
| # id :integer not null, primary key | |||
| # container_id :integer | |||
| # container_type :string(30) | |||
| # filename :string(255) default(""), not null | |||
| # disk_filename :string(255) default(""), not null | |||
| # filesize :integer default("0"), not null | |||
| # content_type :string(255) default("") | |||
| # digest :string(60) default(""), not null | |||
| # downloads :integer default("0"), not null | |||
| # author_id :integer default("0"), not null | |||
| # created_on :datetime | |||
| # description :text(65535) | |||
| # disk_directory :string(255) | |||
| # attachtype :integer default("1") | |||
| # is_public :integer default("1") | |||
| # copy_from :integer | |||
| # quotes :integer default("0") | |||
| # is_publish :integer default("1") | |||
| # publish_time :datetime | |||
| # resource_bank_id :integer | |||
| # unified_setting :boolean default("1") | |||
| # cloud_url :string(255) default("") | |||
| # course_second_category_id :integer default("0") | |||
| # delay_publish :boolean default("0") | |||
| # memo_image :boolean default("0") | |||
| # extra_type :integer default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_attachments_on_author_id (author_id) | |||
| # index_attachments_on_container_id_and_container_type (container_id,container_type) | |||
| # index_attachments_on_course_second_category_id (course_second_category_id) | |||
| # index_attachments_on_created_on (created_on) | |||
| # index_attachments_on_is_public (is_public) | |||
| # index_attachments_on_quotes (quotes) | |||
| # | |||
| @@ -2,23 +2,24 @@ | |||
| # | |||
| # Table name: bot | |||
| # | |||
| # id :integer not null, primary key | |||
| # bot_name :string(255) | |||
| # bot_des :text(4294967295) | |||
| # webhook :string(255) | |||
| # is_public :integer | |||
| # logo :string(255) | |||
| # state :integer | |||
| # client_id :string(255) | |||
| # client_secret :string(255) | |||
| # web_url :string(255) | |||
| # category :string(255) | |||
| # install_num :integer default("0") | |||
| # update_time :datetime not null | |||
| # create_time :datetime not null | |||
| # private_key :text(65535) | |||
| # uid :integer | |||
| # owner_id :integer | |||
| # id :integer not null, primary key | |||
| # bot_name :string(255) not null | |||
| # bot_des :text(4294967295) | |||
| # webhook :string(255) not null | |||
| # is_public :integer | |||
| # logo :string(255) | |||
| # state :integer | |||
| # client_id :string(255) | |||
| # client_secret :string(255) | |||
| # web_url :string(255) | |||
| # category :string(255) | |||
| # install_num :integer default("0") | |||
| # update_time :datetime not null | |||
| # create_time :datetime not null | |||
| # uid :integer | |||
| # owner_id :integer | |||
| # private_key :text(65535) | |||
| # oauth_callback_url :string(255) not null | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -2,13 +2,18 @@ | |||
| # | |||
| # Table name: install_bot | |||
| # | |||
| # id :integer not null, primary key | |||
| # bot_id :integer not null | |||
| # installer_id :integer not null | |||
| # store_id :integer not null | |||
| # state :integer not null | |||
| # create_time :datetime not null | |||
| # update_time :datetime not null | |||
| # id :integer not null, primary key | |||
| # bot_id :integer not null | |||
| # installer_id :integer not null | |||
| # store_id :integer not null | |||
| # state :integer not null | |||
| # create_time :datetime not null | |||
| # update_time :datetime not null | |||
| # installer_login :string(255) not null | |||
| # store_repo :string(255) not null | |||
| # webhook_id :integer | |||
| # webhook_response_msg :text(65535) | |||
| # repo_owner :string(255) | |||
| # | |||
| # frozen_string_literal: true | |||
| @@ -39,15 +39,17 @@ | |||
| # business :boolean default("0") | |||
| # profile_completed :boolean default("0") | |||
| # laboratory_id :integer | |||
| # is_shixun_marker :boolean default("0") | |||
| # admin_visitable :boolean default("0") | |||
| # collaborator :boolean default("0") | |||
| # platform :string(255) default("0") | |||
| # gitea_token :string(255) | |||
| # gitea_uid :integer | |||
| # is_shixun_marker :boolean default("0") | |||
| # is_sync_pwd :boolean default("1") | |||
| # watchers_count :integer default("0") | |||
| # devops_step :integer default("0") | |||
| # gitea_token :string(255) | |||
| # platform :string(255) | |||
| # sign_cla :boolean default("0") | |||
| # enabling_cla :boolean default("0") | |||
| # id_card_verify :boolean default("0") | |||
| # website_permission :boolean default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -56,8 +58,7 @@ | |||
| # index_users_on_homepage_teacher (homepage_teacher) | |||
| # index_users_on_laboratory_id (laboratory_id) | |||
| # index_users_on_login (login) UNIQUE | |||
| # index_users_on_mail (mail) UNIQUE | |||
| # index_users_on_phone (phone) UNIQUE | |||
| # index_users_on_mail (mail) | |||
| # index_users_on_type (type) | |||
| # | |||
| @@ -0,0 +1,46 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: clas | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) not null | |||
| # key :string(255) not null | |||
| # content :text(65535) | |||
| # organization_id :integer not null | |||
| # pr_need :boolean default("0") | |||
| # count :integer default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_clas_on_key (key) | |||
| # index_clas_on_organization_id (organization_id) | |||
| # | |||
| class Cla < ApplicationRecord | |||
| has_many :user_clas, :dependent => :destroy | |||
| has_many :users, through: :user_clas | |||
| belongs_to :organization | |||
| def to_param | |||
| self.key.parameterize | |||
| end | |||
| def self.build(params,org_id) | |||
| self.create!(organization_id: org_id, | |||
| name: params[:name], | |||
| key: params[:key], | |||
| content: params[:content], | |||
| pr_need: params[:pr_need] | |||
| ) | |||
| end | |||
| def valid_sign(user_id) | |||
| user_clas.where(user_id: user_id, state:1).present? | |||
| end | |||
| def fresh_count | |||
| number = self.user_clas.where(state: 1).count | |||
| update(count: number) | |||
| end | |||
| end | |||
| @@ -1,3 +1,26 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: commit_logs | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer | |||
| # project_id :integer | |||
| # repository_id :integer | |||
| # name :string(255) | |||
| # full_name :string(255) | |||
| # commit_id :string(255) | |||
| # ref :string(255) | |||
| # message :text(65535) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_commit_logs_on_commit_id (commit_id) | |||
| # index_commit_logs_on_project_id (project_id) | |||
| # index_commit_logs_on_user_id (user_id) | |||
| # | |||
| class CommitLog < ApplicationRecord | |||
| belongs_to :user | |||
| belongs_to :project | |||
| @@ -200,7 +200,7 @@ module ProjectOperable | |||
| if owner.is_a?(User) | |||
| managers.exists?(user_id: user.id) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| elsif owner.is_a?(Organization) | |||
| managers.exists?(user_id: user.id) || owner.is_owner?(user.id) || (owner.is_only_admin?(user.id) && (teams.pluck(:id) & user.teams.pluck(:id)).size > 0) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| managers.exists?(user_id: user.id) || owner.is_owner?(user.id) || (owner.is_admin?(user.id) && (teams.pluck(:id) & user.teams.pluck(:id)).size > 0) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| else | |||
| false | |||
| end | |||
| @@ -212,7 +212,7 @@ module ProjectOperable | |||
| if owner.is_a?(User) | |||
| developers.exists?(user_id: user.id) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| elsif owner.is_a?(Organization) | |||
| developers.exists?(user_id: user.id) || (owner.is_only_write?(user.id) && (teams.pluck(:id) & user.teams.pluck(:id)).size > 0) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| developers.exists?(user_id: user.id) || (owner.is_write?(user.id) && (teams.pluck(:id) & user.teams.pluck(:id)).size > 0) || (user.platform == "bot" && BotInstall.joins(:bot).where(bot: { uid: user.id }).where(store_id: self.id).exists?) | |||
| else | |||
| false | |||
| end | |||
| @@ -1,18 +1,19 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: edu_settings | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) | |||
| # value :string(255) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # description :string(255) | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_edu_settings_on_name (name) UNIQUE | |||
| # | |||
| # == Schema Information | |||
| # | |||
| # Table name: edu_settings | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) | |||
| # value :string(255) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # description :string(255) | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_edu_settings_on_name (name) UNIQUE | |||
| # | |||
| class EduSetting < ApplicationRecord | |||
| after_commit :expire_value_cache | |||
| @@ -1,3 +1,25 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: public_key | |||
| # | |||
| # id :integer not null, primary key | |||
| # owner_id :integer not null | |||
| # name :string(255) not null | |||
| # fingerprint :string(255) not null | |||
| # content :text(16777215) not null | |||
| # mode :integer default("2"), not null | |||
| # type :integer default("1"), not null | |||
| # login_source_id :integer default("0"), not null | |||
| # created_unix :integer | |||
| # updated_unix :integer | |||
| # verified :boolean default("0"), not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # IDX_public_key_fingerprint (fingerprint) | |||
| # IDX_public_key_owner_id (owner_id) | |||
| # | |||
| class Gitea::PublicKey < Gitea::Base | |||
| self.inheritance_column = nil # FIX The single-table inheritance mechanism failed | |||
| # establish_connection :gitea_db | |||
| @@ -16,10 +16,12 @@ | |||
| # head_branch :string(255) | |||
| # base_branch :string(255) | |||
| # merge_base :string(40) | |||
| # allow_maintainer_edit :boolean default("0"), not null | |||
| # has_merged :boolean | |||
| # merged_commit_id :string(40) | |||
| # merger_id :integer | |||
| # merged_unix :integer | |||
| # flow :integer default("0"), not null | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -1,3 +1,32 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: webhook | |||
| # | |||
| # id :integer not null, primary key | |||
| # repo_id :integer | |||
| # org_id :integer | |||
| # is_system_webhook :boolean | |||
| # url :text(65535) | |||
| # http_method :string(255) | |||
| # content_type :integer | |||
| # secret :text(65535) | |||
| # events :text(65535) | |||
| # is_active :boolean | |||
| # type :string(16) | |||
| # meta :text(65535) | |||
| # last_status :integer | |||
| # created_unix :integer | |||
| # updated_unix :integer | |||
| # | |||
| # Indexes | |||
| # | |||
| # IDX_webhook_created_unix (created_unix) | |||
| # IDX_webhook_is_active (is_active) | |||
| # IDX_webhook_org_id (org_id) | |||
| # IDX_webhook_repo_id (repo_id) | |||
| # IDX_webhook_updated_unix (updated_unix) | |||
| # | |||
| class Gitea::Webhook < Gitea::Base | |||
| serialize :events, JSON | |||
| self.inheritance_column = nil | |||
| @@ -10,4 +39,4 @@ class Gitea::Webhook < Gitea::Base | |||
| enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9} | |||
| enum last_status: {waiting: 0, succeed: 1, fail: 2} | |||
| enum content_type: {json: 1, form: 2} | |||
| end | |||
| end | |||
| @@ -1,3 +1,19 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: hook_task | |||
| # | |||
| # id :integer not null, primary key | |||
| # hook_id :integer | |||
| # uuid :string(255) | |||
| # payload_content :text(4294967295) | |||
| # event_type :string(255) | |||
| # is_delivered :boolean | |||
| # delivered :integer | |||
| # is_succeed :boolean | |||
| # request_content :text(4294967295) | |||
| # response_content :text(4294967295) | |||
| # | |||
| class Gitea::WebhookTask < Gitea::Base | |||
| serialize :payload_content, JSON | |||
| serialize :request_content, JSON | |||
| @@ -11,4 +27,4 @@ class Gitea::WebhookTask < Gitea::Base | |||
| enum type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9} | |||
| end | |||
| end | |||
| @@ -0,0 +1,103 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: glcc_medium_term_examine_material | |||
| # | |||
| # id :integer not null, primary key | |||
| # student_reg_id :integer not null | |||
| # task_id :integer not null | |||
| # defence_video_url :string(1000) not null | |||
| # code_or_pr_url :string(1000) | |||
| # PPT_attachment_id :integer not null | |||
| # term :integer | |||
| # created_on :datetime | |||
| # updated_on :datetime | |||
| # is_delete :boolean default("0"), not null | |||
| # round :integer default("1"), not null | |||
| # | |||
| class GlccMediumTermExamineMaterial < ActiveRecord::Base | |||
| self.table_name = "glcc_medium_term_examine_material" | |||
| belongs_to :glcc_student, :class_name => :GlccRegistrationStudent, :foreign_key => "student_reg_id" | |||
| belongs_to :task, :class_name => :GlccRegistrationTask, :foreign_key => "task_id" | |||
| def check_pr_url | |||
| state = [] | |||
| # code_or_pr_url = "https://www.gitlink.org.cn/Gitlink/forgeplus/pulls/337" | |||
| url_array = code_or_pr_url.split("/") | |||
| gitlink_index = url_array.index("www.gitlink.org.cn") || url_array.index("gitlink.org.cn") || url_array.index("testforgeplus.trustie.net") | |||
| pull_index = url_array.index("pulls") | |||
| #发送没有在gitlink上提交PR的邮件 | |||
| unless gitlink_index.present? | |||
| state << 1 | |||
| end | |||
| # 输入的地址有问题邮件内容 | |||
| unless pull_index == 5 | |||
| state << 2 | |||
| end | |||
| user = Owner.find_by(login: url_array[3]) | |||
| project = Project.find_by(identifier: url_array[4], user_id:user.try(:id)) | |||
| pr = PullRequest.where(project:project, gitea_number:url_array[6]) | |||
| unless pr.present? | |||
| state << 3 | |||
| end | |||
| if white_list #特殊处理 白名单考核不处理 | |||
| state = [] | |||
| end | |||
| state | |||
| end | |||
| def white_list | |||
| # 全局设置白名单 key | |||
| key = "glcc_white_task_#{self.created_on.year}" | |||
| white_task = EduSetting.find_by_name(key) | |||
| if white_task | |||
| task_ids = white_task.value.split(",") | |||
| task_ids.map(&:to_i).include?(self.task_id) | |||
| else | |||
| false | |||
| end | |||
| end | |||
| def send_mail | |||
| gcs = glcc_student | |||
| mail = gcs.mail | |||
| return if mail.nil? || code_or_pr_url.nil? | |||
| state = check_pr_url | |||
| return unless state.present? | |||
| title = "#{self.created_on.year}年GitLink确实开源GLCC开源夏令营#{term == 1 ? "中期考核" : "结项考核"}提醒" | |||
| content = gennerate_content(state) | |||
| UserMailer.glcc_pr_check_email(mail,title, gcs.student_name, content).deliver_now | |||
| end | |||
| def state_to_html | |||
| gcs = glcc_student | |||
| mail = gcs.mail | |||
| return "数据异常,PR链接为空" if mail.nil? || code_or_pr_url.nil? | |||
| state = check_pr_url | |||
| gennerate_content(state) | |||
| end | |||
| def gennerate_content(state) | |||
| content = "" | |||
| state.map{|e| | |||
| content = content + number_to_content(e) | |||
| } | |||
| content | |||
| end | |||
| def number_to_content(num) | |||
| case num | |||
| when 1 | |||
| "<p> PR链接为非GitLink平台链接 </p>" | |||
| when 2 | |||
| "<p> PR链接为GitLink平台链接, 但非PR链接 </p>" | |||
| when 3 | |||
| "<p> PR链接中的PR不存在 </p>" | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,24 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: glcc_registration_student | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer not null | |||
| # student_name :string(255) | |||
| # school :string(255) | |||
| # profession :string(255) | |||
| # location :string(255) | |||
| # grade :string(255) | |||
| # phone :string(255) | |||
| # mail :string(255) | |||
| # created_on :datetime | |||
| # is_delete :boolean default("0"), not null | |||
| # prove_attachment_id :integer | |||
| # cancel_count :integer default("0") | |||
| # round :integer default("1"), not null | |||
| # | |||
| class GlccRegistrationStudent < ActiveRecord::Base | |||
| self.table_name = "glcc_registration_student" | |||
| has_many :examines, :class_name => :GlccMediumTermExamineMaterial, :foreign_key => "student_reg_id" | |||
| end | |||
| @@ -0,0 +1,30 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: glcc_registration_task | |||
| # | |||
| # id :integer not null, primary key | |||
| # reg_id :integer not null | |||
| # task_name :string(255) | |||
| # task_desc :text(16777215) | |||
| # task_difficulty :integer | |||
| # task_url :string(1000) | |||
| # task_reward :string(255) | |||
| # tutor_name :string(255) | |||
| # tutor_mail :string(255) | |||
| # tutor_phone :string(255) | |||
| # created_on :datetime | |||
| # is_delete :boolean default("0"), not null | |||
| # sort_no :integer default("0") | |||
| # locked :boolean default("0") | |||
| # round :integer default("1"), not null | |||
| # check_status :boolean default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| # idx_glcc_reg_id (reg_id) | |||
| # | |||
| class GlccRegistrationTask < ActiveRecord::Base | |||
| self.table_name = "glcc_registration_task" | |||
| has_many :examines, :class_name => :GlccMediumTermExamineMaterial, :foreign_key => "task_id" | |||
| end | |||
| @@ -9,7 +9,6 @@ | |||
| # agreement :text(65535) | |||
| # status :text(65535) | |||
| # help_center :text(65535) | |||
| # join_us :text(65535) | |||
| # | |||
| class Help < ApplicationRecord | |||
| @@ -0,0 +1,48 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: identity_verifications | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer not null | |||
| # number :string(255) not null | |||
| # name :string(255) not null | |||
| # card_front :integer | |||
| # card_back :integer | |||
| # hold_card_front :integer | |||
| # hold_card_back :integer | |||
| # state :integer default("0") | |||
| # description :string(255) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_identity_verifications_on_user_id (user_id) | |||
| # | |||
| class IdentityVerification < ApplicationRecord | |||
| belongs_to :user | |||
| enum state: { "待审核": 0, "已通过": 1, "已拒绝": 2} | |||
| after_save do | |||
| if state == "已通过" | |||
| user.update(id_card_verify: true, website_permission: true) | |||
| end | |||
| end | |||
| def card_front_attachment | |||
| Attachment.find_by_id card_front | |||
| end | |||
| def card_back_attachment | |||
| Attachment.find_by_id card_back | |||
| end | |||
| def hold_card_front_attachment | |||
| Attachment.find_by_id hold_card_front | |||
| end | |||
| def hold_card_back_attachment | |||
| Attachment.find_by_id hold_card_back | |||
| end | |||
| end | |||
| @@ -1,3 +1,26 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: open_shixuns | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) | |||
| # shixun_user_name :string(255) | |||
| # shixun_user_phone :string(255) | |||
| # shixun_user_mail :string(255) | |||
| # shixun_identifier :string(255) | |||
| # git_url :string(255) | |||
| # identifier :string(255) | |||
| # myshixun_git_url :string(255) | |||
| # myshixun_user_name :string(255) | |||
| # myshixun_user_phone :string(255) | |||
| # myshixun_user_mail :string(255) | |||
| # | |||
| # Indexes | |||
| # | |||
| # idx_email (myshixun_user_mail) | |||
| # idx_phone (myshixun_user_phone) | |||
| # | |||
| # for oauth2 application | |||
| @@ -5,7 +5,7 @@ | |||
| # id :integer not null, primary key | |||
| # tracker_id :integer not null | |||
| # project_id :integer not null | |||
| # subject :string(255) default(""), not null | |||
| # subject :string(255) | |||
| # description :text(4294967295) | |||
| # due_date :date | |||
| # category_id :integer | |||
| @@ -33,6 +33,7 @@ | |||
| # issue_classify :string(255) | |||
| # ref_name :string(255) | |||
| # branch_name :string(255) | |||
| # blockchain_token_num :integer | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -1,3 +1,20 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: issue_participants | |||
| # | |||
| # id :integer not null, primary key | |||
| # issue_id :integer | |||
| # participant_id :integer | |||
| # participant_type :integer default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_issue_participants_on_issue_id (issue_id) | |||
| # index_issue_participants_on_participant_id (participant_id) | |||
| # | |||
| class IssueParticipant < ApplicationRecord | |||
| belongs_to :issue | |||
| @@ -2,17 +2,18 @@ | |||
| # | |||
| # Table name: issue_tags | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) | |||
| # description :string(255) | |||
| # color :string(255) | |||
| # user_id :integer | |||
| # project_id :integer | |||
| # issues_count :integer default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # gid :integer | |||
| # gitea_url :string(255) | |||
| # id :integer not null, primary key | |||
| # name :string(190) | |||
| # description :string(255) | |||
| # color :string(255) | |||
| # user_id :integer | |||
| # project_id :integer | |||
| # issues_count :integer default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # gid :integer | |||
| # gitea_url :string(255) | |||
| # pull_requests_count :integer default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -10,7 +10,6 @@ | |||
| # sync_course :boolean default("0") | |||
| # sync_subject :boolean default("0") | |||
| # sync_shixun :boolean default("0") | |||
| # is_local :boolean default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -7,6 +7,7 @@ | |||
| # content :text(65535) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # is_secret :boolean default("0") | |||
| # | |||
| class License < ApplicationRecord | |||
| @@ -1,3 +1,23 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: mark_files | |||
| # | |||
| # id :integer not null, primary key | |||
| # pull_request_id :integer | |||
| # user_id :integer | |||
| # file_path_sha :string(255) | |||
| # file_path :string(255) | |||
| # mark_as_read :boolean default("0") | |||
| # updated_after_read :boolean default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_mark_files_on_file_path_sha (file_path_sha) | |||
| # index_mark_files_on_pull_request_id (pull_request_id) | |||
| # | |||
| class MarkFile < ApplicationRecord | |||
| belongs_to :pull_request | |||
| @@ -11,6 +11,7 @@ | |||
| # course_group_id :integer default("0") | |||
| # is_collect :integer default("1") | |||
| # graduation_group_id :integer default("0") | |||
| # is_apply_signature :boolean default("0") | |||
| # team_user_id :integer | |||
| # | |||
| # Indexes | |||
| @@ -1,3 +1,17 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: message_templates | |||
| # | |||
| # id :integer not null, primary key | |||
| # type :string(255) | |||
| # sys_notice :text(65535) | |||
| # email :text(65535) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # notification_url :string(255) | |||
| # email_title :string(255) | |||
| # | |||
| class MessageTemplate::IssueCreatorExpire < MessageTemplate | |||
| end | |||
| end | |||
| @@ -46,11 +46,10 @@ | |||
| # is_sync_pwd :boolean default("1") | |||
| # watchers_count :integer default("0") | |||
| # devops_step :integer default("0") | |||
| # sponsor_certification :integer default("0") | |||
| # sponsor_num :integer default("0") | |||
| # sponsored_num :integer default("0") | |||
| # sponsor_description :text(65535) | |||
| # award_time :datetime | |||
| # sign_cla :boolean default("0") | |||
| # enabling_cla :boolean default("0") | |||
| # id_card_verify :boolean default("0") | |||
| # website_permission :boolean default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -58,7 +57,7 @@ | |||
| # index_users_on_homepage_engineer (homepage_engineer) | |||
| # index_users_on_homepage_teacher (homepage_teacher) | |||
| # index_users_on_laboratory_id (laboratory_id) | |||
| # index_users_on_login (login) | |||
| # index_users_on_login (login) UNIQUE | |||
| # index_users_on_mail (mail) | |||
| # index_users_on_type (type) | |||
| # | |||
| @@ -70,6 +69,8 @@ class Organization < Owner | |||
| default_scope { where(type: "Organization") } | |||
| has_one :organization_extension, dependent: :destroy | |||
| has_one :cla, dependent: :destroy | |||
| has_many :teams, dependent: :destroy | |||
| has_many :organization_users, dependent: :destroy | |||
| has_many :team_users, dependent: :destroy | |||
| @@ -108,6 +109,16 @@ class Organization < Owner | |||
| organization_users.where(user_id: user_id).present? | |||
| end | |||
| def is_sign?(user_id) | |||
| return false if cla.nil? | |||
| cla.user_clas.where(user_id: user_id, state: 1).present? | |||
| end | |||
| def cla_sign_email(user_id) | |||
| cla.user_clas.find_by(user_id: user_id)&.email | |||
| end | |||
| def is_owner?(user_id) | |||
| team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(owner)}).present? | |||
| end | |||
| @@ -126,14 +137,24 @@ class Organization < Owner | |||
| def is_only_admin?(user_id) | |||
| team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(admin)}).present? | |||
| roles = has_roles(user_id) | |||
| roles.size > 1 ? false : roles.include?("admin") | |||
| end | |||
| def is_only_write?(user_id) | |||
| team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(write)}).present? | |||
| # team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(write)}).present? | |||
| roles = has_roles(user_id) | |||
| roles.size > 1 ? false : roles.include?("write") | |||
| end | |||
| def is_only_read?(user_id) | |||
| team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read)}).present? | |||
| # team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read)}).present? | |||
| roles = has_roles(user_id) | |||
| roles.size > 1 ? false : roles.include?("read") | |||
| end | |||
| def has_roles(user_id) | |||
| teams.joins(:team_users).where("team_users.user_id=?", user_id).pluck("teams.authorize").uniq | |||
| end | |||
| # 是不是所有者团队的最后一个成员 | |||
| @@ -183,4 +204,17 @@ class Organization < Owner | |||
| name | |||
| end | |||
| end | |||
| def open_cla! | |||
| update_attribute(:enabling_cla, true) | |||
| end | |||
| def close_cla! | |||
| update_attribute(:enabling_cla, false) | |||
| end | |||
| def open_cla? | |||
| enabling_cla == true | |||
| end | |||
| end | |||
| @@ -19,6 +19,8 @@ | |||
| # news_banner_id :integer | |||
| # news_content :text(65535) | |||
| # memo :text(65535) | |||
| # news_title :string(255) | |||
| # news_url :string(255) | |||
| # | |||
| # Indexes | |||
| # | |||
| @@ -5,6 +5,7 @@ | |||
| # id :integer not null, primary key | |||
| # user_id :integer | |||
| # organization_id :integer | |||
| # is_creator :boolean default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| @@ -0,0 +1,56 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: pages | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer not null | |||
| # project_id :integer not null | |||
| # identifier :string(255) | |||
| # site_name :string(255) | |||
| # language_frame :integer default("0") | |||
| # theme :string(255) | |||
| # last_build_at :datetime | |||
| # state :boolean default("1") | |||
| # state_description :string(255) | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # last_build_info :text(65535) | |||
| # build_state :boolean | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_pages_on_project_id (project_id) | |||
| # index_pages_on_user_id (user_id) | |||
| # | |||
| class Page < ApplicationRecord | |||
| belongs_to :user | |||
| belongs_to :project | |||
| # language_frame 前端语言框架 | |||
| enum language_frame: { hugo: 0, jekyll: 1, hexo: 2} | |||
| after_create do | |||
| PageService.genernate_user(user_id) | |||
| end | |||
| before_save do | |||
| if state_changed? && state == false | |||
| PageService.close_site(user_id, identifier) | |||
| end | |||
| end | |||
| def deploy_page(branch) | |||
| PageService.deploy_page(branch,self.id) | |||
| end | |||
| def url | |||
| @deploy_domain = EduSetting.find_by_name("site_page_deploy_domain").try(:value) | |||
| "http://#{user.login}.#{@deploy_domain}/#{identifier}" | |||
| end | |||
| def build_script_path | |||
| "#{language_frame}_build" | |||
| end | |||
| end | |||
| @@ -0,0 +1,29 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: page_themes | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) not null | |||
| # language_frame :integer default("0") | |||
| # image_url :string(255) | |||
| # clone_url :string(255) not null | |||
| # order_index :integer default("0") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| class PageTheme < ApplicationRecord | |||
| enum language_frame: { hugo: 0, jeklly: 1, hexo: 2} | |||
| validates :name, presence: {message: "主题名不能为空"}, uniqueness: {message: "主题名已存在",scope: :language_frame},length: {maximum: 255} | |||
| def image | |||
| page_image_url('image') | |||
| end | |||
| private | |||
| def page_image_url(type) | |||
| return nil unless Util::FileManage.exists?(self, type) | |||
| Util::FileManage.source_disk_file_url(self, type) | |||
| end | |||
| end | |||
| @@ -1,19 +1,20 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: praise_treads | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer not null | |||
| # praise_tread_object_id :integer | |||
| # praise_tread_object_type :string(255) | |||
| # praise_or_tread :integer default("1") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # praise_tread (praise_tread_object_id,praise_tread_object_type) | |||
| # | |||
| # == Schema Information | |||
| # | |||
| # Table name: praise_treads | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer not null | |||
| # praise_tread_object_id :integer | |||
| # praise_tread_object_type :string(255) | |||
| # praise_or_tread :integer default("1") | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # praise_tread (praise_tread_object_id,praise_tread_object_type) | |||
| # | |||
| class PraiseTread < ApplicationRecord | |||
| @@ -3,7 +3,7 @@ | |||
| # Table name: projects | |||
| # | |||
| # id :integer not null, primary key | |||
| # name :string(255) | |||
| # name :string(190) | |||
| # description :text(4294967295) | |||
| # homepage :string(255) default("") | |||
| # is_public :boolean default("1"), not null | |||
| @@ -57,17 +57,22 @@ | |||
| # lesson_url :string(255) | |||
| # is_pinned :boolean default("0") | |||
| # recommend_index :integer default("0") | |||
| # use_blockchain :boolean default("0") | |||
| # pr_view_admin :boolean default("0") | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_projects_on_forked_count (forked_count) | |||
| # index_projects_on_forked_from_project_id (forked_from_project_id) | |||
| # index_projects_on_identifier (identifier) | |||
| # index_projects_on_invite_code (invite_code) | |||
| # index_projects_on_is_pinned (is_pinned) | |||
| # index_projects_on_is_public (is_public) | |||
| # index_projects_on_lft (lft) | |||
| # index_projects_on_license_id (license_id) | |||
| # index_projects_on_name (name) | |||
| # index_projects_on_platform (platform) | |||
| # index_projects_on_praises_count (praises_count) | |||
| # index_projects_on_project_category_id (project_category_id) | |||
| # index_projects_on_project_language_id (project_language_id) | |||
| # index_projects_on_project_type (project_type) | |||
| @@ -75,6 +80,7 @@ | |||
| # index_projects_on_rgt (rgt) | |||
| # index_projects_on_status (status) | |||
| # index_projects_on_updated_on (updated_on) | |||
| # index_projects_on_user_id (user_id) | |||
| # | |||
| class Project < ApplicationRecord | |||
| @@ -114,6 +120,7 @@ class Project < ApplicationRecord | |||
| has_many :issues, dependent: :destroy | |||
| # has_many :user_grades, dependent: :destroy | |||
| has_many :attachments, as: :container, dependent: :destroy | |||
| has_one :page, dependent: :destroy | |||
| has_one :project_score, dependent: :destroy | |||
| has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy | |||
| has_many :praise_treads, as: :praise_tread_object, dependent: :destroy | |||