Merge pull request #365 from abf/rosa-build:345-update_to_rails4

#345: Update to rails 4
This commit is contained in:
avm 2014-03-27 12:12:48 +04:00
commit 93dd8dc48e
285 changed files with 2806 additions and 2870 deletions

View File

@ -1,6 +1,6 @@
language: ruby
rvm:
- 2.1.0
- 2.1.1
bundler_args: --without development
env:
- SPEC_GROUP=controllers
@ -18,7 +18,7 @@ before_install:
before_script:
- cp config/database.yml.sample config/database.yml
- cp config/application.yml.travis config/application.yml
- bundle exec rake db:create db:structure:load db:migrate
- bundle exec rake db:create db:schema:load db:migrate
script: "./travis.sh"
branches:
only:

103
Gemfile
View File

@ -1,71 +1,69 @@
source 'https://rubygems.org'
gem 'rails', '3.2.17'
gem 'redhillonrails_core', git: 'git://github.com/rosa-abf/redhillonrails_core.git', branch: 'rails31' # '~> 2.0.0.pre' # deprecated
gem 'rails', '4.0.4'
gem 'pg', '~> 0.14.0'
gem 'activerecord-postgres-hstore'
gem 'devise', '~> 2.2.3'
gem 'pg', '~> 0.17.1'
gem 'schema_plus', '~> 1.4.0'
########
gem 'protected_attributes'
########
gem 'devise', '~> 3.2.3'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-google-oauth2'
gem 'omniauth-github'
# gem 'omniauth-openid', '~> 1.0.1'
gem 'cancan', '1.6.7' # 1.6.8 fail specs with strange error
# gem 'cancan', '1.6.10'
gem 'cancan', git: 'git://github.com/rosa-abf/cancan.git', tag: '1.6.10-abf'
gem 'ancestry', '~> 1.3.0'
gem 'paperclip', '~> 4.1.0'
gem 'resque', '~> 1.24'
gem 'resque-status', '~> 0.3.3'
gem 'ancestry', '~> 2.0.0'
gem 'paperclip', '~> 4.1.1'
gem 'resque', '~> 1.25'
gem 'resque-status', '~> 0.4.2'
gem 'resque_mailer', '~> 2.2'
gem 'resque-scheduler'
# gem 'perform_later', '~> 1.3.0' # should be after resque_mailer
gem 'resque-scheduler', '~> 2.5.4'
gem 'perform_later', git: 'git://github.com/KensoDev/perform_later.git' # should be after resque_mailer
gem 'russian', '~> 0.6.0'
gem 'highline', '~> 1.6.11'
gem 'state_machine'
gem 'redis-rails'
gem 'highline', '~> 1.6.20'
gem 'state_machine', '~> 1.2'
gem 'redis-rails', '~> 4.0'
gem 'grack', git: 'git://github.com/rosa-abf/grack.git', require: 'git_http'
gem 'grit', git: 'git://github.com/rosa-abf/grit.git'
gem 'charlock_holmes', '~> 0.6.9'
gem 'github-linguist', '~> 2.3.4', require: 'linguist'
gem 'github-linguist', '~> 2.10', require: 'linguist'
gem 'diff-display', '~> 0.0.1'
# Wiki
gem "gollum", '~> 2.1.3'
gem "redcarpet", '~> 2.2.2'
gem "gollum-lib", '~> 2.0'
gem "redcarpet", '~> 3.1.1'
gem 'creole'
gem 'rdiscount'
# gem 'org-ruby'
gem 'RedCloth'
gem 'wikicloth'
# gem 'unicorn', '~> 4.3.1', platforms: [:mri, :rbx]
gem 'trinidad', '~> 1.0.2', platforms: :jruby
gem 'newrelic_rpm'
# gem 'whenever', '~> 0.7.3', require: false
gem 'whenever', '~> 0.9.0', require: false
gem 'jbuilder', '~> 1.4.2'
gem 'rails3-jquery-autocomplete', '~> 1.0.7'
gem 'will_paginate', '~> 3.0.3'
gem 'meta-tags', '~> 1.2.5', require: 'meta_tags'
gem "haml-rails", '~> 0.3.4'
gem 'jquery-rails', '~> 2.0.2'
gem 'ruby-haml-js', '~> 0.0.3'
gem 'friendly_id'
gem 'jbuilder', '~> 2.0.3'
gem 'rails3-jquery-autocomplete', '~> 1.0'
gem 'will_paginate', '~> 3.0.5'
gem 'meta-tags', '~> 1.5', require: 'meta_tags'
gem "haml-rails", '~> 0.5'
gem 'jquery-rails', '~> 2.3.0'
gem 'jquery-migrate-rails'
gem 'ruby-haml-js', '~> 0.0.5'
gem 'friendly_id', '~> 5.0.3'
gem 'rack-throttle'
gem 'rest-client', '~> 1.6.6'
gem 'ohm'
gem 'ohm-expire'
gem 'rack-throttle', '~> 0.3.0'
gem 'rest-client', '~> 1.6.7'
gem 'ohm', '~> 1.3.2'
gem 'ohm-expire', '~> 0.1.3'
gem 'ffi'
gem 'ffi', '~> 1.9.3'
gem 'attr_encrypted', '1.2.1'
gem 'attr_encrypted', '~> 1.3.2'
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
# AngularJS related stuff
@ -79,15 +77,13 @@ gem 'soundmanager-rails'
gem 'time_diff'
group :assets do
gem 'sass-rails', '~> 3.2.5'
gem 'coffee-rails', '~> 3.2.2'
gem 'compass-rails', '~> 1.0.3'
gem 'uglifier', '~> 1.2.4'
gem 'sass-rails', '~> 4.0.1'
gem 'coffee-rails', '~> 4.0.1'
gem 'compass-rails', '~> 1.1.6'
gem 'uglifier', '~> 2.4'
gem 'therubyracer', '~> 0.12.1', platforms: [:mri, :rbx]
gem 'therubyrhino', '~> 1.73.1', platforms: :jruby
gem 'turbo-sprockets-rails3'
end
group :production do
gem "airbrake", '~> 3.1.2'
@ -116,11 +112,16 @@ group :development do
#gem 'ruby-dbus' if RUBY_PLATFORM =~ /linux/i # Error at deploy
end
group :test do
gem 'rspec-rails', '~> 2.11.0', group: 'development'
gem 'factory_girl_rails', '~> 4.0.0'
gem 'rr', '~> 1.0.4'
gem 'shoulda'
gem 'mock_redis', '0.6.2'
gem 'rake'
group :development, :test do
gem 'rspec-rails', '~> 2.14.1'
end
group :test do
gem 'factory_girl_rails', '~> 4.4.1'
gem 'rr', '~> 1.1.2'
gem 'shoulda'
gem 'shoulda-matchers'
gem 'mock_redis', '~> 0.11'
gem 'rake'
gem 'test_after_commit'
end

View File

@ -8,6 +8,13 @@ GIT
resque (> 1.25)
resque-scheduler
GIT
remote: git://github.com/rosa-abf/cancan.git
revision: fe1089b70c08d3ed11bac4f8e69ecb3d1d9adc29
tag: 1.6.10-abf
specs:
cancan (1.6.10)
GIT
remote: git://github.com/rosa-abf/grack.git
revision: 020be3fef3fb308b9d214252522aa5945bf6584a
@ -23,74 +30,60 @@ GIT
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
GIT
remote: git://github.com/rosa-abf/redhillonrails_core.git
revision: c0945a4c6ad4bae4ca2750b105efcff162408b15
branch: rails31
specs:
redhillonrails_core (2.0.0.pre)
activerecord (>= 3.1.0.rc)
GEM
remote: https://rubygems.org/
specs:
RedCloth (4.2.9)
actionmailer (3.2.17)
actionpack (= 3.2.17)
actionmailer (4.0.4)
actionpack (= 4.0.4)
mail (~> 2.5.4)
actionpack (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
actionpack (4.0.4)
activesupport (= 4.0.4)
builder (~> 3.1.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
activerecord (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activerecord-postgres-hstore (0.7.7)
activerecord (>= 3.1)
pg-hstore (>= 1.1.5)
rake
activeresource (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
activesupport (3.2.17)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
airbrake (3.1.15)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
activemodel (4.0.4)
activesupport (= 4.0.4)
builder (~> 3.1.0)
activerecord (4.0.4)
activemodel (= 4.0.4)
activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.4)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
activesupport (4.0.4)
i18n (~> 0.6, >= 0.6.9)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
airbrake (3.1.16)
builder
multi_json
ancestry (1.3.0)
activerecord (>= 2.3.14)
ancestry (2.0.0)
activerecord (>= 3.0.0)
angular-i18n (0.1.2)
angularjs-rails (1.2.7)
arel (3.0.3)
attr_encrypted (1.2.1)
encryptor (>= 1.1.1)
bcrypt-ruby (3.1.2)
angularjs-rails (1.2.14)
arel (4.0.2)
atomic (1.1.16)
attr_encrypted (1.3.2)
encryptor (>= 1.3.0)
bcrypt (3.1.7)
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
better_errors (1.1.0)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
blankslate (3.1.2)
bluepill (0.0.66)
activesupport (>= 3.0.0, < 4.0.0)
bluepill (0.0.64)
activesupport (>= 3.0.0)
daemons (~> 1.1.4)
i18n (>= 0.5.0)
state_machine (~> 1.1)
builder (3.0.4)
builder (3.1.4)
callsite (0.0.11)
cancan (1.6.7)
cape (1.8.0)
capistrano (2.15.5)
highline
@ -101,99 +94,100 @@ GEM
capistrano_colors (0.5.5)
charlock_holmes (0.6.9.4)
chronic (0.10.2)
chunky_png (1.2.9)
chunky_png (1.3.0)
climate_control (0.0.3)
activesupport (>= 3.0)
cocaine (0.5.3)
climate_control (>= 0.0.3, < 1.0)
coderay (1.1.0)
coffee-rails (3.2.2)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.6.3)
compass (0.12.2)
coffee-script-source (1.7.0)
compass (0.12.3)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
compass-rails (1.0.3)
compass (>= 0.12.2, < 0.14)
sass (= 3.2.14)
compass-rails (1.1.6)
compass (>= 0.12.2)
creole (0.5.0)
daemons (1.1.9)
debug_inspector (0.0.2)
devise (2.2.8)
devise (3.2.3)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (~> 3.1)
warden (~> 1.2.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-display (0.0.1)
diff-lcs (1.1.3)
diff-lcs (1.2.5)
encryptor (1.3.0)
erubis (2.7.0)
escape_utils (0.2.4)
escape_utils (1.0.1)
eventmachine (1.0.3)
execjs (2.0.2)
expression_parser (0.9.0)
factory_girl (4.0.0)
factory_girl (4.4.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.0.0)
factory_girl (~> 4.0.0)
factory_girl_rails (4.4.1)
factory_girl (~> 4.4.0)
railties (>= 3.0.0)
faraday (0.8.9)
multipart-post (~> 1.2.0)
ffi (1.0.11)
friendly_id (4.0.10.1)
activerecord (>= 3.0, < 4.0)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
ffi (1.9.3)
friendly_id (5.0.3)
activerecord (>= 4.0.0)
fssm (0.2.10)
gemoji (1.2.1)
github-linguist (2.3.4)
github-linguist (2.10.9)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.3)
escape_utils (>= 0.3.1)
mime-types (~> 1.19)
pygments.rb (>= 0.2.13)
github-markdown (0.6.3)
pygments.rb (~> 0.5.4)
github-markup (0.7.5)
gli (2.8.1)
gollum (2.1.10)
github-markdown
github-markup (>= 0.7.0, < 1.0.0)
grit (~> 2.5.0)
mustache (>= 0.11.2, < 1.0.0)
nokogiri (~> 1.4)
posix-spawn (~> 0.3.0)
pygments.rb (~> 0.2.0)
sanitize (~> 2.0.0)
sinatra (~> 1.0)
stringex (~> 1.4.0)
useragent (~> 0.4.9)
haml (3.1.8)
haml-rails (0.3.5)
actionpack (>= 3.1, < 4.1)
activesupport (>= 3.1, < 4.1)
haml (~> 3.1)
railties (>= 3.1, < 4.1)
gitlab-grit (2.6.0)
charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
gli (2.9.0)
gollum-lib (2.0.0)
github-markup (>= 0.7.5, < 1.0.0)
gitlab-grit (= 2.6.0)
nokogiri (~> 1.6.0)
rouge (~> 1.3.1)
sanitize (~> 2.0.6)
stringex (~> 2.1.0)
haml (4.0.5)
tilt
haml-rails (0.5.3)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
haml (>= 3.1, < 5.0)
railties (>= 4.0.1)
hashie (2.0.5)
highline (1.6.20)
highline (1.6.21)
hike (1.2.3)
hirb (0.7.1)
httpauth (0.2.0)
i18n (0.6.9)
jbuilder (1.4.2)
jbuilder (2.0.4)
activesupport (>= 3.0.0)
multi_json (>= 1.2.0)
journey (1.0.4)
jquery-rails (2.0.3)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
js-routes (0.9.6)
rails (>= 3.2)
jquery-migrate-rails (1.2.1)
jquery-rails (2.3.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
js-routes (0.9.7)
railties (>= 3.2)
sprockets-rails
json (1.8.1)
jwt (0.1.10)
jwt (0.1.11)
multi_json (>= 1.5)
libv8 (3.16.14.3)
localeapp (0.6.14)
localeapp (0.7.1)
gli
i18n
json
@ -201,21 +195,20 @@ GEM
rest-client
ya2yaml
logglier (0.2.11)
macaddr (1.6.1)
systemu (~> 2.5.0)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mailcatcher (0.5.12)
activesupport (~> 3.0)
eventmachine (~> 1.0.0)
haml (>= 3.1, < 5)
mail (~> 2.3)
sinatra (~> 1.2)
skinny (~> 0.2.3)
sqlite3 (~> 1.3)
thin (~> 1.5.0)
meta-tags (1.2.6)
mailcatcher (0.2.4)
eventmachine
haml
i18n
json
mail
sinatra
skinny (>= 0.1.2)
sqlite3-ruby
thin
meta-tags (1.5.0)
actionpack
meta_request (0.2.8)
callsite
@ -223,31 +216,32 @@ GEM
railties
mime-types (1.25.1)
mini_portile (0.5.2)
mock_redis (0.6.2)
momentjs-rails (2.5.0)
minitest (4.7.5)
mock_redis (0.11.0)
momentjs-rails (2.5.1)
railties (>= 3.1)
mono_logger (1.1.0)
multi_json (1.8.4)
multipart-post (1.2.0)
mustache (0.99.5)
multi_json (1.9.0)
multi_xml (0.5.5)
multipart-post (2.0.0)
nest (1.1.2)
redis
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.7.0)
net-ssh (2.8.0)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
newrelic_rpm (3.7.1.182)
newrelic_rpm (3.7.3.204)
ng-rails-csrf (0.1.0)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
oauth2 (0.8.1)
faraday (~> 0.8)
httpauth (~> 0.1)
jwt (~> 0.1.4)
multi_json (~> 1.0)
oauth2 (0.9.3)
faraday (>= 0.8, < 0.10)
jwt (~> 0.1.8)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
ohm (1.3.2)
nest (~> 1.0)
@ -255,9 +249,9 @@ GEM
scrivener (~> 0.0.3)
ohm-expire (0.1.3.2)
ohm (>= 0.1.5)
omniauth (1.1.4)
omniauth (1.2.1)
hashie (>= 1.2, < 3)
rack
rack (~> 1.0)
omniauth-facebook (1.6.0)
omniauth-oauth2 (~> 1.1)
omniauth-github (1.1.1)
@ -266,122 +260,111 @@ GEM
omniauth-google-oauth2 (0.2.2)
omniauth (~> 1.0)
omniauth-oauth2
omniauth-oauth2 (1.1.1)
oauth2 (~> 0.8.0)
omniauth (~> 1.0)
omniauth-oauth2 (1.1.2)
faraday (>= 0.8, < 0.10)
multi_json (~> 1.3)
oauth2 (~> 0.9.3)
omniauth (~> 1.2)
orm_adapter (0.5.0)
paperclip (4.1.0)
paperclip (4.1.1)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
cocaine (~> 0.5.3)
mime-types
pg (0.14.1)
pg-hstore (1.2.0)
pg (0.17.1)
polyglot (0.3.4)
posix-spawn (0.3.8)
puma (2.7.1)
protected_attributes (1.0.7)
activemodel (>= 4.0.1, < 5.0)
puma (2.8.1)
rack (>= 1.1, < 2.0)
pygments.rb (0.2.13)
rubypython (~> 0.5.3)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
pygments.rb (0.5.4)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
rack (1.5.2)
rack-contrib (1.1.0)
rack (>= 0.9.1)
rack-protection (1.5.2)
rack
rack-ssl (1.3.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rack-throttle (0.3.0)
rack (>= 1.0.0)
rails (3.2.17)
actionmailer (= 3.2.17)
actionpack (= 3.2.17)
activerecord (= 3.2.17)
activeresource (= 3.2.17)
activesupport (= 3.2.17)
bundler (~> 1.0)
railties (= 3.2.17)
rails (4.0.4)
actionmailer (= 4.0.4)
actionpack (= 4.0.4)
activerecord (= 4.0.4)
activesupport (= 4.0.4)
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.4)
sprockets-rails (~> 2.0.0)
rails3-generators (1.0.0)
railties (>= 3.0.0)
rails3-jquery-autocomplete (1.0.12)
rails (>= 3.0)
railties (3.2.17)
actionpack (= 3.2.17)
activesupport (= 3.2.17)
rack-ssl (~> 1.3.2)
railties (4.0.4)
actionpack (= 4.0.4)
activesupport (= 4.0.4)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
thor (>= 0.18.1, < 2.0)
rake (10.1.1)
rdiscount (2.1.7)
rdoc (3.12.2)
json (~> 1.4)
redcarpet (2.2.2)
redcarpet (3.1.1)
redis (3.0.7)
redis-actionpack (3.2.4)
actionpack (~> 3.2.0)
redis-rack (~> 1.4.4)
redis-store (~> 1.1.4)
redis-activesupport (3.2.5)
activesupport (~> 3.2.0)
redis-actionpack (4.0.0)
actionpack (~> 4)
redis-rack (~> 1.5.0)
redis-store (~> 1.1.0)
redis-activesupport (4.0.0)
activesupport (~> 4)
redis-store (~> 1.1.0)
redis-namespace (1.4.1)
redis (~> 3.0.4)
redis-rack (1.4.4)
rack (~> 1.4.0)
redis-store (~> 1.1.4)
redis-rails (3.2.4)
redis-actionpack (~> 3.2.4)
redis-activesupport (~> 3.2.4)
redis-store (~> 1.1.4)
redis-rack (1.5.0)
rack (~> 1.5)
redis-store (~> 1.1.0)
redis-rails (4.0.0)
redis-actionpack (~> 4)
redis-activesupport (~> 4)
redis-store (~> 1.1.0)
redis-store (1.1.4)
redis (>= 2.2)
redisk (0.2.2)
redis (>= 0.1.1)
redis-namespace (>= 0.1.0)
ref (1.0.5)
resque (1.25.1)
resque (1.25.2)
mono_logger (~> 1.0)
multi_json (~> 1.0)
redis-namespace (~> 1.2)
redis-namespace (~> 1.3)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
resque-scheduler (2.5.4)
resque-scheduler (2.5.5)
mono_logger (~> 1.0)
redis (~> 3.0.4)
resque (~> 1.25.1)
rufus-scheduler (~> 2.0.24)
resque-status (0.3.3)
redisk (>= 0.2.1)
resque-status (0.4.2)
resque (~> 1.19)
uuid (~> 2.3)
resque_mailer (2.2.6)
actionmailer (>= 3.0)
rest-client (1.6.7)
mime-types (>= 1.16)
rinku (1.7.3)
rr (1.0.5)
rspec (2.11.0)
rspec-core (~> 2.11.0)
rspec-expectations (~> 2.11.0)
rspec-mocks (~> 2.11.0)
rspec-core (2.11.1)
rspec-expectations (2.11.3)
diff-lcs (~> 1.1.3)
rspec-mocks (2.11.3)
rspec-rails (2.11.4)
rouge (1.3.3)
rr (1.1.2)
rspec-core (2.14.8)
rspec-expectations (2.14.5)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.6)
rspec-rails (2.14.1)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec (~> 2.11.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
ruby-haml-js (0.0.5)
execjs
sprockets (>= 2.0.0)
rubypython (0.5.3)
blankslate (>= 2.1.2.3)
ffi (~> 1.0.7)
rufus-scheduler (2.0.24)
tzinfo (>= 0.3.22)
russian (0.6.0)
@ -390,11 +373,15 @@ GEM
capistrano (~> 2.15.4)
sanitize (2.0.6)
nokogiri (>= 1.4.4)
sass (3.2.13)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
sass (3.2.14)
sass-rails (4.0.2)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0.0)
schema_plus (1.4.1)
rails (>= 3.2)
valuable
scrivener (0.0.3)
shotgun (0.9)
rack (>= 1.0)
@ -414,15 +401,21 @@ GEM
skype (0.2.7)
tmp_cache
soundmanager-rails (1.0.0)
sprockets (2.2.2)
sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.8)
sprockets-rails (2.0.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.9)
sqlite3-ruby (1.3.3)
sqlite3 (>= 1.3.3)
state_machine (1.2.0)
stringex (1.4.0)
systemu (2.5.2)
stringex (2.1.2)
test_after_commit (0.2.3)
therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
@ -431,6 +424,8 @@ GEM
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.18.1)
thread_safe (0.2.0)
atomic (>= 1.1.7, < 2)
tilt (1.4.1)
time_diff (0.3.0)
activesupport
@ -439,22 +434,17 @@ GEM
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
turbo-sprockets-rails3 (0.3.11)
railties (> 3.2.8, < 4.0.0)
sprockets (>= 2.2.0)
tzinfo (0.3.38)
uglifier (1.2.7)
tzinfo (0.3.39)
uglifier (2.4.0)
execjs (>= 0.3.0)
multi_json (~> 1.3)
underscore-rails (1.5.2)
useragent (0.4.16)
uuid (2.3.7)
macaddr (~> 1.0)
json (>= 1.8.0)
underscore-rails (1.6.0)
valuable (0.9.8)
vegas (0.1.11)
rack (>= 1.0.0)
warden (1.2.3)
rack (>= 1.0)
whenever (0.9.0)
whenever (0.9.2)
activesupport (>= 2.3.4)
chronic (>= 0.6.3)
wikicloth (0.8.1)
@ -463,96 +453,98 @@ GEM
rinku
will_paginate (3.0.5)
ya2yaml (0.31)
yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
RedCloth
activerecord-postgres-hstore
airbrake (~> 3.1.2)
ancestry (~> 1.3.0)
ancestry (~> 2.0.0)
angular-i18n (= 0.1.2)
angularjs-rails
attr_encrypted (= 1.2.1)
attr_encrypted (~> 1.3.2)
better_errors
binding_of_caller
bluepill (~> 0.0.60)
cancan (= 1.6.7)
cancan!
cape
capistrano
capistrano_colors
charlock_holmes (~> 0.6.9)
coffee-rails (~> 3.2.2)
compass-rails (~> 1.0.3)
coffee-rails (~> 4.0.1)
compass-rails (~> 1.1.6)
creole
devise (~> 2.2.3)
devise (~> 3.2.3)
diff-display (~> 0.0.1)
factory_girl_rails (~> 4.0.0)
ffi
friendly_id
factory_girl_rails (~> 4.4.1)
ffi (~> 1.9.3)
friendly_id (~> 5.0.3)
gemoji (~> 1.2.1)
github-linguist (~> 2.3.4)
gollum (~> 2.1.3)
github-linguist (~> 2.10)
gollum-lib (~> 2.0)
grack!
grit!
haml-rails (~> 0.3.4)
highline (~> 1.6.11)
haml-rails (~> 0.5)
highline (~> 1.6.20)
hirb
jbuilder (~> 1.4.2)
jquery-rails (~> 2.0.2)
jbuilder (~> 2.0.3)
jquery-migrate-rails
jquery-rails (~> 2.3.0)
js-routes
localeapp
logglier
mailcatcher
meta-tags (~> 1.2.5)
meta-tags (~> 1.5)
meta_request
mock_redis (= 0.6.2)
mock_redis (~> 0.11)
momentjs-rails
newrelic_rpm
ng-rails-csrf
ohm
ohm-expire
ohm (~> 1.3.2)
ohm-expire (~> 0.1.3)
omniauth
omniauth-facebook
omniauth-github
omniauth-google-oauth2
paperclip (~> 4.1.0)
paperclip (~> 4.1.1)
perform_later!
pg (~> 0.14.0)
pg (~> 0.17.1)
protected_attributes
puma
rack-throttle
rails (= 3.2.17)
rack-throttle (~> 0.3.0)
rails (= 4.0.4)
rails3-generators
rails3-jquery-autocomplete (~> 1.0.7)
rails3-jquery-autocomplete (~> 1.0)
rake
rdiscount
redcarpet (~> 2.2.2)
redhillonrails_core!
redis-rails
resque (~> 1.24)
resque-scheduler
resque-status (~> 0.3.3)
redcarpet (~> 3.1.1)
redis-rails (~> 4.0)
resque (~> 1.25)
resque-scheduler (~> 2.5.4)
resque-status (~> 0.4.2)
resque_mailer (~> 2.2)
rest-client (~> 1.6.6)
rr (~> 1.0.4)
rspec-rails (~> 2.11.0)
ruby-haml-js (~> 0.0.3)
rest-client (~> 1.6.7)
rr (~> 1.1.2)
rspec-rails (~> 2.14.1)
ruby-haml-js (~> 0.0.5)
russian (~> 0.6.0)
rvm-capistrano
sass-rails (~> 3.2.5)
sass-rails (~> 4.0.1)
schema_plus (~> 1.4.0)
shotgun
shoulda
shoulda-matchers
skype
soundmanager-rails
state_machine
state_machine (~> 1.2)
test_after_commit
therubyracer (~> 0.12.1)
therubyrhino (~> 1.73.1)
time_diff
trinidad (~> 1.0.2)
turbo-sprockets-rails3
uglifier (~> 1.2.4)
uglifier (~> 2.4)
underscore-rails
whenever (~> 0.9.0)
wikicloth
will_paginate (~> 3.0.3)
will_paginate (~> 3.0.5)

View File

@ -1,34 +1,24 @@
RosaABF.controller('ProjectScheduleController', ['$scope', '$http', function($scope, $http) {
// See: Modules::Models::Autostart::AUTOSTART_STATUSES
// See: Autostart::AUTOSTART_STATUSES
$scope.statuses = {
'0': 'autostart_statuses.0',
'1': 'autostart_statuses.1',
'2': 'autostart_statuses.2'
};
$scope.project = null;
$scope.owner = null;
$scope.items = [];
$scope.init = function(name_with_owner) {
var arr = name_with_owner.split('/');
$scope.owner = arr[0];
$scope.project = arr[1];
}
$scope.updateStatus = function() {
$http.put(
Routes.project_path($scope.owner, $scope.project),
Routes.project_path($scope.name_with_owner),
{project: {autostart_status: $scope.autostart_status}, format: 'json'}
);
}
$scope.updateSchedule = function(obj) {
$http.put(
Routes.project_schedule_path($scope.owner, $scope.project),
Routes.project_schedule_path($scope.name_with_owner),
{enabled: obj.enabled, auto_publish: obj.auto_publish, repository_id: obj.repository_id, format: 'json'}
);
}
}]);

View File

@ -28,15 +28,15 @@ var BuildList = function(atts, dictionary) {
}
if (self.project) {
self.project.name_with_owner = self.project.owner + '/' + self.project.name;
if (self.last_published_commit_hash) {
self.version_link_text = self.last_published_commit_hash + '...' + self.commit_hash;
self.version_link_url = Routes.diff_path(self.project.owner, self.project.name, self.version_link_text);
self.version_link_url = Routes.diff_path(self.project.name_with_owner, self.version_link_text);
} else {
self.version_link_text = self.commit_hash || self.project_version;
self.version_link_url = Routes.commit_path(self.project.owner, self.project.name, self.version_link_text);
self.version_link_url = Routes.commit_path(self.project.name_with_owner, self.version_link_text);
}
self.project.url = Routes.project_path(self.project.owner, self.project.name);
self.project.name_with_owner = self.project.owner + '/' + self.project.name;
self.project.url = Routes.project_path(self.project.name_with_owner);
}
if (self.user)

View File

@ -14,15 +14,15 @@ var ProjectRef = function(atts) {
self.ui_container = false;
self.path = function(project) {
return Routes.tree_path(project.owner.uname, project.name, self.ref);
return Routes.tree_path(project.fullname, self.ref);
}
self.diff_path = function(project, current_ref) {
return Routes.diff_path(project.owner.uname, project.name, current_ref + '...' + self.ref);
return Routes.diff_path(project.fullname, current_ref + '...' + self.ref);
}
self.archive_path = function(project, type) {
return Routes.archive_path(project.owner.uname, project.name, project.name + '-' + self.ref, {format: type});
return Routes.archive_path(project.fullname, project.name + '-' + self.ref, {format: type});
}
//return the scope-safe instance

View File

@ -13,7 +13,8 @@ RosaABF.factory('ApiCollaborator', ['$resource', function($resource) {
isArray : false
},
find: {
url: '/:owner/:project/collaborators/find.json',
url: '/:owner/:project/collaborators/find',
format: 'json',
method: 'GET',
isArray : true
}

View File

@ -5,27 +5,32 @@ RosaABF.factory("ApiProject", ['$resource', function($resource) {
{owner: '@project.owner.uname', project: '@project.name'},
{
tags: {
url: '/:owner/:project/tags.json',
url: '/:owner/:project/tags',
format: 'json',
method: 'GET',
isArray : false
},
branches: {
url: '/:owner/:project/branches.json',
url: '/:owner/:project/branches',
format: 'json',
method: 'GET',
isArray : false
},
delete_branch: {
url: '/:owner/:project/branches/:ref.json',
url: '/:owner/:project/branches/:ref',
format: 'json',
method: 'DELETE',
isArray : false
},
restore_branch: {
url: '/:owner/:project/branches/:ref.json', // ?sha=<sha>
url: '/:owner/:project/branches/:ref', // ?sha=<sha>
format: 'json',
method: 'PUT',
isArray : false
},
create_branch: {
url: '/:owner/:project/branches.json', // ?new_ref=<new_ref>&from_ref=<from_ref>
url: '/:owner/:project/branches', // ?new_ref=<new_ref>&from_ref=<from_ref>
format: 'json',
method: 'POST',
isArray : false
}

View File

@ -1,7 +1,7 @@
RosaABF.factory("ApiPullRequest", ['$resource', function($resource) {
var PullRequestResource = $resource(
'/:owner/:project/pull_requests/:serial_id.json',
'/:owner/:project/pull_requests/:serial_id?format=json',
{
owner: '@pull_request.to_ref.project.owner_uname',
project: '@pull_request.to_ref.project.name',
@ -13,7 +13,8 @@ RosaABF.factory("ApiPullRequest", ['$resource', function($resource) {
isArray : false
},
merge: {
url: '/:owner/:project/pull_requests/:serial_id/merge.json',
url: '/:owner/:project/pull_requests/:serial_id/merge',
format: 'json',
method: 'PUT',
isArray: false
}

View File

@ -1,4 +1,5 @@
//= require jquery
//= require jquery-migrate-min
//= require jquery_ujs
//= require jquery-ui
//= require autocomplete-rails

View File

@ -1,6 +1,7 @@
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require jquery-migrate-min
//= require pirobox_extended_min
//= require ./design/all

View File

@ -87,6 +87,6 @@ class Admin::UsersController < Admin::BaseController
protected
def find_user
@user = User.find_by_uname!(params[:id]) if params[:id]
@user = User.find_by!(uname: params[:id]) if params[:id].present?
end
end

View File

@ -6,7 +6,7 @@ class Api::V1::AdvisoriesController < Api::V1::BaseController
authorize_resource :build_list, only: [:create, :update]
def index
@advisories = @advisories.scoped(include: [:platforms, :projects]).
@advisories = @advisories.includes(:platforms, :projects).
paginate(paginate_params)
end

View File

@ -13,6 +13,34 @@ class Api::V1::BaseController < ApplicationController
protected
# For this example, we are simply using token authentication
# via parameters. However, anyone could use Rails's token
# authentication features to get the token from a header.
def authenticate_user!
user_token = params[:authentication_token].presence
unless user_token
credentials = decode_credentials.select(&:present?)
user_token = credentials.first if credentials.size == 1
end
user = user_token && User.find_by_authentication_token(user_token.to_s)
if user
# Notice we are passing store false, so the user is not
# actually stored in the session and a token is needed
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in user, store: false
else
super
end
end
# Helper to decode credentials from HTTP.
def decode_credentials
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/m
Base64.decode64($1).split(/:/, 2)
end
def set_csv_file_headers(file_name)
headers['Content-Type'] = 'text/csv'
headers['Content-disposition'] = "attachment; filename=\"#{file_name}.csv\""

View File

@ -3,12 +3,13 @@ class Api::V1::BuildListsController < Api::V1::BaseController
before_filter :authenticate_user!
skip_before_filter :authenticate_user!, only: [:show, :index] if APP_CONFIG['anonymous_access']
load_and_authorize_resource :project, only: :index
load_resource :project, only: :index, parent: false
load_and_authorize_resource :build_list, only: [:show, :create, :cancel, :publish, :reject_publish, :create_container, :publish_into_testing]
def index
authorize!(:show, @project) if @project
filter = BuildList::Filter.new(@project, current_user, current_ability, params[:filter] || {})
@build_lists = filter.find.scoped(include: [:save_to_platform, :project, :user, :arch])
@build_lists = filter.find.includes(:save_to_platform, :project, :user, :arch)
@build_lists = @build_lists.recent.paginate(paginate_params)
end

View File

@ -6,6 +6,7 @@ class Api::V1::IssuesController < Api::V1::BaseController
load_and_authorize_resource :group, only: :group_index, find_by: :id, parent: false
load_and_authorize_resource :project
skip_load_and_authorize_resource :project, only: [:all_index, :user_index, :group_index]
load_and_authorize_resource :issue, through: :project, find_by: :serial_id, only: [:show, :update, :create, :index]
def index
@ -60,7 +61,7 @@ class Api::V1::IssuesController < Api::V1::BaseController
private
def render_issues_list
@issues = @issues.includes(:user, :assignee, :labels).without_pull_requests
@issues = @issues.preload(:user, :assignee, :labels, :project).without_pull_requests
if params[:status] == 'closed'
@issues = @issues.closed
else

View File

@ -58,7 +58,7 @@ class Api::V1::JobsController < Api::V1::BaseController
def status
if params[:key] =~ /\Aabfworker::(rpm|iso)-worker-[\d]+::live-inspector\z/
status = Resque.redis.get(params[:key])
status = Redis.current.get(params[:key])
end
render json: { status: status }.to_json
end

View File

@ -7,12 +7,12 @@ class ApplicationController < ActionController::Base
layout :layout_by_resource
# Hack to prevent token auth on all pages except atom feed:
prepend_before_filter lambda { redirect_to(new_user_session_path) if params[:token] && params[:token].is_a?(String) && params[:format] != 'atom'}
prepend_before_filter -> { redirect_to(new_user_session_path) if params[:token] && params[:token].is_a?(String) && params[:format] != 'atom'}
before_filter :set_locale
before_filter lambda { EventLog.current_controller = self },
before_filter -> { EventLog.current_controller = self },
only: [:create, :destroy, :open_id, :cancel, :publish, :change_visibility] # :update
after_filter lambda { EventLog.current_controller = nil }
after_filter -> { EventLog.current_controller = nil }
helper_method :get_owner
@ -48,10 +48,15 @@ class ApplicationController < ActionController::Base
def render_error(status)
respond_to do |format|
format.json { render json: {status: status, message: t("flash.#{status}_message")}.to_json, status: status }
format.html { redirect_to "/#{status}.html", alert: t("flash.#{status}_message") }
format.all { redirect_to "/#{status}.html", alert: t("flash.#{status}_message") }
end
end
# Helper method for all controllers
def permit_params(param_name, *accessible)
(params[param_name] || ActionController::Parameters.new).permit(*accessible.flatten)
end
def set_locale
I18n.locale = check_locale( get_user_locale ||
(request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'][0,2].downcase : nil ))
@ -73,8 +78,8 @@ class ApplicationController < ActionController::Base
return current_user
end
else
params['user_id'] && User.find_by_id(params['user_id']) ||
params['group_id'] && Group.find_by_id(params['group_id']) || current_user
params['user_id'] && User.find(params['user_id']) ||
params['group_id'] && Group.find(params['group_id']) || current_user
end
end

View File

@ -1,13 +1,14 @@
class Groups::MembersController < Groups::BaseController
before_filter lambda { authorize! :manage_members, @group }
before_filter -> { authorize! :manage_members, @group }
def index
@members = @group.members.order(:uname) - [@group.owner]
end
def update
params['user'].keys.each do |user_id|
role = params['user'][user_id]
if relation = @group.actors.where(actor_id: user_id, actor_type: 'User') #find_by_actor_id_and_actor_type(user_id, 'User')
if relation = @group.actors.where(actor_id: user_id, actor_type: 'User')
relation.update_all(role: role) if @group.owner.id.to_s != user_id
else
relation = @group.actors.build(actor_id: user_id, actor_type: 'User', role: role)
@ -34,7 +35,7 @@ class Groups::MembersController < Groups::BaseController
end
def add
@user = User.find_by_uname(params[:user_uname])
@user = User.find_by uname: params[:user_uname]
if !@user
flash[:error] = t("flash.collaborators.wrong_user", uname: params[:user_uname])
elsif @group.add_member(@user, params[:role])

View File

@ -9,8 +9,8 @@ class Groups::ProfileController < Groups::BaseController
end
def show
@path, page = group_path, params[:page].to_i
@projects = @group.own_projects.opened.search(params[:search]).recent
@path, page = group_path(@group), params[:page].to_i
@projects = @group.own_projects.search(params[:search]).recent
if request.xhr?
if params[:visibility] != 'hidden'
@projects = @projects.opened
@ -20,6 +20,7 @@ class Groups::ProfileController < Groups::BaseController
end
render partial: 'shared/profile_projects', layout: nil, locals: {projects: paginate_projects(page)}
else
@projects = @projects.opened
@projects = paginate_projects(page)
end
end

View File

@ -112,7 +112,7 @@ class Platforms::PlatformsController < Platforms::BaseController
end
def members
@members = @platform.members.order('name')
@members = @platform.members.order(:uname)
end
def remove_members

View File

@ -67,8 +67,6 @@ class Platforms::ProductsController < Platforms::BaseController
protected
def set_project
args = params[:src_project].try(:split, '/') || []
@product.project = (args.length == 2) ?
Project.find_by_owner_and_name(*args) : nil
@product.project = Project.find_by_owner_and_name params[:src_project]
end
end

View File

@ -12,7 +12,7 @@ class Projects::BaseController < ApplicationController
end
def find_project
@project = Project.find_by_owner_and_name!(params[:owner_name], params[:project_name]) if params[:owner_name].present? && params[:project_name].present?
@project = Project.find_by_owner_and_name! params[:name_with_owner] if params[:name_with_owner].present?
end
def init_statistics

View File

@ -8,13 +8,15 @@ class Projects::BuildListsController < Projects::BaseController
before_filter :find_build_list, only: [:show, :publish, :cancel, :update, :log, :create_container]
load_and_authorize_resource :project, only: NESTED_ACTIONS
load_and_authorize_resource :project, only: [:new, :create]
load_resource :project, only: :index, parent: false
load_and_authorize_resource :build_list, through: :project, only: NESTED_ACTIONS, shallow: true
load_and_authorize_resource except: NESTED_ACTIONS
before_filter :create_from_build_list, only: :new
def index
authorize!(:show, @project) if @project
params[:filter].each{|k,v| params[:filter].delete(k) if v.blank? } if params[:filter]
respond_to do |format|

View File

@ -47,7 +47,7 @@ class Projects::CommentsController < Projects::BaseController
protected
def find_commentable
@commentable = params[:issue_id].present? && @project.issues.find_by_serial_id(params[:issue_id]) ||
@commentable = params[:issue_id].present? && @project.issues.find_by(serial_id: params[:issue_id]) ||
params[:commit_id].present? && @project.repo.commit(params[:commit_id])
end

View File

@ -1,6 +1,6 @@
class Projects::Git::BlobsController < Projects::Git::BaseController
before_filter :set_blob
before_filter lambda {authorize! :write, @project}, only: [:edit, :update]
before_filter -> {authorize! :write, @project}, only: [:edit, :update]
def show
end

View File

@ -1,10 +1,10 @@
class Projects::Git::TreesController < Projects::Git::BaseController
before_filter lambda{redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, only: :show
before_filter -> {redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, only: :show
skip_before_filter :set_branch_and_tree, :set_treeish_and_path, only: :archive
before_filter lambda { raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) }, only: [:branch, :destroy]
before_filter -> { raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) }, only: [:branch, :destroy]
skip_authorize_resource :project, only: [:destroy, :restore_branch, :create]
before_filter lambda { authorize!(:write, @project) }, only: [:destroy, :restore_branch, :create]
before_filter -> { authorize!(:write, @project) }, only: [:destroy, :restore_branch, :create]
def show
unless request.xhr?

View File

@ -24,7 +24,7 @@ class Projects::IssuesController < Projects::BaseController
@sort = params[:sort] == 'updated' ? :updated : :created
@direction = params[:direction] == 'asc' ? :asc : :desc
@issues = @issues.order("issues.#{@sort}_at #{@direction}")
@issues = @issues.includes(:assignee, :user, :pull_request).uniq
@issues = @issues.preload(:assignee, :user, :pull_request).uniq
.paginate per_page: 20, page: params[:page]
if status == 200
render 'index', layout: request.xhr? ? 'with_sidebar' : 'application'
@ -81,11 +81,11 @@ class Projects::IssuesController < Projects::BaseController
end
end
def destroy
@issue.destroy
flash[:notice] = t("flash.issue.destroyed")
redirect_to root_path
end
# def destroy
# @issue.destroy
# flash[:notice] = t("flash.issue.destroyed")
# redirect_to root_path
# end
def create_label
index(@project.labels.create!(name: params[:name], color: params[:color]) ? 200 : 500)

View File

@ -1,7 +1,7 @@
class Projects::ProjectsController < Projects::BaseController
include ProjectsHelper
before_filter :authenticate_user!
load_and_authorize_resource id_param: :project_name # to force member actions load
load_and_authorize_resource id_param: :name_with_owner # to force member actions load
before_filter :who_owns, only: [:new, :create, :mass_import, :run_mass_import]
def index

View File

@ -152,8 +152,7 @@ class Projects::PullRequestsController < Projects::BaseController
end
def find_destination_project bang=true
args = params[:to_project].try(:split, '/') || []
project = (args.length == 2) ? Project.find_by_owner_and_name(*args) : nil
project = Project.find_by_owner_and_name params[:to_project]
raise ActiveRecord::RecordNotFound if bang && !project
project || @project
end

View File

@ -45,7 +45,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
else
raise 'Provider #{provider} not handled'
end
user = User.find_or_initialize_by_email(auth['info']['email'])
user = User.find_or_initialize_by email: auth['info']['email']
if user.new_record?
user.name = name
user.uname = name.gsub(/\s/, '').underscore

View File

@ -13,6 +13,7 @@ class Users::ProfileController < Users::BaseController
end
render partial: 'shared/profile_projects', layout: nil, locals: {projects: paginate_projects(page)}
else
@projects = @projects.opened
@projects = paginate_projects(page)
end
end

View File

@ -3,7 +3,7 @@ class Users::SettingsController < Users::BaseController
before_filter :set_current_user
def profile
if request.put?
if request.patch?
send_confirmation = params[:user][:email] != @user.email
if @user.update_without_password(params[:user])
update_avatar(@user, params)
@ -27,7 +27,7 @@ class Users::SettingsController < Users::BaseController
end
def private
if request.put?
if request.patch?
if @user.update_with_password(params[:user])
flash[:notice] = t('flash.user.saved')
redirect_to private_settings_path
@ -40,7 +40,7 @@ class Users::SettingsController < Users::BaseController
end
def notifiers
if request.put?
if request.patch?
if @user.notifier.update_attributes(params[:settings_notifier])
flash[:notice] = I18n.t("flash.settings.saved")
redirect_to notifiers_settings_path
@ -49,4 +49,5 @@ class Users::SettingsController < Users::BaseController
end
end
end
end

View File

@ -3,8 +3,7 @@ class Users::UsersController < Users::BaseController
before_filter :find_user_by_key, only: [:allowed, :discover]
def allowed
owner_name, project_name = params[:project].split '/'
project = Project.find_by_owner_and_name!(owner_name, project_name ? project_name : '!')
project = Project.find_by_owner_and_name! params[:project]
action = case params[:action_type]
when 'git-upload-pack'
then :read

View File

@ -87,7 +87,7 @@ module BuildListsHelper
bl = item.build_list
{
text: str_version ? "#{shortest_hash_id item.version, hash_size}" : shortest_hash_id(item.version, hash_size),
href: commit_path(bl.project.owner, bl.project, item.version)
href: commit_path(bl.project, item.version)
}
else
{}
@ -99,10 +99,10 @@ module BuildListsHelper
if bl.commit_hash.present?
if bl.last_published_commit_hash.present? && bl.last_published_commit_hash != bl.commit_hash
link_to "#{shortest_hash_id bl.last_published_commit_hash, hash_size}...#{shortest_hash_id bl.commit_hash, hash_size}",
diff_path(bl.project.owner, bl.project, bl.last_published_commit_hash) + "...#{bl.commit_hash}"
diff_path(bl.project, bl.last_published_commit_hash) + "...#{bl.commit_hash}"
else
link_to str_version ? "#{shortest_hash_id bl.commit_hash, hash_size}" : shortest_hash_id(bl.commit_hash, hash_size),
commit_path(bl.project.owner, bl.project, bl.commit_hash)
commit_path(bl.project, bl.commit_hash)
end
else
bl.project_version
@ -112,7 +112,7 @@ module BuildListsHelper
def product_build_list_version_link(bl, str_version = false)
if bl.commit_hash.present?
link_to str_version ? "#{shortest_hash_id bl.commit_hash} ( #{bl.project_version} )" : shortest_hash_id(bl.commit_hash),
commit_path(bl.project.owner, bl.project, bl.commit_hash)
commit_path(bl.project, bl.commit_hash)
else
bl.project_version
end

View File

@ -1,7 +1,7 @@
# This module is based on
# https://github.com/gitlabhq/gitlabhq/blob/7665b1de7eed4addd7b94786c84e6674710e6377/app/helpers/gitlab_markdown_helper.rb
module GitlabMarkdownHelper
include Modules::Models::Markdown
include MarkdownHelper
# Use this in places where you would normally use link_to(gfm(...), ...).
#

View File

@ -0,0 +1,190 @@
# This module is based on
# https://github.com/gitlabhq/gitlabhq/blob/397c3da9758c03a215a308c011f94261d9c61cfa/lib/gitlab/markdown.rb
# Custom parser for GitLab-flavored Markdown
#
# It replaces references in the text with links to the appropriate items in
# GitLab.
#
# Supported reference formats are:
# * @foo for team members
# * for issues & pull requests:
# * #123
# * abf#123
# * abf/rosa-build#123
# * 123456 for commits
#
# It also parses Emoji codes to insert images. See
# http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
#
# Examples
#
# >> gfm("Hey @david, can you fix this?")
# => "Hey <a href="/users/david">@david</a>, can you fix this?"
#
# >> gfm("Commit 35d5f7c closes #1234")
# => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
#
# >> gfm(":trollface:")
# => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
module MarkdownHelper
include IssuesHelper
attr_reader :html_options
# Public: Parse the provided text with GitLab-Flavored Markdown
#
# text - the source text
# html_options - extra options for the reference links as given to link_to
#
# Note: reference links will only be generated if @project is set
def gfm(text, html_options = {})
return text if text.nil?
# Duplicate the string so we don't alter the original, then call to_str
# to cast it back to a String instead of a SafeBuffer. This is required
# for gsub calls to work as we need them to.
text = text.dup.to_str
@html_options = html_options
# Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| extract_piece(match) }
# Extract links with probably parsable hrefs
text.gsub!(%r{<a.*?>.*?</a>}m) { |match| extract_piece(match) }
# Extract images with probably parsable src
text.gsub!(%r{<img.*?>}m) { |match| extract_piece(match) }
# TODO: add popups with additional information
text = parse(text)
# Insert pre block extractions
text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
insert_piece($1)
end
sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
end
private
def extract_piece(text)
@extractions ||= {}
md5 = Digest::MD5.hexdigest(text)
@extractions[md5] = text
"{gfm-extraction-#{md5}}"
end
def insert_piece(id)
@extractions[id]
end
# Private: Parses text for references and emoji
#
# text - Text to parse
#
# Note: reference links will only be generated if @project is set
#
# Returns parsed text
def parse(text)
parse_references(text) if @project
parse_emoji(text)
text
end
REFERENCE_PATTERN = %r{
(?<prefix>[\W\/])? # Prefix
( # Reference
@(?<user>[a-zA-Z][a-zA-Z0-9_\-\.]*) # User/Group uname
|(?<issue>(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?\#[0-9]+) # Issue ID
|(?<commit>[\h]{6,40}) # Commit ID
)
(?<suffix>\W)? # Suffix
}x.freeze
TYPES = [:user, :issue, :commit].freeze
def parse_references(text)
# parse reference links
text.gsub!(REFERENCE_PATTERN) do |match|
prefix = $~[:prefix]
suffix = $~[:suffix]
type = TYPES.select{|t| !$~[t].nil?}.first
identifier = $~[type]
# Avoid HTML entities
if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
match
elsif ref_link = reference_link(type, identifier)
"#{prefix}#{ref_link}#{suffix}"
else
match
end
end
end
EMOJI_PATTERN = %r{(:(\S+):)}.freeze
def parse_emoji(text)
# parse emoji
text.gsub!(EMOJI_PATTERN) do |match|
if valid_emoji?($2)
image_tag(image_path("emoji/#{$2}.png"), class: 'emoji', title: $1, alt: $1, size: "20x20")
else
match
end
end
end
# Private: Checks if an emoji icon exists in the image asset directory
#
# emoji - Identifier of the emoji as a string (e.g., "+1", "heart")
#
# Returns boolean
def valid_emoji?(emoji)
Emoji.names.include? emoji
end
# Private: Dispatches to a dedicated processing method based on reference
#
# reference - Object reference ("@1234", "!567", etc.)
# identifier - Object identifier (Issue ID, SHA hash, etc.)
#
# Returns string rendered by the processing method
def reference_link(type, identifier)
send("reference_#{type}", identifier)
end
def reference_user(identifier)
member = User.where(uname: identifier).first || Group.where(uname: identifier).first
if member
link_to("@#{identifier}", "/#{identifier}", html_options.merge(title: member.fullname, class: "gfm gfm-member #{html_options[:class]}"))
end
end
def reference_issue(identifier)
if issue = Issue.find_by_hash_tag(identifier, current_ability, @project)
if issue.pull_request
title = "#{PullRequest.model_name.human}: #{issue.title}"
url = project_pull_request_path(issue.project, issue.pull_request)
else
title = "#{Issue.model_name.human}: #{issue.title}"
url = project_issue_path(issue.project, issue.serial_id)
end
link_to(identifier, url, html_options.merge(title: title, class: "gfm gfm-issue #{html_options[:class]}"))
end
end
def reference_commit(identifier)
if commit = @project.repo.commit(identifier)
link_to shortest_hash_id(commit.id), commit_path(@project, commit.id)
title = GitPresenters::CommitAsMessagePresenter.present(commit, project: @project) do |presenter|
link_to(identifier, commit_path(@project, commit), html_options.merge(title: presenter.caption, class: "gfm gfm-commit #{html_options[:class]}"))
end
end
end
end

View File

@ -2,13 +2,13 @@ class BuildListsQueuesMonitoringJob
@queue = :hook
def self.perform
redis.smembers('queues').each do |key|
Redis.current.smembers('resque:queues').each do |key|
next if key !~ /(user|mass)_build_/
queue = "queue:#{key}"
queue = "resque:queue:#{key}"
id = key.gsub(/[^\d]/, '')
if redis.llen(queue) == 0
if Redis.current.llen(queue) == 0
if key =~ /^user/
last_updated_at = BuildList.select(:updated_at).
where(user_id: id).order('updated_at DESC').first
@ -21,29 +21,25 @@ class BuildListsQueuesMonitoringJob
else
# ensures that user/mass-build in the set from which we select next jobs
set_key = key =~ /^user/ ? BuildList::USER_BUILDS_SET : BuildList::MASS_BUILDS_SET
redis.sadd set_key, id
Redis.current.sadd set_key, id
end
end
end
def self.clean(key)
queue = "queue:#{key}"
queue = "resque:queue:#{key}"
# See [#watch]: https://github.com/redis/redis-rb/blob/master/lib/redis.rb#L2012
redis.watch(queue) do
if redis.llen(queue) == 0
redis.multi do |multi|
Redis.current.watch(queue) do
if Redis.current.llen(queue) == 0
Redis.current.multi do |multi|
multi.del queue
multi.srem 'queues', key
multi.srem 'resque:queues', key
end
else
redis.unwatch
Redis.current.unwatch
end
end
end
def self.redis
@redis ||= Resque.redis
end
end

View File

@ -18,12 +18,12 @@ class UserMailer < ActionMailer::Base
end
end
def new_comment_notification(comment, user)
@user, @comment = user, comment
def new_comment_notification(comment, user_id)
@user, @comment = User.find(user_id), comment
subject = @comment.issue_comment? ? subject_for_issue(@comment.commentable) :
I18n.t('notifications.subjects.new_commit_comment_notification')
mail(
to: email_with_name(user, user.email),
to: email_with_name(@user, @user.email),
subject: subject,
from: email_with_name(comment.user)
) do |format|

View File

@ -1,20 +1,21 @@
class ActivityFeed < ActiveRecord::Base
CODE = ['git_delete_branch_notification', 'git_new_push_notification', 'new_comment_commit_notification']
TRACKER = ['issue_assign_notification', 'new_comment_notification', 'new_issue_notification']
BUILD = ['build_list_notification']
WIKI = ['wiki_new_commit_notification']
CODE = %w(git_delete_branch_notification git_new_push_notification new_comment_commit_notification)
TRACKER = %w(issue_assign_notification new_comment_notification new_issue_notification)
BUILD = %w(build_list_notification)
WIKI = %w(wiki_new_commit_notification)
belongs_to :user
serialize :data
default_scope order("#{table_name}.created_at DESC")
scope :outdated, offset(100)
attr_accessible :user, :kind, :data
default_scope { order created_at: :desc }
scope :outdated, -> { offset(100) }
self.per_page = 10
def partial
'home/partials/' + self.kind
end
end

View File

@ -1,4 +1,6 @@
class Advisory < ActiveRecord::Base
self.include_root_in_json = false
has_and_belongs_to_many :platforms
has_and_belongs_to_many :projects
has_many :build_lists
@ -9,18 +11,20 @@ class Advisory < ActiveRecord::Base
after_create :generate_advisory_id
before_save :normalize_references, if: :references_changed?
attr_accessible :description
ID_TEMPLATE = 'ROSA-%<type>s-%<year>d:%<id>04d'
ID_STRING_TEMPLATE = 'ROSA-%<type>s-%<year>04s:%<id>04s'
TYPES = {'security' => 'SA', 'bugfix' => 'A'}
scope :search, lambda { |q|
scope :search, ->(q) {
q = q.to_s.strip
where("#{table_name}.advisory_id ILIKE :q OR #{table_name}.description ILIKE :q OR build_list_packages.fullname ILIKE :q", q: "%#{q}%").
joins(build_lists: :packages) if q.present?
}
scope :search_by_id, lambda { |aid| where("#{table_name}.advisory_id ILIKE ?", "%#{aid.to_s.strip}%") }
scope :by_update_type, lambda { |ut| where(update_type: ut) }
default_scope order("#{table_name}.created_at DESC")
scope :search_by_id, ->(aid) { where("#{table_name}.advisory_id ILIKE ?", "%#{aid.to_s.strip}%") }
scope :by_update_type, ->(ut) { where(update_type: ut) }
default_scope { order(created_at: :desc) }
def to_param
advisory_id
@ -37,7 +41,7 @@ class Advisory < ActiveRecord::Base
# this method fetches and structurize packages attached to current advisory.
def fetch_packages_info
packages_info = Hash.new { |h, k| h[k] = {} } # maaagic, it's maaagic ;)
build_lists.find_in_batches(include: [:save_to_platform, :packages, :project]) do |batch|
build_lists.includes(:save_to_platform, :packages, :project).find_in_batches do |batch|
batch.each do |build_list|
tmp = build_list.packages.inject({srpm: nil, rpm: []}) do |h, p|
p.package_type == 'binary' ? h[:rpm] << p.fullname : h[:srpm] = p.fullname
@ -69,4 +73,3 @@ class Advisory < ActiveRecord::Base
end
end
Advisory.include_root_in_json = false

View File

@ -5,5 +5,5 @@ class Arch < ActiveRecord::Base
validates :name, presence: true, uniqueness: true
scope :recent, order("#{table_name}.name ASC")
scope :recent, -> { order(:name) }
end

View File

@ -6,14 +6,15 @@ class Avatar < ActiveRecord::Base
AVATAR_SIZES_HASH = {}.tap do |styles|
AVATAR_SIZES.each do |name, size|
styles[name] = { geometry: "#{size}x#{size}#", format: :jpg, convert_options: '-strip -background white -flatten -quality 70'}
styles[name] = { geometry: "#{size}x#{size}#", format: :jpg,
convert_options: '-strip -background white -flatten -quality 70' }
end
end
has_attached_file :avatar, styles: AVATAR_SIZES_HASH
validates_attachment_size :avatar, less_than_or_equal_to: MAX_AVATAR_SIZE
validates_attachment_content_type :avatar, content_type: /\Aimage/
validates_attachment_file_name :avatar, matches: [ /(png|jpe?g|gif|bmp|tif?f)\z/i ]
attr_accessible :avatar
end

View File

@ -1,8 +1,10 @@
class BuildList < ActiveRecord::Base
include Modules::Models::CommitAndVersion
include Modules::Models::FileStoreClean
include CommitAndVersion
include FileStoreClean
include AbfWorker::ModelHelper
include Modules::Observers::ActivityFeed::BuildList
include Feed::BuildList
include BuildListObserver
include EventLoggable
belongs_to :project
belongs_to :arch
@ -16,7 +18,7 @@ class BuildList < ActiveRecord::Base
belongs_to :mass_build, counter_cache: true, touch: true
has_many :items, class_name: '::BuildList::Item', dependent: :destroy
has_many :packages, class_name: '::BuildList::Package', dependent: :destroy
has_many :source_packages, class_name: '::BuildList::Package', conditions: {package_type: 'source'}
has_many :source_packages, -> { where(package_type: 'source') }, class_name: '::BuildList::Package'
UPDATE_TYPES = %w[bugfix security enhancement recommended newpackage]
RELEASE_UPDATE_TYPES = %w[bugfix security]
@ -37,22 +39,22 @@ class BuildList < ActiveRecord::Base
unless: Proc.new { |b| b.advisory.present? }
validates :update_type, inclusion: { in: RELEASE_UPDATE_TYPES, message: I18n.t('flash.build_list.frozen_platform') },
if: Proc.new { |b| b.advisory.present? }
validate lambda {
validate -> {
errors.add(:build_for_platform, I18n.t('flash.build_list.wrong_platform')) if save_to_platform.main? && save_to_platform_id != build_for_platform_id
}
validate lambda {
validate -> {
errors.add(:build_for_platform, I18n.t('flash.build_list.wrong_build_for_platform')) unless build_for_platform.main?
}
validate lambda {
validate -> {
errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_repository')) if save_to_repository.platform_id != save_to_platform.id
}
validate lambda {
validate -> {
errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_include_repos')) if build_for_platform.repositories.where(id: include_repos).count != include_repos.size
}
validate lambda {
validate -> {
errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_project')) unless save_to_repository.projects.exists?(project_id)
}
before_validation lambda { self.include_repos = include_repos.uniq if include_repos.present? }, on: :create
before_validation -> { self.include_repos = include_repos.uniq if include_repos.present? }, on: :create
before_validation :prepare_extra_repositories, on: :create
before_validation :prepare_extra_build_lists, on: :create
before_validation :prepare_extra_params, on: :create
@ -95,40 +97,45 @@ class BuildList < ActiveRecord::Base
STATUSES.freeze
HUMAN_STATUSES.freeze
scope :recent, order("#{table_name}.updated_at DESC")
scope :for_extra_build_lists, lambda {|ids, current_ability, save_to_platform|
s = scoped
scope :recent, -> { order(updated_at: :desc) }
scope :for_extra_build_lists, ->(ids, current_ability, save_to_platform) {
s = all
s = s.where(id: ids).published_container.accessible_by(current_ability, :read)
s = s.where(save_to_platform_id: save_to_platform.id) if save_to_platform && save_to_platform.main?
s
}
scope :for_status, lambda {|status| where(status: status) if status.present? }
scope :for_user, lambda { |user| where(user_id: user.id) }
scope :not_owned_external_nodes, where("#{table_name}.external_nodes is null OR #{table_name}.external_nodes != ?", :owned)
scope :external_nodes, lambda { |type| where("#{table_name}.external_nodes = ?", type) }
scope :oldest, lambda { where("#{table_name}.updated_at < ?", Time.zone.now - 15.seconds) }
scope :for_platform, lambda { |platform| where(build_for_platform_id: platform) }
scope :by_mass_build, lambda { |mass_build| where(mass_build_id: mass_build) }
scope :scoped_to_arch, lambda {|arch| where(arch_id: arch) if arch.present? }
scope :scoped_to_save_platform, lambda {|pl_id| where(save_to_platform_id: pl_id) if pl_id.present? }
scope :scoped_to_project_version, lambda {|project_version| where(project_version: project_version) if project_version.present? }
scope :scoped_to_is_circle, lambda {|is_circle| where(is_circle: is_circle) }
scope :for_creation_date_period, lambda{|start_date, end_date|
s = scoped
scope :for_status, ->(status) { where(status: status) if status.present? }
scope :for_user, ->(user) { where(user_id: user.id) }
scope :not_owned_external_nodes, -> { where("#{table_name}.external_nodes is null OR #{table_name}.external_nodes != ?", :owned) }
scope :external_nodes, ->(type) { where("#{table_name}.external_nodes = ?", type) }
scope :oldest, -> { where("#{table_name}.updated_at < ?", Time.zone.now - 15.seconds) }
scope :for_platform, ->(platform) { where(build_for_platform_id: platform) }
scope :by_mass_build, ->(mass_build) { where(mass_build_id: mass_build) }
scope :scoped_to_arch, ->(arch) { where(arch_id: arch) if arch.present? }
scope :scoped_to_save_platform, ->(pl_id) { where(save_to_platform_id: pl_id) if pl_id.present? }
scope :scoped_to_project_version, ->(pr_version) { where(project_version: pr_version) if pr_version.present? }
scope :scoped_to_is_circle, ->(is_circle) { where(is_circle: is_circle) }
scope :for_creation_date_period, ->(start_date, end_date) {
s = all
s = s.where(["#{table_name}.created_at >= ?", start_date]) if start_date
s = s.where(["#{table_name}.created_at <= ?", end_date]) if end_date
s
}
scope :for_notified_date_period, lambda{|start_date, end_date|
s = scoped
scope :for_notified_date_period, ->(start_date, end_date) {
s = all
s = s.where("#{table_name}.updated_at >= ?", start_date) if start_date.present?
s = s.where("#{table_name}.updated_at <= ?", end_date) if end_date.present?
s
}
scope :scoped_to_project_name, lambda {|project_name| joins(:project).where('projects.name LIKE ?', "%#{project_name}%") if project_name.present? }
scope :scoped_to_new_core, lambda {|new_core| where(new_core: new_core)}
scope :outdated, where("#{table_name}.created_at < ? AND #{table_name}.status NOT IN (?) OR #{table_name}.created_at < ?", Time.now - LIVE_TIME, [BUILD_PUBLISHED,BUILD_PUBLISHED_INTO_TESTING], Time.now - MAX_LIVE_TIME)
scope :published_container, where(container_status: BUILD_PUBLISHED)
scope :scoped_to_project_name, ->(project_name) {
joins(:project).where('projects.name LIKE ?', "%#{project_name}%") if project_name.present?
}
scope :scoped_to_new_core, ->(new_core) { where(new_core: new_core) }
scope :outdated, -> {
where("#{table_name}.created_at < ? AND #{table_name}.status NOT IN (?) OR #{table_name}.created_at < ?",
Time.now - LIVE_TIME, [BUILD_PUBLISHED,BUILD_PUBLISHED_INTO_TESTING], Time.now - MAX_LIVE_TIME)
}
scope :published_container, -> { where(container_status: BUILD_PUBLISHED) }
serialize :additional_repos
serialize :include_repos
@ -137,7 +144,7 @@ class BuildList < ActiveRecord::Base
serialize :extra_build_lists, Array
serialize :extra_params, Hash
after_commit :place_build, on: :create
after_create :place_build
after_destroy :remove_container
state_machine :status, initial: :waiting_for_response do
@ -157,7 +164,7 @@ class BuildList < ActiveRecord::Base
after_transition on: [:published, :fail_publish, :build_error, :tests_failed], do: :notify_users
after_transition on: :build_success, do: :notify_users,
unless: lambda { |build_list| build_list.auto_publish? || build_list.auto_publish_into_testing? }
unless: ->(build_list) { build_list.auto_publish? || build_list.auto_publish_into_testing? }
event :place_build do
transition waiting_for_response: :build_pending
@ -413,7 +420,7 @@ class BuildList < ActiveRecord::Base
end
def set_packages(pkg_hash, project_name)
prj = Project.joins(repositories: :platform).where('platforms.id = ?', save_to_platform.id).find_by_name!(project_name)
prj = Project.joins(repositories: :platform).where('platforms.id = ?', save_to_platform.id).find_by!(name: project_name)
build_package(pkg_hash['srpm'], 'source', prj) {|p| p.save!}
pkg_hash['rpm'].each do |rpm_hash|
build_package(rpm_hash, 'binary', prj) {|p| p.save!}
@ -425,7 +432,11 @@ class BuildList < ActiveRecord::Base
end
def current_duration
if started_at
(Time.now.utc - started_at.utc).to_i
else
0
end
end
def human_current_duration
@ -527,17 +538,16 @@ class BuildList < ActiveRecord::Base
end
def self.next_build
redis = Resque.redis
kind_id = redis.spop(USER_BUILDS_SET)
kind_id = Redis.current.spop(USER_BUILDS_SET)
key = "user_build_#{kind_id}_rpm_worker_default" if kind_id
task = Resque.pop(key) if key
redis.sadd(USER_BUILDS_SET, kind_id) if task
Redis.current.sadd(USER_BUILDS_SET, kind_id) if task
kind_id ||= redis.spop(MASS_BUILDS_SET)
kind_id ||= Redis.current.spop(MASS_BUILDS_SET)
key ||= "mass_build_#{kind_id}_rpm_worker" if kind_id
task ||= Resque.pop(key) if key
redis.sadd(MASS_BUILDS_SET, kind_id) if task && key =~ /^mass_build/
Redis.current.sadd(MASS_BUILDS_SET, kind_id) if task && key =~ /^mass_build/
if task
build_list = BuildList.where(id: task['args'][0]['id']).first
@ -582,7 +592,7 @@ class BuildList < ActiveRecord::Base
users = [user, publisher].compact.uniq.select{ |u| u.notifier.can_notify? && u.notifier.new_build? }
# find associated users
users |= project.all_members.select do |u|
users |= project.all_members(:notifier).select do |u|
u.notifier.can_notify? && u.notifier.new_associated_build?
end if project
users.each{ |u| UserMailer.build_list_notification(self, u).deliver }

View File

@ -9,7 +9,7 @@ class BuildList::Filter
end
def find
build_lists = @project ? @project.build_lists : BuildList.scoped
build_lists = @project ? @project.build_lists : BuildList.all
if @options[:id]
build_lists = build_lists.where(id: @options[:id])

View File

@ -17,14 +17,12 @@ class BuildList::Item < ActiveRecord::Base
BuildList::BUILD_CANCELED => :build_canceled
}
scope :recent, order("#{table_name}.level ASC, #{table_name}.name ASC")
scope :recent, -> { order("#{table_name}.level ASC, #{table_name}.name ASC") }
def self.group_by_level
items = scoped({}).recent
groups = []
current_level = -1
items.each do |item|
all.recent.find_each do |item|
groups << [] if current_level < item.level
groups.last << item
current_level = item.level

View File

@ -13,14 +13,14 @@ class BuildList::Package < ActiveRecord::Base
validates :package_type, inclusion: PACKAGE_TYPES
validates :sha1, presence: true, if: Proc.new { |p| p.build_list.new_core? }
default_scope order("lower(#{table_name}.name) ASC, length(#{table_name}.name) ASC")
default_scope { order("lower(#{table_name}.name) ASC, length(#{table_name}.name) ASC") }
# Fetches only actual (last publised) packages.
scope :actual, where(actual: true)
scope :by_platform, lambda {|platform| where(platform_id: platform) }
scope :by_name, lambda {|name| where(name: name) }
scope :by_package_type, lambda {|type| where(package_type: type) }
scope :like_name, lambda {|name| where("#{table_name}.name ILIKE ?", "%#{name}%") if name.present?}
scope :actual, -> { where(actual: true) }
scope :by_platform, ->(platform) { where(platform_id: platform) }
scope :by_name, ->(name) { where(name: name) }
scope :by_package_type, ->(type) { where(package_type: type) }
scope :like_name, ->(name) { where("#{table_name}.name ILIKE ?", "%#{name}%") if name.present? }
before_create :set_epoch

View File

@ -1,30 +0,0 @@
class BuildListObserver < ActiveRecord::Observer
observe :build_list
def before_update(record)
if record.status_changed?
record.started_at = Time.now if record.status == BuildList::BUILD_STARTED
if [BuildList::BUILD_ERROR,
BuildList::SUCCESS,
BuildList::BUILD_CANCELING,
BuildList::TESTS_FAILED,
BuildList::BUILD_CANCELED].include? record.status
# stores time interval beetwin build start and finish in seconds
record.duration = record.current_duration if record.started_at
if record.status == BuildList::SUCCESS
# Update project average build time
begin
statistic = record.project.project_statistics.find_or_create_by_arch_id(record.arch_id)
rescue ActiveRecord::RecordNotUnique
retry
end
build_count = statistic.build_count.to_i
new_av_time = ( statistic.average_build_time * build_count + record.duration.to_i ) / ( build_count + 1 )
statistic.update_attributes(average_build_time: new_av_time, build_count: build_count + 1)
end
end
end
end # before_update
end

View File

@ -1,5 +1,5 @@
class Comment < ActiveRecord::Base
include Modules::Observers::ActivityFeed::Comment
include Feed::Comment
# regexp take from http://code.google.com/p/concerto-platform/source/browse/v3/cms/lib/CodeMirror/mode/gfm/gfm.js?spec=svn861&r=861#71
# User/Project#Num
@ -7,17 +7,18 @@ class Comment < ActiveRecord::Base
# #Num
ISSUES_REGEX = /(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?#[0-9]+/
belongs_to :commentable, polymorphic: true, touch: true
belongs_to :commentable, polymorphic: true
belongs_to :user
belongs_to :project
serialize :data
validates :body, :user_id, :commentable_id, :commentable_type, :project_id, presence: true
scope :for_commit, lambda {|c| where(commentable_id: c.id.hex, commentable_type: c.class)}
default_scope order("#{table_name}.created_at")
scope :for_commit, ->(c) { where(commentable_id: c.id.hex, commentable_type: c.class) }
default_scope { order(:created_at) }
after_create :subscribe_on_reply, unless: lambda {|c| c.commit_comment?}
before_save :touch_commentable
after_create :subscribe_on_reply, unless: ->(c) { c.commit_comment? }
after_create :subscribe_users
attr_accessible :body, :data
@ -186,8 +187,12 @@ class Comment < ActiveRecord::Base
protected
def touch_commentable
commentable.touch unless commit_comment?
end
def subscribe_on_reply
commentable.subscribes.create(user_id: user_id) if !commentable.subscribes.exists?(user_id: user_id)
commentable.subscribes.where(user_id: user_id).first_or_create
end
def subscribe_users
@ -195,7 +200,7 @@ class Comment < ActiveRecord::Base
commentable.subscribes.create(user: user) if !commentable.subscribes.exists?(user_id: user.id)
elsif commit_comment?
recipients = project.admins
recipients << user << User.where(email: commentable.try(:committer).try(:email)).first # commentor and committer
recipients << user << User.find_by(email: commentable.try(:committer).try(:email)) # commentor and committer
recipients.compact.uniq.each do |user|
options = {project_id: project.id, subscribeable_id: commentable_id, subscribeable_type: commentable.class.name, user_id: user.id}
Subscribe.subscribe_to_commit(options) if Subscribe.subscribed_to_commit?(project, user, commentable)

View File

@ -0,0 +1,37 @@
module ActsLikeMember
extend ActiveSupport::Concern
included do
scope :not_member_of, ->(item) {
where("
#{table_name}.id NOT IN (
SELECT relations.actor_id
FROM relations
WHERE (
relations.actor_type = '#{self.to_s}'
AND relations.target_type = '#{item.class.to_s}'
AND relations.target_id = #{item.id}
)
)
")
}
scope :search_order, -> { order("CHAR_LENGTH(#{table_name}.uname) ASC") }
scope :without, ->(a) { where("#{table_name}.id NOT IN (?)", a) }
scope :by_uname, ->(n) { where("#{table_name}.uname ILIKE ?", n) }
scope :search, ->(q) { by_uname("%#{q.to_s.strip}%") }
end
def to_param
uname
end
module ClassMethods
def find_by_insensitive_uname(uname)
find_by(uname: uname) || by_uname(uname).first
end
def find_by_insensitive_uname!(uname)
find_by_insensitive_uname(uname) or raise ActiveRecord::RecordNotFound
end
end
end

View File

@ -0,0 +1,31 @@
module Autostart
extend ActiveSupport::Concern
ONCE_A_12_HOURS = 0
ONCE_A_DAY = 1
ONCE_A_WEEK = 2
AUTOSTART_STATUSES = [ONCE_A_12_HOURS, ONCE_A_DAY, ONCE_A_WEEK]
HUMAN_AUTOSTART_STATUSES = {
ONCE_A_12_HOURS => :once_a_12_hours,
ONCE_A_DAY => :once_a_day,
ONCE_A_WEEK => :once_a_week
}
included do
validates :autostart_status, numericality: true,
inclusion: {in: AUTOSTART_STATUSES}, allow_blank: true
attr_accessible :autostart_status
end
def human_autostart_status
self.class.human_autostart_status(autostart_status)
end
module ClassMethods
def human_autostart_status(autostart_status)
I18n.t("layout.products.autostart_statuses.#{HUMAN_AUTOSTART_STATUSES[autostart_status]}")
end
end
end

View File

@ -0,0 +1,35 @@
module BuildListObserver
extend ActiveSupport::Concern
included do
before_update :update_average_build_time
end
private
def update_average_build_time
if status_changed?
started_at = Time.now if status == self.class::BUILD_STARTED
if [self.class::BUILD_ERROR,
self.class::SUCCESS,
self.class::BUILD_CANCELING,
self.class::TESTS_FAILED,
self.class::BUILD_CANCELED].include? status
# stores time interval beetwin build start and finish in seconds
duration = current_duration if started_at
if status == self.class::SUCCESS
# Update project average build time
begin
statistic = project.project_statistics.where(arch_id: arch_id).first_or_create
rescue ActiveRecord::RecordNotUnique
retry
end
build_count = statistic.build_count.to_i
new_av_time = ( statistic.average_build_time * build_count + duration.to_i ) / ( build_count + 1 )
statistic.update_attributes({average_build_time: new_av_time, build_count: build_count + 1}, without_protection: true)
end
end
end
end
end

View File

@ -0,0 +1,33 @@
module CommitAndVersion
extend ActiveSupport::Concern
included do
validate -> {
if project && (commit_hash.blank? || project.repo.commit(commit_hash).blank?)
errors.add :commit_hash, I18n.t('flash.build_list.wrong_commit_hash', commit_hash: commit_hash)
end
}
before_validation :set_commit_and_version
before_create :set_last_published_commit
end
protected
def set_commit_and_version
if project && project_version.present? && commit_hash.blank?
self.commit_hash = project.repo.commits(project_version).try(:first).try(:id)
elsif project_version.blank? && commit_hash.present?
self.project_version = commit_hash
end
end
def set_last_published_commit
return unless self.respond_to? :last_published_commit_hash # product?
last_commit = self.last_published.first.try :commit_hash
if last_commit && self.project.repo.commit(last_commit).present? # commit(nil) is not nil!
self.last_published_commit_hash = last_commit
end
end
end

View File

@ -0,0 +1,32 @@
module EventLoggable
extend ActiveSupport::Concern
included do
after_create :log_creation_event
after_destroy :log_destroying_event
end
private
def log_creation_event
ActiveSupport::Notifications.instrument(self.class.name, eventable: self)
end
def log_before_update
case self.class.to_s
when 'BuildList'
if status_changed? and [BuildList::BUILD_CANCELED, BuildList::BUILD_PUBLISHED].include?(status)
ActiveSupport::Notifications.instrument("event_log.observer", eventable: self)
end
when 'Platform'
if self.visibility_changed?
ActiveSupport::Notifications.instrument "event_log.observer", eventable: self,
message: I18n.t("activeself.attributes.platform.visibility_types.#{visibility}")
end
end
end
def log_destroying_event
ActiveSupport::Notifications.instrument(self.class.name, eventable: self)
end
end

View File

@ -1,4 +1,4 @@
module Modules::Observers::ActivityFeed::BuildList
module Feed::BuildList
extend ActiveSupport::Concern
included do

View File

@ -0,0 +1,74 @@
module Feed::Comment
extend ActiveSupport::Concern
included do
after_commit :new_comment_notifications, on: :create
# dont remove outdated issues link
after_update -> { Comment.create_link_on_issues_from_item(self) }
end
private
def new_comment_notifications
return if automatic?
if issue_comment?
commentable.subscribes.each do |subscribe|
if user_id != subscribe.user_id && can_notify_on_new_comment?(subscribe)
UserMailer.new_comment_notification(self, subscribe.user_id).deliver
ActivityFeed.create(
{
user_id: subscribe.user_id,
kind: 'new_comment_notification',
data: {
user_name: user.name,
user_email: user.email,
user_id: user_id,
comment_body: body,
issue_title: commentable.title,
issue_serial_id: commentable.serial_id,
project_id: commentable.project.id,
comment_id: id,
project_name: project.name,
project_owner: project.owner.uname
}
}, without_protection: true
)
end
end
elsif commit_comment?
Subscribe.comment_subscribes(self).where(status: true).each do |subscribe|
next if !subscribe.user_id || own_comment?(subscribe.user)
if subscribe.user.notifier.can_notify &&
( (subscribe.project.owner?(subscribe.user) && subscribe.user.notifier.new_comment_commit_repo_owner) ||
(subscribe.user.commentor?(self.commentable) && subscribe.user.notifier.new_comment_commit_commentor) ||
(subscribe.user.committer?(self.commentable) && subscribe.user.notifier.new_comment_commit_owner) )
UserMailer.new_comment_notification(self, subscribe.user_id).deliver
end
ActivityFeed.create(
{
user_id: subscribe.user_id,
kind: 'new_comment_commit_notification',
data: {
user_name: user.name,
user_email: user.email,
user_id: user_id,
comment_body: body,
commit_message: commentable.message,
commit_id: commentable.id,
project_id: project.id,
comment_id: id,
project_name: project.name,
project_owner: project.owner.uname
}
}, without_protection: true
)
end
end
Comment.create_link_on_issues_from_item(self)
end
def can_notify_on_new_comment?(subscribe)
notifier = SettingsNotifier.find_by user_id: subscribe.user_id
notifier && notifier.new_comment && notifier.can_notify
end
end

View File

@ -1,4 +1,4 @@
module Modules::Observers::ActivityFeed::Git
module Feed::Git
def self.create_notifications(record)
@ -49,7 +49,7 @@ module Modules::Observers::ActivityFeed::Git
end
when 'Hash' # 'Gollum::Committer'
actor = User.find_by_uname! record[:actor_name]
actor = User.find_by! uname: record[:actor_name]
project = Project.find record[:project_id]
project.admins.each do |recipient|

View File

@ -1,14 +1,14 @@
module Modules::Observers::ActivityFeed::Issue
module Feed::Issue
extend ActiveSupport::Concern
included do
after_commit :new_issue_notifications, on: :create
after_commit :send_assign_notifications, on: :create, if: Proc.new { |i| i.assignee }
after_commit -> { send_assign_notifications(:update) }, on: :update
after_commit :send_assign_notifications, on: :create, if: ->(i) { i.assignee }
after_update -> { send_assign_notifications(:update) }
after_commit :send_hooks, on: :create
after_commit -> { send_hooks(:update) }, on: :update, if: Proc.new { |i| i.previous_changes['status'].present? }
after_update -> { send_hooks(:update) }, if: ->(i) { i.previous_changes['status'].present? }
end
private
@ -34,7 +34,7 @@ module Modules::Observers::ActivityFeed::Issue
}
)
end
Comment.create_link_on_issues_from_item(self)
::Comment.create_link_on_issues_from_item(self)
end
def send_assign_notifications(action = :create)
@ -57,7 +57,7 @@ module Modules::Observers::ActivityFeed::Issue
)
end
# dont remove outdated issues link
Comment.create_link_on_issues_from_item(self) if previous_changes['title'].present? || previous_changes['body'].present?
::Comment.create_link_on_issues_from_item(self) if previous_changes['title'].present? || previous_changes['body'].present?
end
def send_hooks(action = :create)

View File

@ -1,4 +1,4 @@
module Modules::Observers::ActivityFeed::User
module Feed::User
extend ActiveSupport::Concern
included do
@ -8,10 +8,9 @@ module Modules::Observers::ActivityFeed::User
private
def new_user_notification
ActivityFeed.create(
user: self,
activity_feeds.create(
kind: 'new_user_notification',
data: {user_name: self.user_appeal, user_email: self.email}
data: { user_name: user_appeal, user_email: email }
)
end

View File

@ -0,0 +1,49 @@
module FileStoreClean
extend ActiveSupport::Concern
included do
def destroy
destroy_files_from_file_store if Rails.env.production?
super
end
later :destroy, queue: :clone_build
def sha1_of_file_store_files
raise NotImplementedError, "You should implement this method"
end
def destroy_files_from_file_store(args = sha1_of_file_store_files)
files = *args
token = User.find_by(uname: 'file_store').authentication_token
uri = URI APP_CONFIG['file_store_url']
Net::HTTP.start(uri.host, uri.port) do |http|
files.each do |sha1|
begin
req = Net::HTTP::Delete.new("/api/v1/file_stores/#{sha1}.json")
req.basic_auth token, ''
http.request(req)
rescue # Dont care about it
end
end
end
end
def later_destroy_files_from_file_store(args)
destroy_files_from_file_store(args)
end
later :later_destroy_files_from_file_store, queue: :clone_build
end
def self.file_exist_on_file_store?(sha1)
begin
resp = JSON(RestClient.get "#{APP_CONFIG['file_store_url']}/api/v1/file_stores.json", params: {hash: sha1})
rescue # Dont care about it
resp = []
end
if resp[0].respond_to?('[]') && resp[0]['file_name'] && resp[0]['sha1_hash']
true
else
false
end
end
end

241
app/models/concerns/git.rb Normal file
View File

@ -0,0 +1,241 @@
require 'nokogiri'
require 'open-uri'
module Git
extend ActiveSupport::Concern
included do
has_attached_file :srpm
validates_attachment_size :srpm, less_than_or_equal_to: 500.megabytes
validates_attachment_content_type :srpm, content_type: ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], message: I18n.t('layout.invalid_content_type')
after_create :create_git_repo
after_commit(on: :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque
after_commit(on: :create) {|p| p.import_attached_srpm if p.srpm?} # later with resque # should be after create_git_repo
after_destroy :destroy_git_repo
# after_rollback -> { destroy_git_repo rescue true if new_record? }
later :import_attached_srpm, queue: :fork_import
later :fork_git_repo, queue: :fork_import
end
def repo
@repo ||= Grit::Repo.new(path) rescue Grit::Repo.new(GAP_REPO_PATH)
end
def path
build_path(name_with_owner)
end
def versions
repo.tags.map(&:name) + repo.branches.map(&:name)
end
def create_branch(new_ref, from_ref, user)
return false if new_ref.blank? || from_ref.blank? || !(from_commit = repo.commit(from_ref))
status, out, err = repo.git.native(:branch, {process_info: true}, new_ref, from_commit.id)
if status == 0
Resque.enqueue(GitHook, owner.uname, name, from_commit.id, GitHook::ZERO, "refs/heads/#{new_ref}", 'commit', "user-#{user.id}", nil)
return true
end
return false
end
def delete_branch(branch, user)
return false if default_branch == branch.name
message = repo.git.native(:branch, {}, '-D', branch.name)
if message.present?
Resque.enqueue(GitHook, owner.uname, name, GitHook::ZERO, branch.commit.id, "refs/heads/#{branch.name}", 'commit', "user-#{user.id}", message)
end
return message.present?
end
def update_file(path, data, options = {})
head = options[:head].to_s || default_branch
actor = get_actor(options[:actor])
filename = File.split(path).last
message = options[:message]
message = "Updated file #{filename}" if message.nil? or message.empty?
# can not write to unexisted branch
return false if repo.branches.select{|b| b.name == head}.size != 1
parent = repo.commits(head).first
index = repo.index
index.read_tree(parent.tree.id)
# can not create new file
return false if (index.current_tree / path).nil?
system "sudo chown -R rosa:rosa #{repo.path}" #FIXME Permission denied - /mnt/gitstore/git_projects/...
index.add(path, data)
if sha1 = index.commit(message, parents: [parent], actor: actor, last_tree: parent.tree.id, head: head)
Resque.enqueue(GitHook, owner.uname, name, sha1, sha1, "refs/heads/#{head}", 'commit', "user-#{options[:actor].id}", message)
end
sha1
end
def paginate_commits(treeish, options = {})
options[:page] = options[:page].try(:to_i) || 1
options[:per_page] = options[:per_page].try(:to_i) || 20
skip = options[:per_page] * (options[:page] - 1)
last_page = (skip + options[:per_page]) >= repo.commit_count(treeish)
[repo.commits(treeish, options[:per_page], skip), options[:page], last_page]
end
def tree_info(tree, treeish = nil, path = nil)
return [] unless tree
grouped = tree.contents.sort_by{|c| c.name.downcase}.group_by(&:class)
[
grouped[Grit::Tree],
grouped[Grit::Blob],
grouped[Grit::Submodule]
].compact.flatten.map do |node|
node_path = File.join([path.present? ? path : nil, node.name].compact)
[
node,
node_path,
repo.log(treeish, node_path, max_count: 1).first
]
end
end
def import_srpm(srpm_path = srpm.path, branch_name = 'import')
token = User.find_by(uname: 'rosa_system').authentication_token
opts = [srpm_path, path, branch_name, Rails.root.join('bin', 'file-store.rb'), token, APP_CONFIG['file_store_url']].join(' ')
system("#{Rails.root.join('bin', 'import_srpm.sh')} #{opts} >> /dev/null 2>&1")
end
def is_empty?
repo.branches.count == 0
end
def total_commits_count
return 0 if is_empty?
%x(cd #{path} && git rev-list --all | wc -l).to_i
end
protected
def build_path(dir)
File.join(APP_CONFIG['git_path'], 'git_projects', "#{dir}.git")
end
def import_attached_srpm
if srpm?
import_srpm # srpm.path
self.srpm = nil; save # clear srpm
end
end
def create_git_repo
if is_root?
Grit::Repo.init_bare(path)
write_hook
end
end
def fork_git_repo
dummy = Grit::Repo.new(path) rescue parent.repo.fork_bare(path, shared: false)
write_hook
end
def destroy_git_repo
FileUtils.rm_rf path
end
def write_hook
hook = "/home/#{APP_CONFIG['shell_user']}/gitlab-shell/hooks/post-receive"
hook_file = File.join(path, 'hooks', 'post-receive')
FileUtils.ln_sf hook, hook_file
end
def get_actor(actor = nil)
@last_actor = case actor.class.to_s
when 'Grit::Actor' then options[:actor]
when 'Hash' then Grit::Actor.new(actor[:name], actor[:email])
when 'String' then Grit::Actor.from_stirng(actor)
else begin
if actor.respond_to?(:name) and actor.respond_to?(:email)
Grit::Actor.new(actor.name, actor.email)
else
config = Grit::Config.new(repo)
Grit::Actor.new(config['user.name'], config['user.email'])
end
end
end
@last_actor
end
module ClassMethods
MAX_SRC_SIZE = 1024*1024*256
def process_hook(owner_uname, repo, newrev, oldrev, ref, newrev_type, user = nil, message = nil)
rec = GitHook.new(owner_uname, repo, newrev, oldrev, ref, newrev_type, user, message)
Modules::Observers::ActivityFeed::Git.create_notifications rec
end
def run_mass_import(url, srpms_list, visibility, owner, add_to_repository_id)
doc = Nokogiri::HTML(open(url))
links = doc.css("a[href$='.src.rpm']")
return if links.count == 0
filter = srpms_list.lines.map(&:chomp).map(&:strip).select(&:present?)
repository = Repository.find add_to_repository_id
platform = repository.platform
dir = Dir.mktmpdir 'mass-import-', APP_CONFIG['tmpfs_path']
links.each do |link|
begin
package = link.attributes['href'].value
package.chomp!; package.strip!
next if package.size == 0 || package !~ /^[\w\.\-]+$/
next if filter.present? && !filter.include?(package)
uri = URI "#{url}/#{package}"
srpm_file = "#{dir}/#{package}"
Net::HTTP.start(uri.host) do |http|
if http.request_head(uri.path)['content-length'].to_i < MAX_SRC_SIZE
f = open(srpm_file, 'wb')
http.request_get(uri.path) do |resp|
resp.read_body{ |segment| f.write(segment) }
end
f.close
end
end
if name = `rpm -q --qf '[%{Name}]' -p #{srpm_file}` and $?.success? and name.present?
next if owner.projects.exists?(name: name)
description = `rpm -q --qf '[%{Description}]' -p #{srpm_file}`.scrub('')
project = owner.projects.build(
name: name,
description: description,
visibility: visibility,
is_package: false # See: Hook for #attach_to_personal_repository
)
project.owner = owner
if project.save
repository.projects << project rescue nil
project.update_attributes(is_package: true)
project.import_srpm srpm_file, platform.name
end
end
rescue => e
f.close if defined?(f)
Airbrake.notify_or_ignore(e, link: link.to_s, url: url, owner: owner)
ensure
File.delete srpm_file if srpm_file
end
end
rescue => e
Airbrake.notify_or_ignore(e, url: url, owner: owner)
ensure
FileUtils.remove_entry_secure dir if dir
end
end
end

View File

@ -0,0 +1,10 @@
module Owner
extend ActiveSupport::Concern
included do
validates :owner, presence: true
after_create do
relations.create(actor: owner, role: 'admin')
end
end
end

View File

@ -0,0 +1,37 @@
module PersonalRepository
extend ActiveSupport::Concern
included do
after_create :create_personal_repository, unless: :system?
end
def create_personal_repository
begin
pl = own_platforms.build
pl.owner = self
pl.name = "#{self.uname}_personal"
pl.description = "#{self.uname}_personal"
pl.platform_type = 'personal'
pl.distrib_type = APP_CONFIG['distr_types'].first
pl.visibility = 'open'
pl.save!
rep = pl.repositories.build
rep.name = 'main'
rep.description = 'main'
rep.save!
rescue Exception => e
pl.now_destroy rescue false
raise e
end
return true
end
def personal_platform
own_platforms.personal.first
end
def personal_repository
personal_platform.repositories.first
end
end

View File

@ -0,0 +1,44 @@
module RegenerationStatus
extend ActiveSupport::Concern
READY = 0
WAITING_FOR_REGENERATION = 100
REGENERATING = 200
HUMAN_STATUSES = {
READY => :ready,
WAITING_FOR_REGENERATION => :waiting_for_regeneration,
REGENERATING => :regenerating
}
HUMAN_REGENERATION_STATUSES = {
AbfWorker::BaseObserver::COMPLETED => :completed,
AbfWorker::BaseObserver::FAILED => :failed,
AbfWorker::BaseObserver::CANCELED => :canceled
}.freeze
included do
after_update :cleanup_file_store
def sha1_of_file_store_files
files = []
files << last_regenerated_log_sha1 if last_regenerated_log_sha1.present?
files
end
def human_regeneration_status
self.class::HUMAN_REGENERATION_STATUSES[last_regenerated_status] || :no_data
end
def human_status
self.class::HUMAN_STATUSES[status] || :no_data
end
def cleanup_file_store
old_log_sha1 = last_regenerated_log_sha1_was
if old_log_sha1.present? && old_log_sha1 != last_regenerated_log_sha1
later_destroy_files_from_file_store([old_log_sha1])
end
end
end
end

View File

@ -0,0 +1,29 @@
module TimeLiving
extend ActiveSupport::Concern
included do
validates :time_living, numericality: { only_integer: true }, presence: true
validate -> {
# MIN_TIME_LIVING <= time_living <= MAX_TIME_LIVING or
# 2 min <= time_living <= 12 hours
# time_living in seconds
min = self.class.const_defined?(:MIN_TIME_LIVING) ? self.class::MIN_TIME_LIVING : 120
max = self.class.const_defined?(:MAX_TIME_LIVING) ? self.class::MAX_TIME_LIVING : 43200
if min > time_living.to_i || time_living.to_i > max
errors.add :time_living,
I18n.t('flash.time_living.numericality_error', min: (min / 60), max: (max / 60))
end
}
before_validation :convert_time_living
attr_accessible :time_living
end
protected
def convert_time_living
self.time_living = time_living.to_i * 60 if time_living_was.to_i != time_living.to_i
end
end

View File

@ -0,0 +1,31 @@
module TokenAuthenticatable
extend ActiveSupport::Concern
module ClassMethods
def find_by_authentication_token(authentication_token = nil)
if authentication_token
where(authentication_token: authentication_token).first
end
end
end
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
def reset_authentication_token!
self.authentication_token = generate_authentication_token
save
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.where(authentication_token: token).first
end
end
end

View File

@ -1,4 +1,4 @@
module Modules::Models::UrlHelper
module UrlHelper
def default_url_options
host ||= EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
protocol ||= APP_CONFIG['mailer_https_url'] ? 'https' : 'http' rescue 'http'

View File

@ -1,4 +1,4 @@
module Modules::Models::WebHooks
module WebHooks
class << self
protected
@ -45,10 +45,11 @@ module Modules::Models::WebHooks
password :password
boolean :ssl, :message_without_join, :no_colors, :long_url, :notice
end
add_hook :jabber do
string :user
end
SCHEMA.freeze
NAMES.freeze
end

View File

@ -0,0 +1,31 @@
module Wiki
extend ActiveSupport::Concern
included do
after_save :create_wiki
after_destroy :destroy_wiki
end
def wiki_path
build_path(wiki_repo_name)
end
def wiki_repo_name
File.join owner.uname, "#{name}.wiki"
end
protected
def create_wiki
if has_wiki && !FileTest.exist?(wiki_path)
Grit::Repo.init_bare(wiki_path)
wiki = Gollum::Wiki.new(wiki_path, { base_path: Rails.application.routes.url_helpers.project_wiki_index_path(self) })
wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"),
{ name: owner.name, email: owner.email, message: 'Initial commit' })
end
end
def destroy_wiki
FileUtils.rm_rf wiki_path
end
end

View File

@ -4,14 +4,15 @@ class EventLog < ActiveRecord::Base
# self.per_page = 1
scope :eager_loading, preload(:user)
scope :default_order, order("#{table_name}.id DESC") # order('created_at DESC')
scope :eager_loading, -> { preload(:user) }
scope :default_order, -> { order(id: :desc) }
before_create do
self.user_name = user.try(:uname) || 'guest'
self.eventable_name ||= eventable.name if eventable.respond_to?(:name)
end
# after_create { self.class.current_controller = nil }
attr_accessible :kind, :message, :eventable, :eventable_name
class << self
def create_with_current_controller(attributes)

View File

@ -1,25 +0,0 @@
class EventLogObserver < ActiveRecord::Observer
observe :user, :platform, :repository, :project, :product, :build_list, :product_build_list
def after_create(record)
ActiveSupport::Notifications.instrument("event_log.observer", eventable: record)
end
def before_update(record)
case record.class.to_s
when 'BuildList'
if record.status_changed? and [BuildList::BUILD_CANCELED, BuildList::BUILD_PUBLISHED].include?(record.status)
ActiveSupport::Notifications.instrument("event_log.observer", eventable: record)
end
when 'Platform'
if record.visibility_changed?
ActiveSupport::Notifications.instrument "event_log.observer", eventable: record,
message: I18n.t("activerecord.attributes.platform.visibility_types.#{record.visibility}")
end
end
end
def after_destroy(record)
ActiveSupport::Notifications.instrument("event_log.observer", eventable: record)
end
end

View File

@ -8,6 +8,8 @@ class Feedback
include ActiveModel::MassAssignmentSecurity
extend ActiveModel::Naming
self.include_root_in_json = false
attr_accessor :name, :email, :subject, :message
attr_accessible :name, :email, :subject, :message
@ -99,6 +101,4 @@ class Feedback
perform_validation = options[:validate] != false
perform_validation ? valid?(options[:context]) : true
end
end
Feedback.include_root_in_json = false

View File

@ -8,7 +8,9 @@ class FlashNotify < ActiveRecord::Base
validates :status, inclusion: {in: STATUSES}
validates :body_ru, :body_en, :status, presence: true
scope :published, where(published: true)
scope :published, -> { where(published: true) }
attr_accessible :body_ru, :body_en, :status, :published
def hash_id
@digest ||= Digest::MD5.hexdigest("#{self.id}-#{self.updated_at}")

View File

@ -1,12 +1,13 @@
class GitHook
include Feed::Git
include Resque::Plugins::Status
ZERO = '0000000000000000000000000000000000000000'
@queue = :hook
attr_reader :repo, :newrev, :oldrev, :newrev_type, :oldrev_type, :refname,
:change_type, :rev, :rev_type, :refname_type, :owner, :project, :user, :message
include Resque::Plugins::Status
def self.perform(*options)
self.process(*options)
end
@ -64,19 +65,19 @@ class GitHook
end
def self.process(*args)
Modules::Observers::ActivityFeed::Git.create_notifications(args.size > 1 ? GitHook.new(*args) : args.first)
Feed::Git.create_notifications(args.size > 1 ? GitHook.new(*args) : args.first)
end
def find_user(user)
if user.blank?
# Local push
User.find_by_email(project.repo.commit(newrev).author.email) rescue nil
User.find_by(email: project.repo.commit(newrev).author.email) rescue nil
elsif user =~ /\Auser-\d+\Z/
# git push over http
User.find(user.gsub('user-', ''))
elsif user =~ /\Akey-\d+\Z/
# git push over ssh
SshKey.find_by_id(user.gsub('key-', '')).try(:user)
SshKey.find(user.gsub('key-', '')).try(:user)
end
end
end

View File

@ -1,4 +1,7 @@
class Group < Avatar
include ActsLikeMember
include PersonalRepository
belongs_to :owner, class_name: 'User'
has_many :relations, as: :actor, dependent: :destroy, dependent: :destroy
@ -15,10 +18,14 @@ class Group < Avatar
validates :uname, presence: true, uniqueness: {case_sensitive: false}, format: {with: /\A[a-z0-9_]+\z/}, reserved_name: true
validate { errors.add(:uname, :taken) if User.by_uname(uname).present? }
scope :opened, where('1=1')
scope :by_owner, lambda {|owner| where(owner_id: owner.id)}
scope :by_admin, lambda {|admin| joins(:actors).where(:'relations.role' => 'admin', :'relations.actor_id' => admin.id, :'relations.actor_type' => 'User')}
scope :by_admin_and_writer, lambda {|actor| joins(:actors).where(:'relations.role' => ['admin', 'writer'], :'relations.actor_id' => actor.id, :'relations.actor_type' => 'User')}
scope :opened, -> { all }
scope :by_owner, ->(owner) { where(owner_id: owner.id) }
scope :by_admin, ->(admin) {
joins(:actors).where('relations.role' => 'admin', 'relations.actor_id' => admin.id, 'relations.actor_type' => 'User')
}
scope :by_admin_and_writer, ->(actor) {
joins(:actors).where('relations.role' => ['admin', 'writer'], 'relations.actor_id' => actor.id, 'relations.actor_type' => 'User')
}
attr_accessible :uname, :description
attr_readonly :uname
@ -27,10 +34,6 @@ class Group < Avatar
after_create :add_owner_to_members
include Modules::Models::ActsLikeMember
include Modules::Models::PersonalRepository
# include Modules::Models::Owner
def self.can_own_project(user)
(by_owner(user) | by_admin_and_writer(user))
end

View File

@ -1,7 +1,8 @@
class Hook < ActiveRecord::Base
include Modules::Models::WebHooks
include Modules::Models::UrlHelper
include WebHooks
include UrlHelper
include Rails.application.routes.url_helpers
belongs_to :project
before_validation :cleanup_data
@ -12,7 +13,7 @@ class Hook < ActiveRecord::Base
serialize :data, Hash
scope :for_name, lambda {|name| where(name: name) if name.present? }
scope :for_name, ->(name) { where(name: name) if name.present? }
def receive_issues(issue, action)
pull = issue.pull_request

View File

@ -1,5 +1,5 @@
class Issue < ActiveRecord::Base
include Modules::Observers::ActivityFeed::Issue
include Feed::Issue
STATUSES = ['open', 'closed']
belongs_to :project
@ -10,8 +10,8 @@ class Issue < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
has_many :subscribes, as: :subscribeable, dependent: :destroy
has_many :labelings, dependent: :destroy
has_many :labels, through: :labelings, uniq: true
has_one :pull_request, dependent: :destroy
has_many :labels, -> { uniq }, through: :labelings
has_one :pull_request#, dependent: :destroy
validates :title, :body, :project_id, presence: true
@ -22,15 +22,17 @@ class Issue < ActiveRecord::Base
attr_accessible :labelings_attributes, :title, :body, :assignee_id
accepts_nested_attributes_for :labelings, allow_destroy: true
scope :opened, where(status: 'open')
scope :closed, where(status: 'closed')
scope :opened, -> { where(status: 'open') }
scope :closed, -> { where(status: 'closed') }
scope :needed_checking, where(issues: {status: ['open', 'blocked', 'ready', 'already']})
scope :not_closed_or_merged, needed_checking
scope :closed_or_merged, where(issues: {status: ['closed', 'merged']})
scope :needed_checking, -> { where(issues: {status: ['open', 'blocked', 'ready', 'already']}) }
scope :not_closed_or_merged, -> { needed_checking }
scope :closed_or_merged, -> { where(issues: {status: ['closed', 'merged']}) }
# Using mb_chars for correct transform to lowercase ('Русский Текст'.downcase => "Русский Текст")
scope :search, lambda {|q| where("#{table_name}.title ILIKE ?", "%#{q.mb_chars.downcase}%") if q.present?}
scope :without_pull_requests, where('NOT EXISTS (select null from pull_requests as pr where pr.issue_id = issues.id)')
scope :search, ->(q) { where("#{table_name}.title ILIKE ?", "%#{q.mb_chars.downcase}%") if q.present? }
scope :without_pull_requests, -> {
where('NOT EXISTS (select null from pull_requests as pr where pr.issue_id = issues.id)')
}
def assign_uname
assignee.uname if assignee

View File

@ -2,4 +2,5 @@ class Labeling < ActiveRecord::Base
belongs_to :issue
belongs_to :label
attr_accessible :label_id
end

View File

@ -1,5 +1,5 @@
class MassBuild < ActiveRecord::Base
belongs_to :build_for_platform, class_name: 'Platform', conditions: {platform_type: 'main'}
belongs_to :build_for_platform, -> { where(platform_type: 'main') }, class_name: 'Platform'
belongs_to :save_to_platform, class_name: 'Platform'
belongs_to :user
has_many :build_lists, dependent: :destroy
@ -7,9 +7,9 @@ class MassBuild < ActiveRecord::Base
serialize :extra_repositories, Array
serialize :extra_build_lists, Array
scope :recent, order("#{table_name}.created_at DESC")
scope :by_platform, lambda { |platform| where(save_to_platform_id: platform.id) }
scope :outdated, where("#{table_name}.created_at < ?", Time.now + 1.day - BuildList::MAX_LIVE_TIME)
scope :recent, -> { order(created_at: :desc) }
scope :by_platform, ->(platform) { where(save_to_platform_id: platform.id) }
scope :outdated, -> { where("#{table_name}.created_at < ?", Time.now + 1.day - BuildList::MAX_LIVE_TIME) }
attr_accessor :arches
attr_accessible :arches, :auto_publish, :projects_list, :build_for_platform_id,
@ -41,7 +41,7 @@ class MassBuild < ActiveRecord::Base
next if name.blank?
name.chomp!; name.strip!
if project = Project.joins(:repositories).where('repositories.id in (?)', save_to_platform.repository_ids).find_by_name(name)
if project = Project.joins(:repositories).where('repositories.id in (?)', save_to_platform.repository_ids).find_by(name: name)
begin
return if self.reload.stop_build
increase_rt = increase_release_tag?

View File

@ -1,9 +1,11 @@
class Platform < ActiveRecord::Base
extend FriendlyId
friendly_id :name
friendly_id :name, use: [:finders]
include Modules::Models::FileStoreClean
include Modules::Models::RegenerationStatus
include FileStoreClean
include RegenerationStatus
include Owner
include EventLoggable
AUTOMATIC_METADATA_REGENERATIONS = %w(day week)
VISIBILITIES = %w(open hidden)
@ -34,12 +36,12 @@ class Platform < ActiveRecord::Base
validates :automatic_metadata_regeneration, inclusion: { in: AUTOMATIC_METADATA_REGENERATIONS }, allow_blank: true
validates :name, uniqueness: {case_sensitive: false}, presence: true, format: { with: /\A#{NAME_PATTERN}\z/ }
validates :distrib_type, presence: true, inclusion: { in: APP_CONFIG['distr_types'] }
validate lambda {
validate -> {
if released_was && !released
errors.add(:released, I18n.t('flash.platform.released_status_can_not_be_changed'))
end
}
validate lambda {
validate -> {
if personal? && (owner_id_changed? || owner_type_changed?)
errors.add :owner, I18n.t('flash.platform.owner_can_not_be_changed')
end
@ -51,25 +53,23 @@ class Platform < ActiveRecord::Base
after_update :freeze_platform_and_update_repos
after_update :update_owner_relation
after_create lambda { symlink_directory unless hidden? }
after_destroy lambda { remove_symlink_directory unless hidden? }
after_create -> { symlink_directory unless hidden? }
after_destroy -> { remove_symlink_directory unless hidden? }
scope :search_order, order("CHAR_LENGTH(#{table_name}.name) ASC")
scope :search, lambda {|q| where("#{table_name}.name ILIKE ?", "%#{q.to_s.strip}%")}
scope :by_visibilities, lambda {|v| where(visibility: v)}
scope :opened, where(visibility: 'open')
scope :hidden, where(visibility: 'hidden')
scope :by_type, lambda {|type| where(platform_type: type) if type.present?}
scope :main, by_type('main')
scope :personal, by_type('personal')
scope :waiting_for_regeneration, where(status: WAITING_FOR_REGENERATION)
scope :search_order, -> { order(:name) }
scope :search, ->(q) { where("#{table_name}.name ILIKE ?", "%#{q.to_s.strip}%") }
scope :by_visibilities, ->(v) { where(visibility: v) }
scope :opened, -> { where(visibility: 'open') }
scope :hidden, -> { where(visibility: 'hidden') }
scope :by_type, ->(type) { where(platform_type: type) if type.present? }
scope :main, -> { by_type('main') }
scope :personal, -> { by_type('personal') }
scope :waiting_for_regeneration, -> { where(status: WAITING_FOR_REGENERATION) }
accepts_nested_attributes_for :platform_arch_settings, allow_destroy: true
attr_accessible :name, :distrib_type, :parent_platform_id, :platform_type, :owner, :visibility, :description, :released, :platform_arch_settings_attributes, :automatic_metadata_regeneration
attr_readonly :name, :distrib_type, :parent_platform_id, :platform_type
include Modules::Models::Owner
state_machine :status, initial: :ready do
after_transition on: :ready, do: :notify_users
@ -79,7 +79,7 @@ class Platform < ActiveRecord::Base
end
event :regenerate do
transition ready: :waiting_for_regeneration, if: lambda{ |p| p.main? }
transition ready: :waiting_for_regeneration, if: ->(p) { p.main? }
end
event :start_regeneration do
@ -223,13 +223,13 @@ class Platform < ActiveRecord::Base
end
Rails.cache.fetch([platform_name, token, :platform_allowed], expires_in: 2.minutes) do
platform = Platform.find_by_name platform_name
platform = Platform.find_by name: platform_name
next false unless platform
next true unless platform.hidden?
next false unless token
next true if platform.tokens.by_active.where(authentication_token: token).exists?
user = User.find_by_authentication_token token
user = User.find_by authentication_token: token
current_ability = Ability.new(user)
if user && current_ability.can?(:show, platform)
true

View File

@ -2,21 +2,19 @@ class PlatformArchSetting < ActiveRecord::Base
DEFAULT_TIME_LIVING = 43200 # seconds, 12 hours
MIN_TIME_LIVING = 600 # seconds, 10 minutes
MAX_TIME_LIVING = 360000 # seconds, 100 hours, 4 day and 4 hours
include Modules::Models::TimeLiving
include TimeLiving
belongs_to :arch
belongs_to :platform
validates :arch_id, :platform_id, presence: true
validates :platform_id, :uniqueness => {scope: :arch_id}
validates :platform_id, uniqueness: { scope: :arch_id }
validate lambda {
errors.add(:platform, I18n.t('flash.platform_arch_settings.wrong_platform')) unless platform.main?
}
scope :by_arch, lambda {|arch| where(arch_id: arch) if arch.present?}
scope :by_default, where(default: true)
scope :by_arch, ->(arch) { where(arch_id: arch) if arch.present? }
scope :by_default, -> { where(default: true) }
attr_accessible :arch_id, :platform_id, :default
end

View File

@ -1,15 +1,7 @@
class PlatformContent
# ------------------
# *** ATTRIBUTES ***
# ------------------
attr_reader :path
# ---------------
# *** METHODS ***
# ---------------
def initialize(platform, path)
@platform, @path = platform, path
end
@ -29,7 +21,7 @@ class PlatformContent
bfp_name = @path.match(/\/#{@platform.name}\/repository\/[\w]+\//)
return nil unless bfp_name
bfp_name = bfp_name[0].gsub(/\/#{@platform.name}\/repository\//, '').gsub('/', '')
build_for_platform = Platform.main.find_by_name bfp_name
build_for_platform = Platform.main.find_by name: bfp_name
return nil unless build_for_platform
end
@ -61,10 +53,6 @@ class PlatformContent
"#{APP_CONFIG['downloads_url']}/#{@platform.name}#{suffix}"
end
# ---------------------
# *** CLASS METHODS ***
# ---------------------
def self.find_by_platform(platform, path, term)
# Strip out the non-ascii character
term = (term || '').strip.gsub(/[\\\/]+/, '')

View File

@ -1,6 +1,7 @@
class Product < ActiveRecord::Base
include Modules::Models::TimeLiving
include Modules::Models::Autostart
include TimeLiving
include Autostart
include EventLoggable
belongs_to :platform
belongs_to :project
@ -10,7 +11,7 @@ class Product < ActiveRecord::Base
validates :project_id, presence: true
validates :main_script, :params, length: { maximum: 255 }
scope :recent, order("#{table_name}.name ASC")
scope :recent, -> { order(:name) }
attr_accessible :name,
:description,
@ -24,7 +25,7 @@ class Product < ActiveRecord::Base
def full_clone(attrs = {})
dup.tap do |c|
attrs.each {|k,v| c.send("#{k}=", v)}
c.time_living = c.time_living.to_i / 60 # see: Modules::Models::TimeLiving#convert_time_living
c.time_living = c.time_living.to_i / 60 # see: TimeLiving#convert_time_living
c.platform_id = nil
c.product_build_lists = []
c.updated_at = nil; c.created_at = nil
@ -32,7 +33,7 @@ class Product < ActiveRecord::Base
end
class << self
Modules::Models::Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
define_method "autostart_iso_builds_#{human_autostart_status}" do
autostart_iso_builds autostart_status
end

View File

@ -1,9 +1,11 @@
class ProductBuildList < ActiveRecord::Base
include Modules::Models::CommitAndVersion
include Modules::Models::TimeLiving
include Modules::Models::FileStoreClean
include Modules::Models::UrlHelper
include CommitAndVersion
include TimeLiving
include FileStoreClean
include UrlHelper
include AbfWorker::ModelHelper
include EventLoggable
delegate :url_helpers, to: 'Rails.application.routes'
LIVE_TIME = 2.week # for autostart
@ -38,9 +40,9 @@ class ProductBuildList < ActiveRecord::Base
belongs_to :user
# see: Issue #6
before_validation lambda { self.arch_id = Arch.find_by_name('x86_64').id }, on: :create
before_validation -> { self.arch_id = Arch.find_by(name: 'x86_64').id }, on: :create
# field "not_delete" can be changed only if build has been completed
before_validation lambda { self.not_delete = false unless build_completed?; true }
before_validation -> { self.not_delete = false unless build_completed?; true }
validates :product_id,
:status,
:project_id,
@ -64,13 +66,16 @@ class ProductBuildList < ActiveRecord::Base
serialize :results, Array
scope :default_order, order("#{table_name}.updated_at DESC")
scope :for_status, lambda {|status| where(status: status) }
scope :for_user, lambda { |user| where(user_id: user.id) }
scope :scoped_to_product_name, lambda {|product_name| joins(:product).where('products.name LIKE ?', "%#{product_name}%")}
scope :recent, order("#{table_name}.updated_at DESC")
scope :outdated, where(not_delete: false).
where("(#{table_name}.created_at < ? AND #{table_name}.autostarted is TRUE) OR #{table_name}.created_at < ?", Time.now - LIVE_TIME, Time.now - MAX_LIVE_TIME)
scope :default_order, -> { order(updated_at: :desc) }
scope :for_status, ->(status) { where(status: status) }
scope :for_user, ->(user) { where(user_id: user.id) }
scope :scoped_to_product_name, ->(product_name) { joins(:product).where('products.name LIKE ?', "%#{product_name}%") }
scope :recent, -> { order(updated_at: :desc) }
scope :outdated, -> {
where(not_delete: false).
where("(#{table_name}.created_at < ? AND #{table_name}.autostarted is TRUE) OR #{table_name}.created_at < ?",
Time.now - LIVE_TIME, Time.now - MAX_LIVE_TIME)
}
after_create :add_job_to_abf_worker_queue
before_destroy :can_destroy?
@ -154,8 +159,7 @@ class ProductBuildList < ActiveRecord::Base
opts = default_url_options
opts.merge!({user: user.authentication_token, password: ''}) if user.present?
srcpath = url_helpers.archive_url(
project.owner,
project.name,
project.name_with_owner,
file_name,
'tar.gz',
opts

View File

@ -1,12 +1,20 @@
class Project < ActiveRecord::Base
include Modules::Models::Autostart
has_ancestry orphan_strategy: :adopt # we replace a 'path' method in the Git module
include Autostart
include Owner
include Git
include Wiki
include UrlHelper
include EventLoggable
VISIBILITIES = ['open', 'hidden']
MAX_OWN_PROJECTS = 32000
NAME_REGEXP = /[\w\-\+\.]+/
OWNER_AND_NAME_REGEXP = /#{User::NAME_REGEXP.source}\/#{NAME_REGEXP.source}/
belongs_to :owner, polymorphic: true, counter_cache: :own_projects_count
belongs_to :maintainer, class_name: "User"
belongs_to :maintainer, class_name: 'User'
has_many :issues, dependent: :destroy
has_many :pull_requests, dependent: :destroy, foreign_key: 'to_project_id'
@ -25,12 +33,12 @@ class Project < ActiveRecord::Base
has_many :collaborators, through: :relations, source: :actor, source_type: 'User'
has_many :groups, through: :relations, source: :actor, source_type: 'Group'
has_many :packages, class_name: "BuildList::Package", dependent: :destroy
has_many :packages, class_name: 'BuildList::Package', dependent: :destroy
has_and_belongs_to_many :advisories # should be without dependent: :destroy
validates :name, uniqueness: { scope: [:owner_id, :owner_type], case_sensitive: false },
presence: true,
format: {with: /\A#{NAME_REGEXP}\z/,
format: { with: /\A#{NAME_REGEXP.source}\z/,
message: I18n.t("activerecord.errors.project.uname") }
validates :maintainer_id, presence: true, unless: :new_record?
validates :url, presence: true, format: { with: /\Ahttps?:\/\/[\S]+\z/ }, if: :mass_import
@ -53,57 +61,50 @@ class Project < ActiveRecord::Base
:autostart_status
attr_readonly :owner_id, :owner_type
scope :recent, order("lower(#{table_name}.name) ASC")
scope :search_order, order("CHAR_LENGTH(#{table_name}.name) ASC")
scope :search, lambda {|q|
scope :recent, -> { order(:name) }
scope :search_order, -> { order('CHAR_LENGTH(projects.name) ASC') }
scope :search, ->(q) {
q = q.to_s.strip
by_name("%#{q}%").search_order if q.present?
}
scope :by_name, lambda {|name| where("#{table_name}.name ILIKE ?", name) if name.present?}
scope :by_owner_and_name, lambda { |*params|
scope :by_name, ->(name) { where('projects.name ILIKE ?', name) if name.present? }
scope :by_owner_and_name, ->(*params) {
term = params.map(&:strip).join('/').downcase
where("lower(concat(owner_uname, '/', name)) ILIKE ?", "%#{term}%") if term.present?
}
scope :by_visibilities, lambda {|v| where(visibility: v)}
scope :opened, where(visibility: 'open')
scope :package, where(is_package: true)
scope :addable_to_repository, lambda { |repository_id| where %Q(
projects.id NOT IN (
SELECT
ptr.project_id
FROM
project_to_repositories AS ptr
WHERE (ptr.repository_id = #{ repository_id })
)
) }
scope :by_owners, lambda { |group_owner_ids, user_owner_ids|
where("(#{table_name}.owner_id in (?) AND #{table_name}.owner_type = 'Group') OR (#{table_name}.owner_id in (?) AND #{table_name}.owner_type = 'User')", group_owner_ids, user_owner_ids)
scope :by_visibilities, ->(v) { where(visibility: v) }
scope :opened, -> { where(visibility: 'open') }
scope :package, -> { where(is_package: true) }
scope :addable_to_repository, ->(repository_id) {
where('projects.id NOT IN (
SELECT ptr.project_id
FROM project_to_repositories AS ptr
WHERE ptr.repository_id = ?)', repository_id)
}
scope :by_owners, ->(group_owner_ids, user_owner_ids) {
where("(projects.owner_id in (?) AND projects.owner_type = 'Group') OR
(projects.owner_id in (?) AND projects.owner_type = 'User')", group_owner_ids, user_owner_ids)
}
before_validation :truncate_name, on: :create
before_save lambda { self.owner_uname = owner.uname if owner_uname.blank? || owner_id_changed? || owner_type_changed? }
before_save -> { self.owner_uname = owner.uname if owner_uname.blank? || owner_id_changed? || owner_type_changed? }
before_create :set_maintainer
after_save :attach_to_personal_repository
after_update :set_new_git_head
after_update lambda { update_path_to_project(name_was) }, if: :name_changed?
has_ancestry orphan_strategy: :rootify #:adopt not available yet
after_update -> { update_path_to_project(name_was) }, if: :name_changed?
attr_accessor :url, :srpms_list, :mass_import, :add_to_repository_id
include Modules::Models::Owner
include Modules::Models::Git
include Modules::Models::Wiki
include Modules::Models::UrlHelper
class << self
def find_by_owner_and_name(owner_name, project_name)
where(owner_uname: owner_name, name: project_name).first ||
by_owner_and_name(owner_name, project_name).first
def find_by_owner_and_name(first, last = nil)
arr = first.try(:split, '/') || []
arr = (arr << last).compact
return nil if arr.length != 2
where(owner_uname: arr.first, name: arr.last).first || by_owner_and_name(*arr).first
end
def find_by_owner_and_name!(owner_name, project_name)
find_by_owner_and_name(owner_name, project_name) or raise ActiveRecord::RecordNotFound
def find_by_owner_and_name!(first, last = nil)
find_by_owner_and_name(first, last) or raise ActiveRecord::RecordNotFound
end
end
@ -116,15 +117,15 @@ class Project < ActiveRecord::Base
end
def to_param
name
name_with_owner
end
def all_members
members | (owner_type == 'User' ? [owner] : owner.members)
def all_members(*includes)
members(includes) | (owner_type == 'User' ? [owner] : owner.members.includes(includes))
end
def members
collaborators | groups.map(&:members).flatten
def members(*includes)
collaborators.includes(includes) | groups.map{ |g| g.members.includes(includes) }.flatten
end
def add_member(member, role = 'admin')
@ -160,11 +161,11 @@ class Project < ActiveRecord::Base
def git_project_address auth_user
opts = default_url_options
opts.merge!({user: auth_user.authentication_token, password: ''}) unless self.public?
Rails.application.routes.url_helpers.project_url(self.owner.uname, self.name, opts) + '.git'
Rails.application.routes.url_helpers.project_url(self.name_with_owner, opts) + '.git'
#path #share by NFS
end
def build_for(mass_build, repository_id, arch = Arch.find_by_name('i586'), priority = 0, increase_rt = false)
def build_for(mass_build, repository_id, arch = Arch.find_by(name: 'i586'), priority = 0, increase_rt = false)
build_for_platform = mass_build.build_for_platform
save_to_platform = mass_build.save_to_platform
user = mass_build.user
@ -239,12 +240,12 @@ class Project < ActiveRecord::Base
format_id = ProjectTag::FORMATS["#{tag_file_format(format)}"]
project_tag = project_tags.where(tag_name: tag.name, format_id: format_id).first
return project_tag.sha1 if project_tag && project_tag.commit_id == tag.commit.id && Modules::Models::FileStoreClean.file_exist_on_file_store?(project_tag.sha1)
return project_tag.sha1 if project_tag && project_tag.commit_id == tag.commit.id && FileStoreClean.file_exist_on_file_store?(project_tag.sha1)
archive = archive_by_treeish_and_format tag.name, format
sha1 = Digest::SHA1.file(archive[:path]).hexdigest
unless Modules::Models::FileStoreClean.file_exist_on_file_store? sha1
token = User.find_by_uname('rosa_system').authentication_token
unless FileStoreClean.file_exist_on_file_store? sha1
token = User.find_by(uname: 'rosa_system').authentication_token
begin
resp = JSON `curl --user #{token}: -POST -F 'file_store[file]=@#{archive[:path]};filename=#{name}-#{tag.name}.#{tag_file_format(format)}' #{APP_CONFIG['file_store_url']}/api/v1/upload`
rescue # Dont care about it
@ -298,7 +299,7 @@ class Project < ActiveRecord::Base
end
class << self
Modules::Models::Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
define_method "autostart_build_lists_#{human_autostart_status}" do
autostart_build_lists autostart_status
end

View File

@ -5,7 +5,7 @@ class ProjectImport < ActiveRecord::Base
validates :name, uniqueness: { scope: :platform_id, case_sensitive: false }
validates :name, :platform_id, :version, presence: true
scope :by_name, lambda {|name| where("#{table_name}.name ILIKE ?", name)}
scope :by_name, ->(name) { where("#{table_name}.name ILIKE ?", name) }
after_initialize lambda {|r| r.file_mtime ||= Time.current - 10.years } # default
after_initialize ->(r) { r.file_mtime ||= Time.current - 10.years } # default
end

View File

@ -1,5 +1,5 @@
class ProjectTag < ActiveRecord::Base
include Modules::Models::FileStoreClean
include FileStoreClean
FORMATS = {
'zip' => 0,
@ -11,14 +11,9 @@ class ProjectTag < ActiveRecord::Base
validates :project_id, :commit_id, :sha1, :tag_name, :format_id, presence: true
validates :project_id, uniqueness: { scope: [:tag_name, :format_id] }
attr_accessible :project_id,
:commit_id,
:sha1,
:tag_name,
:format_id
attr_accessible :project_id, :commit_id, :sha1, :tag_name, :format_id
def sha1_of_file_store_files
[sha1]
end
end

View File

@ -6,13 +6,14 @@ class ProjectToRepository < ActiveRecord::Base
delegate :path, to: :project
scope :autostart_enabled, lambda { where("autostart_options -> 'enabled' = 'true'") }
scope :autostart_enabled, -> { where("autostart_options -> 'enabled' = 'true'") }
after_destroy lambda { project.destroy_project_from_repository(repository) }, unless: lambda {Thread.current[:skip]}
after_destroy -> { project.destroy_project_from_repository(repository) }, unless: -> { Thread.current[:skip] }
validate :one_project_in_platform_repositories, on: :create
serialize :autostart_options, ActiveRecord::Coders::Hstore
attr_accessible :project, :project_id
AUTOSTART_OPTIONS.each do |field|
store_accessor :autostart_options, field
end
@ -28,7 +29,8 @@ class ProjectToRepository < ActiveRecord::Base
protected
def one_project_in_platform_repositories
errors.add(:base, I18n.t('activerecord.errors.project_to_repository.project')) if Project.joins(repositories: :platform).
where('platforms.id = ?', repository.platform_id).by_name(project.name).exists?
if Project.joins(repositories: :platform).where('platforms.id = ?', repository.platform_id).by_name(project.name).exists?
errors.add(:base, I18n.t('activerecord.errors.project_to_repository.project'))
end
end
end

View File

@ -7,7 +7,7 @@ class PullRequest < ActiveRecord::Base
:created_at, :updated_at, :comments, :status=, to: :issue, allow_nil: true
validates :from_project, :to_project, presence: true
validate :uniq_merge, if: Proc.new { |pull| pull.to_project.present? }
validate :uniq_merge, if: ->(pull) { pull.to_project.present? }
validates_each :from_ref, :to_ref do |record, attr, value|
check_ref record, attr, value
end
@ -19,9 +19,9 @@ class PullRequest < ActiveRecord::Base
accepts_nested_attributes_for :issue
attr_accessible :issue_attributes, :to_ref, :from_ref
scope :needed_checking, includes(:issue).where(issues: {status: ['open', 'blocked', 'ready']})
scope :not_closed_or_merged, needed_checking
scope :closed_or_merged, where(issues: {status: ['closed', 'merged']})
scope :needed_checking, -> { includes(:issue).where(issues: {status: ['open', 'blocked', 'ready']}) }
scope :not_closed_or_merged, -> { needed_checking }
scope :closed_or_merged, -> { where(issues: {status: ['closed', 'merged']}) }
state_machine :status, initial: :open do
event :ready do

View File

@ -1,12 +1,13 @@
class RegisterRequest < ActiveRecord::Base
default_scope order('created_at ASC')
default_scope { order(:created_at) }
scope :rejected, where(rejected: true)
scope :approved, where(approved: true)
scope :unprocessed, where(approved: false, rejected: false)
scope :rejected, -> { where(rejected: true) }
scope :approved, -> { where(approved: true) }
scope :unprocessed, -> { where(approved: false, rejected: false) }
validates :email, presence: true, uniqueness: {case_sensitive: false}, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
validates :email, presence: true, uniqueness: {case_sensitive: false},
format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
# before_create :generate_token
before_update :invite_approve_notification

View File

@ -1,17 +1,22 @@
class Relation < ActiveRecord::Base
ROLES = %w[reader writer admin]
belongs_to :target, polymorphic: true
belongs_to :actor, polymorphic: true, touch: true
ROLES = %w[reader writer admin]
validates :role, inclusion: { in: ROLES }
# validate { errors.add(:actor, :taken) if Relation.where(actor_type: self.actor_type, actor_id: self.actor_id).present? }
before_validation :add_default_role
scope :by_user_through_groups, lambda {|u| where("actor_type = 'User' AND actor_id = ? OR actor_type = 'Group' AND actor_id IN (?)", u.id, u.group_ids)}
scope :by_actor, lambda {|obj| where(actor_id: obj.id, actor_type: obj.class.to_s)}
scope :by_target, lambda {|tar| where(target_id: tar.id, target_type: tar.class.to_s)}
scope :by_role, lambda {|role| where(role: role)}
attr_accessible :actor_id, :actor_type, :target_id, :target_type, :actor, :target, :role
scope :by_user_through_groups, ->(u) {
where("actor_type = 'User' AND actor_id = ? OR actor_type = 'Group' AND actor_id IN (?)", u.id, u.group_ids)
}
scope :by_actor, ->(obj) { where(actor_id: obj.id, actor_type: obj.class.to_s) }
scope :by_target, ->(tar) { where(target_id: tar.id, target_type: tar.class.to_s) }
scope :by_role, ->(role) { where(role: role) }
def self.create_with_role(actor, target, role)
r = self.new

View File

@ -1,6 +1,8 @@
class Repository < ActiveRecord::Base
extend FriendlyId
friendly_id :name
friendly_id :name, use: [:finders]
include EventLoggable
LOCK_FILE_NAMES = { sync: '.sync.lock', repo: '.repo.lock' }
SORT = { 'base' => 1, 'main' => 2, 'contrib' => 3, 'non-free' => 4, 'restricted' => 5 }
@ -19,10 +21,11 @@ class Repository < ActiveRecord::Base
has_many :build_lists, foreign_key: :save_to_repository_id, dependent: :destroy
validates :description, presence: true
validates :name, uniqueness: {scope: :platform_id, case_sensitive: false}, presence: true, format: {with: /\A[a-z0-9_\-]+\z/}
validates :name, uniqueness: { scope: :platform_id, case_sensitive: false }, presence: true,
format: { with: /\A[a-z0-9_\-]+\z/ }
scope :recent, order("#{table_name}.name ASC")
scope :main, lambda { where(name: %w(main base)) }
scope :recent, -> { order(:name) }
scope :main, -> { where(name: %w(main base)) }
before_destroy :detele_directory
@ -32,13 +35,13 @@ class Repository < ActiveRecord::Base
def regenerate(build_for_platform_id = nil)
build_for_platform = Platform.main.find build_for_platform_id if platform.personal?
status = repository_statuses.find_or_create_by_platform_id(build_for_platform.try(:id) || platform_id)
status = repository_statuses.find_or_create_by(platform_id: build_for_platform.try(:id) || platform_id)
status.regenerate
end
def resign
if platform.main?
status = repository_statuses.find_or_create_by_platform_id(platform_id)
status = repository_statuses.find_or_create_by(platform_id: platform_id)
status.resign
end
end
@ -79,7 +82,7 @@ class Repository < ActiveRecord::Base
begin
name.chomp!; name.strip!
next if name.blank?
project_to_repositories.where(projects: { name: name }).joins(:project).destroy_all
project_to_repositories.where(projects: { name: name }).joins(:project).readonly(false).destroy_all
rescue RuntimeError, Exception
end
end

View File

@ -1,6 +1,6 @@
class RepositoryStatus < ActiveRecord::Base
include Modules::Models::FileStoreClean
include Modules::Models::RegenerationStatus
include FileStoreClean
include RegenerationStatus
WAITING_FOR_RESIGN = 300
PUBLISH = 400
@ -33,10 +33,10 @@ class RepositoryStatus < ActiveRecord::Base
attr_accessible :platform_id, :repository_id
scope :platform_ready, where(platforms: {status: READY}).joins(:platform)
scope :for_regeneration, where(status: WAITING_FOR_REGENERATION)
scope :for_resign, where(status: [WAITING_FOR_RESIGN, WAITING_FOR_RESIGN_AND_REGENERATION])
scope :not_ready, where('repository_statuses.status != ?', READY)
scope :platform_ready, -> { where(platforms: {status: READY}).joins(:platform) }
scope :for_regeneration, -> { where(status: WAITING_FOR_REGENERATION) }
scope :for_resign, -> { where(status: [WAITING_FOR_RESIGN, WAITING_FOR_RESIGN_AND_REGENERATION]) }
scope :not_ready, -> { where('repository_statuses.status != ?', READY) }
state_machine :status, initial: :ready do
event :ready do
@ -80,5 +80,4 @@ class RepositoryStatus < ActiveRecord::Base
state name, value: code
end
end
end

View File

@ -29,5 +29,4 @@ class RpmBuildNode < Ohm::Model
end
{ systems: systems, others: others, busy: busy }
end
end

View File

@ -2,4 +2,17 @@ class SettingsNotifier < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
attr_accessible :can_notify,
:update_code,
:new_comment_commit_owner,
:new_comment_commit_repo_owner,
:new_comment_commit_commentor,
:new_comment,
:new_comment_reply,
:new_issue,
:issue_assign,
:new_build,
:new_associated_build
end

View File

@ -7,7 +7,7 @@ class SshKey < ActiveRecord::Base
belongs_to :user
attr_accessible :key, :name
before_validation lambda { self.key = key.strip if key.present? }
before_validation -> { self.key = key.strip if key.present? }
before_validation :set_fingerprint
validates :name, length: { maximum: 255 }

View File

@ -3,6 +3,8 @@ class Subscribe < ActiveRecord::Base
belongs_to :user
belongs_to :project
attr_accessible :status, :user_id
def commit_subscribe?
subscribeable_type == 'Grit::Commit'
end
@ -35,7 +37,7 @@ class Subscribe < ActiveRecord::Base
if subscribe = Subscribe.where(options).first
subscribe.update_attributes(status: status)
else
Subscribe.create(options.merge(status: status))
Subscribe.create(options.merge(status: status), without_protection: true)
end
end

View File

@ -6,8 +6,8 @@ class Token < ActiveRecord::Base
validates :creator_id, :subject_id, :subject_type, presence: true
validates :authentication_token, presence: true, uniqueness: { case_sensitive: true }
default_scope order("#{table_name}.created_at desc")
scope :by_active, where(status: 'active')
default_scope { order(created_at: :desc) }
scope :by_active, -> { where(status: 'active') }
before_validation :generate_token, on: :create

View File

@ -1,11 +1,18 @@
class User < Avatar
include PersonalRepository
include ActsLikeMember
include Feed::User
include EventLoggable
include TokenAuthenticatable
ROLES = ['', 'admin', 'banned', 'tester']
EXTENDED_ROLES = ROLES | ['system']
LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']]
LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last)
NAME_REGEXP = /[a-z0-9_]+/
devise :database_authenticatable, :registerable, :omniauthable, :token_authenticatable,# :encryptable, :timeoutable
:recoverable, :rememberable, :validatable, :lockable, :confirmable#, :reconfirmable, :trackable
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :validatable, :lockable, :confirmable
devise :omniauthable, omniauth_providers: [:facebook, :google_oauth2, :github]
has_one :notifier, class_name: 'SettingsNotifier', dependent: :destroy #:notifier
@ -34,7 +41,8 @@ class User < Avatar
has_many :key_pairs
has_many :ssh_keys, dependent: :destroy
validates :uname, presence: true, uniqueness: {case_sensitive: false}, format: {with: /\A[a-z0-9_]+\z/}, reserved_name: true
validates :uname, presence: true, uniqueness: { case_sensitive: false },
format: { with: /\A#{NAME_REGEXP.source}\z/ }, reserved_name: true
validate { errors.add(:uname, :taken) if Group.by_uname(uname).present? }
validates :role, inclusion: { in: EXTENDED_ROLES }, allow_blank: true
validates :language, inclusion: { in: LANGUAGES }, allow_blank: true
@ -44,23 +52,19 @@ class User < Avatar
attr_readonly :uname
attr_accessor :login
scope :opened, where('users.role != \'system\' OR users.role IS NULL')
scope :real, where(role: ['', nil])
scope :opened, -> { where('users.role != \'system\' OR users.role IS NULL') }
scope :real, -> { where(role: ['', nil]) }
EXTENDED_ROLES.select { |type| type.present?}.each do |type|
scope type.to_sym, where(role: type)
scope type.to_sym, -> { where(role: type) }
end
scope :member_of_project, lambda {|item|
where "#{table_name}.id IN (?)", item.members.map(&:id).uniq
scope :member_of_project, ->(item) {
where 'users.id IN (?)', item.members.map(&:id).uniq
}
after_create lambda { self.create_notifier unless self.system? }
after_create -> { self.create_notifier unless self.system? }
before_create :ensure_authentication_token
include Modules::Models::PersonalRepository
include Modules::Models::ActsLikeMember
include Modules::Observers::ActivityFeed::User
def admin?
role == 'admin'
end
@ -169,7 +173,7 @@ class User < Avatar
gr = gr.where('groups.id != ?', target.owner.id) # exclude target owner group from users group list
end
roles += rel.where(actor_id: self.id, actor_type: 'User') # user is member
roles += rel.where(actor_id: gr, actor_type: 'Group') # user group is member
roles += rel.where(actor_id: gr.pluck('DISTINCT groups.id'), actor_type: 'Group') # user group is member
roles.map(&:role).uniq
end

View File

@ -62,7 +62,7 @@ class CommentPresenter < ApplicationPresenter
end
if controller.can? :destroy, @comment
res << link_to(t('layout.delete'), path, method: "delete",
confirm: t('layout.comments.confirm_delete')).html_safe
data: { confirm: t('layout.comments.confirm_delete') }).html_safe
end
res
end

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